aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
commit0883ccd9eac3b974df00e6548ee319a7dd3646f4 (patch)
treed6a70c3518b8dea8be7062438d7e8676820ed17f
parent60bfabcd8ce617297c0d231f77d14ab507e98796 (diff)
downloadsrc-0883ccd9eac3b974df00e6548ee319a7dd3646f4.tar.gz
src-0883ccd9eac3b974df00e6548ee319a7dd3646f4.zip
Update clang to r103004.
Notes
Notes: svn path=/vendor/clang/dist/; revision=207619
-rw-r--r--CMakeLists.txt21
-rw-r--r--Makefile27
-rw-r--r--VER2
-rw-r--r--bindings/python/README.txt5
-rw-r--r--bindings/python/clang/cindex.py6
-rw-r--r--clang.xcodeproj/project.pbxproj343
-rw-r--r--docs/Block-ABI-Apple.txt11
-rw-r--r--docs/InternalsManual.html12
-rw-r--r--docs/LanguageExtensions.html43
-rw-r--r--docs/UsersManual.html6
-rw-r--r--examples/clang-interpreter/main.cpp8
-rw-r--r--include/Makefile2
-rw-r--r--include/clang-c/Index.h37
-rw-r--r--include/clang-c/Makefile31
-rw-r--r--include/clang/AST/APValue.h8
-rw-r--r--include/clang/AST/ASTContext.h48
-rw-r--r--include/clang/AST/ASTVector.h397
-rw-r--r--include/clang/AST/CanonicalType.h1
-rw-r--r--include/clang/AST/Decl.h96
-rw-r--r--include/clang/AST/DeclAccessPair.h72
-rw-r--r--include/clang/AST/DeclBase.h99
-rw-r--r--include/clang/AST/DeclCXX.h40
-rw-r--r--include/clang/AST/DeclContextInternals.h4
-rw-r--r--include/clang/AST/DeclFriend.h10
-rw-r--r--include/clang/AST/DeclNodes.def8
-rw-r--r--include/clang/AST/DeclObjC.h75
-rw-r--r--include/clang/AST/DeclTemplate.h109
-rw-r--r--include/clang/AST/DeclarationName.h11
-rw-r--r--include/clang/AST/DependentDiagnostic.h9
-rw-r--r--include/clang/AST/Expr.h331
-rw-r--r--include/clang/AST/ExprCXX.h104
-rw-r--r--include/clang/AST/ExprObjC.h485
-rw-r--r--include/clang/AST/ExternalASTSource.h7
-rw-r--r--include/clang/AST/Stmt.h8
-rw-r--r--include/clang/AST/StmtNodes.def3
-rw-r--r--include/clang/AST/StmtObjC.h137
-rw-r--r--include/clang/AST/TemplateName.h6
-rw-r--r--include/clang/AST/Type.h84
-rw-r--r--include/clang/AST/TypeNodes.def4
-rw-r--r--include/clang/AST/UnresolvedSet.h51
-rw-r--r--include/clang/AST/UsuallyTinyPtrVector.h105
-rw-r--r--include/clang/Analysis/Support/Optional.h66
-rw-r--r--include/clang/Basic/Builtins.def12
-rw-r--r--include/clang/Basic/BuiltinsPPC.def92
-rw-r--r--include/clang/Basic/BuiltinsX86.def2
-rw-r--r--include/clang/Basic/Diagnostic.h49
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td19
-rw-r--r--include/clang/Basic/DiagnosticGroups.td13
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td319
-rw-r--r--include/clang/Basic/LangOptions.h19
-rw-r--r--include/clang/Basic/SourceLocation.h11
-rw-r--r--include/clang/Basic/SourceManager.h19
-rw-r--r--include/clang/Basic/TargetInfo.h34
-rw-r--r--include/clang/Basic/Version.h4
-rw-r--r--include/clang/Checker/BugReporter/BugReporter.h1
-rw-r--r--include/clang/Checker/PathSensitive/AnalysisManager.h8
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h27
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h24
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h6
-rw-r--r--include/clang/Checker/PathSensitive/Store.h3
-rw-r--r--include/clang/Checker/PathSensitive/ValueManager.h6
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h19
-rw-r--r--include/clang/Driver/CC1Options.td40
-rw-r--r--include/clang/Driver/Options.td14
-rw-r--r--include/clang/Driver/Tool.h4
-rw-r--r--include/clang/Driver/ToolChain.h7
-rw-r--r--include/clang/Frontend/ASTConsumers.h4
-rw-r--r--include/clang/Frontend/Analyses.def25
-rw-r--r--include/clang/Frontend/AnalysisConsumer.h1
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h5
-rw-r--r--include/clang/Frontend/FixItRewriter.h59
-rw-r--r--include/clang/Frontend/FrontendActions.h8
-rw-r--r--include/clang/Frontend/FrontendOptions.h9
-rw-r--r--include/clang/Frontend/PCHBitCodes.h6
-rw-r--r--include/clang/Frontend/PCHReader.h5
-rw-r--r--include/clang/Frontend/StmtXML.def9
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h2
-rw-r--r--include/clang/Frontend/VerifyDiagnosticsClient.h19
-rw-r--r--include/clang/Lex/PPCallbacks.h15
-rw-r--r--include/clang/Lex/Preprocessor.h10
-rw-r--r--include/clang/Lex/TokenConcatenation.h4
-rw-r--r--include/clang/Makefile27
-rw-r--r--include/clang/Parse/Action.h284
-rw-r--r--include/clang/Parse/AttributeList.h4
-rw-r--r--include/clang/Parse/DeclSpec.h35
-rw-r--r--include/clang/Parse/Parser.h62
-rw-r--r--include/clang/Parse/Scope.h41
-rw-r--r--include/clang/Rewrite/Rewriter.h30
-rw-r--r--lib/AST/APValue.cpp3
-rw-r--r--lib/AST/ASTContext.cpp211
-rw-r--r--lib/AST/ASTDiagnostic.cpp6
-rw-r--r--lib/AST/ASTImporter.cpp28
-rw-r--r--lib/AST/Decl.cpp193
-rw-r--r--lib/AST/DeclBase.cpp38
-rw-r--r--lib/AST/DeclCXX.cpp48
-rw-r--r--lib/AST/DeclObjC.cpp18
-rw-r--r--lib/AST/DeclPrinter.cpp69
-rw-r--r--lib/AST/DeclTemplate.cpp22
-rw-r--r--lib/AST/DeclarationName.cpp59
-rw-r--r--lib/AST/Expr.cpp444
-rw-r--r--lib/AST/ExprCXX.cpp53
-rw-r--r--lib/AST/ExprConstant.cpp112
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp568
-rw-r--r--lib/AST/RecordLayoutBuilder.h8
-rw-r--r--lib/AST/Stmt.cpp89
-rw-r--r--lib/AST/StmtDumper.cpp78
-rw-r--r--lib/AST/StmtPrinter.cpp73
-rw-r--r--lib/AST/StmtProfile.cpp28
-rw-r--r--lib/AST/TemplateName.cpp18
-rw-r--r--lib/AST/Type.cpp20
-rw-r--r--lib/AST/TypePrinter.cpp4
-rw-r--r--lib/Analysis/CFG.cpp68
-rw-r--r--lib/Basic/Diagnostic.cpp70
-rw-r--r--lib/Basic/IdentifierTable.cpp6
-rw-r--r--lib/Basic/SourceManager.cpp100
-rw-r--r--lib/Basic/TargetInfo.cpp12
-rw-r--r--lib/Basic/Targets.cpp33
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp41
-rw-r--r--lib/Checker/BasicStore.cpp2
-rw-r--r--lib/Checker/BugReporter.cpp2
-rw-r--r--lib/Checker/BugReporterVisitors.cpp14
-rw-r--r--lib/Checker/CFRefCount.cpp115
-rw-r--r--lib/Checker/CMakeLists.txt1
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp19
-rw-r--r--lib/Checker/CastToStructChecker.cpp2
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp30
-rw-r--r--lib/Checker/CheckObjCInstMethSignature.cpp6
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp12
-rw-r--r--lib/Checker/Environment.cpp7
-rw-r--r--lib/Checker/GRCXXExprEngine.cpp246
-rw-r--r--lib/Checker/GRCoreEngine.cpp27
-rw-r--r--lib/Checker/GRExprEngine.cpp369
-rw-r--r--lib/Checker/MemRegion.cpp21
-rw-r--r--lib/Checker/NSAutoreleasePoolChecker.cpp2
-rw-r--r--lib/Checker/NSErrorChecker.cpp2
-rw-r--r--lib/Checker/ObjCUnusedIVarsChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp44
-rw-r--r--lib/Checker/SVals.cpp3
-rw-r--r--lib/Checker/SimpleSValuator.cpp22
-rw-r--r--lib/Checker/Store.cpp22
-rw-r--r--lib/Checker/UnixAPIChecker.cpp85
-rw-r--r--lib/CodeGen/CGBlocks.cpp24
-rw-r--r--lib/CodeGen/CGBlocks.h3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp91
-rw-r--r--lib/CodeGen/CGCXX.cpp12
-rw-r--r--lib/CodeGen/CGCall.cpp11
-rw-r--r--lib/CodeGen/CGClass.cpp664
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp209
-rw-r--r--lib/CodeGen/CGDebugInfo.h10
-rw-r--r--lib/CodeGen/CGDecl.cpp62
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp11
-rw-r--r--lib/CodeGen/CGException.cpp235
-rw-r--r--lib/CodeGen/CGExpr.cpp335
-rw-r--r--lib/CodeGen/CGExprAgg.cpp25
-rw-r--r--lib/CodeGen/CGExprCXX.cpp50
-rw-r--r--lib/CodeGen/CGExprConstant.cpp579
-rw-r--r--lib/CodeGen/CGExprScalar.cpp133
-rw-r--r--lib/CodeGen/CGObjC.cpp216
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp230
-rw-r--r--lib/CodeGen/CGObjCMac.cpp341
-rw-r--r--lib/CodeGen/CGObjCRuntime.h5
-rw-r--r--lib/CodeGen/CGRTTI.cpp101
-rw-r--r--lib/CodeGen/CGRecordLayout.h134
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp306
-rw-r--r--lib/CodeGen/CGStmt.cpp64
-rw-r--r--lib/CodeGen/CGTemporaries.cpp12
-rw-r--r--lib/CodeGen/CGVTT.cpp24
-rw-r--r--lib/CodeGen/CGVTables.cpp (renamed from lib/CodeGen/CGVtable.cpp)451
-rw-r--r--lib/CodeGen/CGVTables.h (renamed from lib/CodeGen/CGVtable.h)39
-rw-r--r--lib/CodeGen/CGValue.h67
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp24
-rw-r--r--lib/CodeGen/CodeGenFunction.h93
-rw-r--r--lib/CodeGen/CodeGenModule.cpp239
-rw-r--r--lib/CodeGen/CodeGenModule.h37
-rw-r--r--lib/CodeGen/CodeGenTypes.h5
-rw-r--r--lib/CodeGen/Mangle.cpp239
-rw-r--r--lib/CodeGen/Mangle.h12
-rw-r--r--lib/CodeGen/TargetInfo.cpp83
-rw-r--r--lib/Driver/Driver.cpp6
-rw-r--r--lib/Driver/ToolChains.cpp21
-rw-r--r--lib/Driver/ToolChains.h17
-rw-r--r--lib/Driver/Tools.cpp129
-rw-r--r--lib/Driver/Tools.h5
-rw-r--r--lib/Frontend/ASTConsumers.cpp191
-rw-r--r--lib/Frontend/ASTUnit.cpp18
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp209
-rw-r--r--lib/Frontend/CacheTokens.cpp5
-rw-r--r--lib/Frontend/CodeGenAction.cpp313
-rw-r--r--lib/Frontend/CompilerInstance.cpp19
-rw-r--r--lib/Frontend/CompilerInvocation.cpp135
-rw-r--r--lib/Frontend/FixItRewriter.cpp105
-rw-r--r--lib/Frontend/FrontendActions.cpp71
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp59
-rw-r--r--lib/Frontend/InitPreprocessor.cpp30
-rw-r--r--lib/Frontend/LangStandards.cpp2
-rw-r--r--lib/Frontend/PCHReader.cpp34
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp17
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp135
-rw-r--r--lib/Frontend/PCHWriter.cpp15
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp10
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp83
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp9
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp50
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp528
-rw-r--r--lib/Frontend/StmtXML.cpp5
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp24
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp463
-rw-r--r--lib/Frontend/Warnings.cpp6
-rw-r--r--lib/Headers/CMakeLists.txt2
-rw-r--r--lib/Headers/altivec.h1483
-rw-r--r--lib/Headers/arm_neon.h537
-rw-r--r--lib/Headers/nmmintrin.h2
-rw-r--r--lib/Headers/stdint.h7
-rw-r--r--lib/Headers/tmmintrin.h2
-rw-r--r--lib/Index/ASTLocation.cpp4
-rw-r--r--lib/Index/Analyzer.cpp79
-rw-r--r--lib/Lex/Lexer.cpp6
-rw-r--r--lib/Lex/LiteralSupport.cpp5
-rw-r--r--lib/Lex/PPDirectives.cpp24
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PPMacroExpansion.cpp31
-rw-r--r--lib/Lex/Preprocessor.cpp8
-rw-r--r--lib/Lex/TokenConcatenation.cpp6
-rw-r--r--lib/Parse/AttributeList.cpp3
-rw-r--r--lib/Parse/DeclSpec.cpp1
-rw-r--r--lib/Parse/MinimalAction.cpp37
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp50
-rw-r--r--lib/Parse/ParseDecl.cpp112
-rw-r--r--lib/Parse/ParseDeclCXX.cpp16
-rw-r--r--lib/Parse/ParseExpr.cpp106
-rw-r--r--lib/Parse/ParseExprCXX.cpp33
-rw-r--r--lib/Parse/ParseInit.cpp132
-rw-r--r--lib/Parse/ParseObjc.cpp350
-rw-r--r--lib/Parse/ParseStmt.cpp13
-rw-r--r--lib/Parse/ParseTentative.cpp13
-rw-r--r--lib/Parse/Parser.cpp12
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp4
-rw-r--r--lib/Rewrite/Rewriter.cpp8
-rw-r--r--lib/Runtime/Makefile2
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp93
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h4
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp4
-rw-r--r--lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--lib/Sema/Lookup.h25
-rw-r--r--lib/Sema/ParseAST.cpp27
-rw-r--r--lib/Sema/Sema.cpp22
-rw-r--r--lib/Sema/Sema.h807
-rw-r--r--lib/Sema/SemaAccess.cpp706
-rw-r--r--lib/Sema/SemaCXXCast.cpp239
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp110
-rw-r--r--lib/Sema/SemaChecking.cpp198
-rw-r--r--lib/Sema/SemaCodeComplete.cpp584
-rw-r--r--lib/Sema/SemaDecl.cpp868
-rw-r--r--lib/Sema/SemaDeclAttr.cpp58
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2088
-rw-r--r--lib/Sema/SemaDeclObjC.cpp237
-rw-r--r--lib/Sema/SemaExpr.cpp768
-rw-r--r--lib/Sema/SemaExprCXX.cpp537
-rw-r--r--lib/Sema/SemaExprObjC.cpp1004
-rw-r--r--lib/Sema/SemaInit.cpp428
-rw-r--r--lib/Sema/SemaInit.h60
-rw-r--r--lib/Sema/SemaLookup.cpp501
-rw-r--r--lib/Sema/SemaObjCProperty.cpp61
-rw-r--r--lib/Sema/SemaOverload.cpp798
-rw-r--r--lib/Sema/SemaOverload.h35
-rw-r--r--lib/Sema/SemaStmt.cpp214
-rw-r--r--lib/Sema/SemaTemplate.cpp496
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp160
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp274
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp336
-rw-r--r--lib/Sema/SemaType.cpp124
-rw-r--r--lib/Sema/TreeTransform.h817
-rw-r--r--test/ASTMerge/category.m2
-rw-r--r--test/ASTMerge/enum.c2
-rw-r--r--test/ASTMerge/function.c2
-rw-r--r--test/ASTMerge/interface.m2
-rw-r--r--test/ASTMerge/property.m2
-rw-r--r--test/ASTMerge/struct.c2
-rw-r--r--test/ASTMerge/typedef.c2
-rw-r--r--test/ASTMerge/var.c2
-rw-r--r--test/Analysis/inline.c4
-rw-r--r--test/Analysis/inline2.c3
-rw-r--r--test/Analysis/inline3.c4
-rw-r--r--test/Analysis/inline4.c4
-rw-r--r--test/Analysis/method-call.cpp18
-rw-r--r--test/Analysis/misc-ps-region-store.m59
-rw-r--r--test/Analysis/misc-ps.m24
-rw-r--r--test/Analysis/new.cpp14
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m6
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/override-werror.c2
-rw-r--r--test/Analysis/unix-fns.c37
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp15
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp60
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp2
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp4
-rw-r--r--test/CXX/class.access/class.access.base/p1.cpp2
-rw-r--r--test/CXX/class.access/class.access.base/p5.cpp2
-rw-r--r--test/CXX/class.access/class.access.nest/p1.cpp2
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp97
-rw-r--r--test/CXX/class.access/class.friend/p2-cxx03.cpp13
-rw-r--r--test/CXX/class.access/class.friend/p3-cxx0x.cpp29
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp387
-rw-r--r--test/CXX/class.access/p4.cpp99
-rw-r--r--test/CXX/class.access/p6.cpp69
-rw-r--r--test/CXX/class/class.friend/p2.cpp4
-rw-r--r--test/CXX/class/class.local/p2.cpp2
-rw-r--r--test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp2
-rw-r--r--test/CXX/conv/conv.mem/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp12
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp7
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp50
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp61
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp8
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp16
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp3
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp1
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp6
-rw-r--r--test/CXX/except/except.handle/p16.cpp4
-rw-r--r--test/CXX/expr/expr.unary/expr.delete/p5.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p19.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p20-0x.cpp2
-rw-r--r--test/CXX/expr/expr.unary/expr.new/p20.cpp2
-rw-r--r--test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp14
-rw-r--r--test/CXX/stmt.stmt/stmt.select/p3.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp38
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp83
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p3.cpp3
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p1.cpp6
-rw-r--r--test/CXX/temp/temp.param/p3.cpp12
-rw-r--r--test/CXX/temp/temp.res/temp.local/p3.cpp32
-rw-r--r--test/CXX/temp/temp.spec/p5.cpp17
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p3.cpp16
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p4.cpp22
-rw-r--r--test/CXX/temp/temp.spec/temp.inst/p11.cpp15
-rw-r--r--test/CodeCompletion/call.cpp1
-rw-r--r--test/CodeCompletion/macros.c4
-rw-r--r--test/CodeCompletion/ordinary-name.cpp18
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c8
-rw-r--r--test/CodeGen/arm-arguments.c30
-rw-r--r--test/CodeGen/arm_asm_clobber.c21
-rw-r--r--test/CodeGen/asm-errors.c8
-rw-r--r--test/CodeGen/asm.c21
-rw-r--r--test/CodeGen/asm_arm.c32
-rw-r--r--test/CodeGen/bitfield-2.c368
-rw-r--r--test/CodeGen/blocks.c2
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c332
-rw-r--r--test/CodeGen/catch-undef-behavior.c7
-rw-r--r--test/CodeGen/const-unordered-compare.c7
-rw-r--r--test/CodeGen/decl.c32
-rw-r--r--test/CodeGen/designated-initializers.c37
-rw-r--r--test/CodeGen/functions.c12
-rw-r--r--test/CodeGen/global-init.c30
-rw-r--r--test/CodeGen/init.c6
-rw-r--r--test/CodeGen/libcalls.c50
-rw-r--r--test/CodeGen/palignr.c19
-rw-r--r--test/CodeGen/struct-passing.c4
-rw-r--r--test/CodeGen/union-init2.c11
-rw-r--r--test/CodeGen/x86_32-arguments.c126
-rw-r--r--test/CodeGen/x86_64-arguments.c81
-rw-r--r--test/CodeGenCXX/PR6747.cpp11
-rw-r--r--test/CodeGenCXX/address-of-fntemplate.cpp14
-rw-r--r--test/CodeGenCXX/anonymous-union-member-initializer.cpp26
-rw-r--r--test/CodeGenCXX/arm.cpp20
-rw-r--r--test/CodeGenCXX/assign-operator.cpp14
-rw-r--r--test/CodeGenCXX/bitfield-layout.cpp43
-rw-r--r--test/CodeGenCXX/block-destruct.cpp9
-rw-r--r--test/CodeGenCXX/c-linkage.cpp13
-rw-r--r--test/CodeGenCXX/constructor-init-reference.cpp2
-rw-r--r--test/CodeGenCXX/constructors.cpp14
-rw-r--r--test/CodeGenCXX/default-arg-temps.cpp50
-rw-r--r--test/CodeGenCXX/default-destructor-nested.cpp2
-rw-r--r--test/CodeGenCXX/delete.cpp26
-rw-r--r--test/CodeGenCXX/destructor-debug-info.cpp21
-rw-r--r--test/CodeGenCXX/eh.cpp87
-rw-r--r--test/CodeGenCXX/empty-classes.cpp69
-rw-r--r--test/CodeGenCXX/exceptions-no-rtti.cpp48
-rw-r--r--test/CodeGenCXX/field-access-debug-info.cpp11
-rw-r--r--test/CodeGenCXX/implicit-copy-assign-operator.cpp56
-rw-r--r--test/CodeGenCXX/instantiate-init-list.cpp2
-rw-r--r--test/CodeGenCXX/mangle-template.cpp40
-rw-r--r--test/CodeGenCXX/mangle.cpp11
-rw-r--r--test/CodeGenCXX/member-function-pointer-calls.cpp11
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp37
-rw-r--r--test/CodeGenCXX/member-initializers.cpp2
-rw-r--r--test/CodeGenCXX/namespace-aliases.cpp6
-rw-r--r--test/CodeGenCXX/new-operator-phi.cpp2
-rw-r--r--test/CodeGenCXX/new.cpp12
-rw-r--r--test/CodeGenCXX/operator-new.cpp1
-rw-r--r--test/CodeGenCXX/reference-in-blocks.cpp21
-rw-r--r--test/CodeGenCXX/rtti-fundamental.cpp4
-rw-r--r--test/CodeGenCXX/static-init.cpp11
-rw-r--r--test/CodeGenCXX/static-local-in-local-class.cpp21
-rw-r--r--test/CodeGenCXX/template-anonymous-union-member-initializer.cpp1
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp1
-rw-r--r--test/CodeGenCXX/temporaries.cpp19
-rw-r--r--test/CodeGenCXX/value-init.cpp26
-rw-r--r--test/CodeGenCXX/virt-template-vtable.cpp1
-rw-r--r--test/CodeGenCXX/virt.cpp696
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp334
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp4
-rw-r--r--test/CodeGenObjC/atomic-aggregate-property.m28
-rw-r--r--test/CodeGenObjC/blocks.m2
-rw-r--r--test/CodeGenObjC/encode-cstyle-method.m11
-rw-r--r--test/CodeGenObjC/exceptions.m18
-rw-r--r--test/CodeGenObjC/image-info.m10
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m2
-rw-r--r--test/CodeGenObjC/metadata_symbols.m51
-rw-r--r--test/CodeGenObjC/next-objc-dispatch.m73
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m2
-rw-r--r--test/CodeGenObjC/ns-constant-strings.m33
-rw-r--r--test/CodeGenObjC/objc-gc-aggr-assign.m46
-rw-r--r--test/CodeGenObjC/objc2-legacy-dispatch.m4
-rw-r--r--test/CodeGenObjC/x86_64-struct-return-gc.m2
-rw-r--r--test/CodeGenObjCXX/ivar-objects.mm71
-rw-r--r--test/CodeGenObjCXX/mangle.mm12
-rw-r--r--test/Coverage/ast-printing.cpp2
-rw-r--r--test/Driver/darwin-ld.c2
-rw-r--r--test/Driver/darwin-objc-defaults.m88
-rw-r--r--test/Driver/darwin-objc-gc.m19
-rw-r--r--test/Driver/darwin-objc-options.m19
-rw-r--r--test/FixIt/fixit-at.c5
-rw-r--r--test/FixIt/fixit-c90.c8
-rw-r--r--test/FixIt/fixit-cxx0x.cpp10
-rw-r--r--test/FixIt/fixit-errors-1.c5
-rw-r--r--test/FixIt/fixit-errors.c5
-rw-r--r--test/FixIt/fixit-objc.m7
-rw-r--r--test/FixIt/fixit-pmem.cpp5
-rw-r--r--test/FixIt/fixit-suffix.c5
-rw-r--r--test/FixIt/fixit-unrecoverable.c10
-rw-r--r--test/FixIt/fixit-unrecoverable.cpp11
-rw-r--r--test/FixIt/fixit.c19
-rw-r--r--test/FixIt/fixit.cpp15
-rw-r--r--test/FixIt/typo.c4
-rw-r--r--test/FixIt/typo.cpp5
-rw-r--r--test/FixIt/typo.m60
-rw-r--r--test/Index/Inputs/complete-pch.h10
-rw-r--r--test/Index/annotate-tokens.m18
-rw-r--r--test/Index/complete-at-directives.m4
-rw-r--r--test/Index/complete-at-exprstmt.m4
-rw-r--r--test/Index/complete-exprs.c15
-rw-r--r--test/Index/complete-method-decls.m82
-rw-r--r--test/Index/complete-objc-message-id.m42
-rw-r--r--test/Index/complete-objc-message.m78
-rw-r--r--test/Index/complete-pch.m26
-rw-r--r--test/Index/invalid-code-rdar_7833619.m4
-rw-r--r--test/Index/load-exprs.c39
-rw-r--r--test/Index/local-symbols.m26
-rw-r--r--test/Index/print-usrs.c4
-rw-r--r--test/Index/usrs.m87
-rw-r--r--test/Lexer/gnu_keywords.c12
-rw-r--r--test/Lexer/utf-16.c6
-rw-r--r--test/Lexer/utf-16.c.txtbin0 -> 48 bytes
-rw-r--r--test/Misc/message-length.c16
-rw-r--r--test/Misc/tabstop.c3
-rw-r--r--test/Misc/verify.c14
-rw-r--r--test/PCH/exprs.c4
-rw-r--r--test/PCH/exprs.h13
-rw-r--r--test/PCH/functions.c4
-rw-r--r--test/PCH/functions.h5
-rw-r--r--test/PCH/objc_stmts.h22
-rw-r--r--test/PCH/objc_stmts.m12
-rw-r--r--test/PCH/pr4489.c7
-rw-r--r--test/PCH/types.c2
-rw-r--r--test/Parser/altivec.c8
-rw-r--r--test/Parser/attributes.c4
-rw-r--r--test/Parser/builtin_types_compatible.c2
-rw-r--r--test/Parser/check-syntax-1.m4
-rw-r--r--test/Parser/cxx-altivec.cpp9
-rw-r--r--test/Parser/cxx-casting.cpp9
-rw-r--r--test/Parser/cxx-class.cpp2
-rw-r--r--test/Parser/cxx-friend.cpp6
-rw-r--r--test/Parser/cxx-template-decl.cpp2
-rw-r--r--test/Parser/declarators.c2
-rw-r--r--test/Parser/implicit-casts.c2
-rw-r--r--test/Parser/objc-init.m3
-rw-r--r--test/Parser/objc-quirks.m18
-rw-r--r--test/Preprocessor/expr_usual_conversions.c5
-rw-r--r--test/Preprocessor/if_warning.c6
-rw-r--r--test/Preprocessor/init.c10
-rw-r--r--test/Preprocessor/line-directive-output.c71
-rw-r--r--test/Preprocessor/non_fragile_feature.m4
-rw-r--r--test/Preprocessor/output_paste_avoid.c5
-rw-r--r--test/Rewriter/dllimport-typedef.c4
-rw-r--r--test/Rewriter/missing-dllimport.c4
-rw-r--r--test/Rewriter/rewrite-super-message.mm2
-rw-r--r--test/Sema/address_spaces.c2
-rw-r--r--test/Sema/altivec-init.c4
-rw-r--r--test/Sema/anonymous-struct-union.c12
-rw-r--r--test/Sema/arm-layout.c49
-rw-r--r--test/Sema/array-constraint.c4
-rw-r--r--test/Sema/array-init.c14
-rw-r--r--test/Sema/attr-format.c2
-rw-r--r--test/Sema/attr-noreturn.c2
-rw-r--r--test/Sema/attr-section.c2
-rw-r--r--test/Sema/bitfield.c4
-rw-r--r--test/Sema/block-call.c12
-rw-r--r--test/Sema/block-misc.c12
-rw-r--r--test/Sema/block-return.c14
-rw-r--r--test/Sema/builtin-prefetch.c4
-rw-r--r--test/Sema/builtin-stackaddress.c4
-rw-r--r--test/Sema/builtins.c2
-rw-r--r--test/Sema/cast-to-union.c2
-rw-r--r--test/Sema/compare.c5
-rw-r--r--test/Sema/compound-literal.c2
-rw-r--r--test/Sema/conditional-expr.c8
-rw-r--r--test/Sema/conditional.c4
-rw-r--r--test/Sema/decl-invalid.c12
-rw-r--r--test/Sema/declspec.c2
-rw-r--r--test/Sema/enum.c3
-rw-r--r--test/Sema/exprs.c8
-rw-r--r--test/Sema/ext_vector_casts.c2
-rw-r--r--test/Sema/format-strings.c4
-rw-r--r--test/Sema/function-ptr.c6
-rw-r--r--test/Sema/function-redecl.c2
-rw-r--r--test/Sema/incompatible-sign.c4
-rw-r--r--test/Sema/invalid-init-diag.c2
-rw-r--r--test/Sema/offsetof.c13
-rw-r--r--test/Sema/parentheses.c12
-rw-r--r--test/Sema/pointer-conversion.c6
-rw-r--r--test/Sema/predef.c2
-rw-r--r--test/Sema/predefined-function.c5
-rw-r--r--test/Sema/return.c2
-rw-r--r--test/Sema/statements.c12
-rw-r--r--test/Sema/struct-compat.c2
-rw-r--r--test/Sema/transparent-union.c2
-rw-r--r--test/Sema/typedef-retain.c4
-rw-r--r--test/Sema/unused-expr.c6
-rw-r--r--test/Sema/vector-assign.c44
-rw-r--r--test/Sema/vector-cast.c4
-rw-r--r--test/Sema/warn-missing-braces.c2
-rw-r--r--test/Sema/warn-unused-function.c7
-rw-r--r--test/Sema/warn-unused-parameters.c15
-rw-r--r--test/Sema/warn-unused-value.c15
-rw-r--r--test/Sema/warn-write-strings.c2
-rw-r--r--test/Sema/x86-builtin-palignr.c10
-rw-r--r--test/SemaCXX/abstract.cpp9
-rw-r--r--test/SemaCXX/access-base-class.cpp2
-rw-r--r--test/SemaCXX/access-control-check.cpp2
-rw-r--r--test/SemaCXX/addr-of-overloaded-function.cpp32
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp17
-rw-r--r--test/SemaCXX/anonymous-union.cpp2
-rw-r--r--test/SemaCXX/bitfield-layout.cpp30
-rw-r--r--test/SemaCXX/class-base-member-init.cpp23
-rw-r--r--test/SemaCXX/class.cpp2
-rw-r--r--test/SemaCXX/conditional-expr.cpp10
-rw-r--r--test/SemaCXX/constant-expression.cpp10
-rw-r--r--test/SemaCXX/constructor-initializer.cpp48
-rw-r--r--test/SemaCXX/conversion-function.cpp88
-rw-r--r--test/SemaCXX/copy-assignment.cpp2
-rw-r--r--test/SemaCXX/copy-initialization.cpp21
-rw-r--r--test/SemaCXX/cstyle-cast.cpp2
-rw-r--r--test/SemaCXX/default-assignment-operator.cpp22
-rw-r--r--test/SemaCXX/default-constructor-initializers.cpp6
-rw-r--r--test/SemaCXX/default1.cpp9
-rw-r--r--test/SemaCXX/default2.cpp3
-rw-r--r--test/SemaCXX/derived-to-base-ambig.cpp4
-rw-r--r--test/SemaCXX/direct-initializer.cpp2
-rw-r--r--test/SemaCXX/elaborated-type-specifier.cpp2
-rw-r--r--test/SemaCXX/exceptions.cpp23
-rw-r--r--test/SemaCXX/functional-cast.cpp2
-rw-r--r--test/SemaCXX/illegal-member-initialization.cpp6
-rw-r--r--test/SemaCXX/implicit-member-functions.cpp35
-rw-r--r--test/SemaCXX/inc-decrement-qualifiers.cpp9
-rw-r--r--test/SemaCXX/libstdcxx_is_pod_hack.cpp6
-rw-r--r--test/SemaCXX/libstdcxx_map_base_hack.cpp25
-rw-r--r--test/SemaCXX/local-classes.cpp9
-rw-r--r--test/SemaCXX/member-expr.cpp22
-rw-r--r--test/SemaCXX/member-location.cpp5
-rw-r--r--test/SemaCXX/member-pointer.cpp16
-rw-r--r--test/SemaCXX/missing-header.cpp9
-rw-r--r--test/SemaCXX/namespace-alias.cpp10
-rw-r--r--test/SemaCXX/nested-name-spec.cpp16
-rw-r--r--test/SemaCXX/new-delete.cpp23
-rw-r--r--test/SemaCXX/no-exceptions.cpp21
-rw-r--r--test/SemaCXX/offsetof.cpp37
-rw-r--r--test/SemaCXX/overload-call.cpp30
-rw-r--r--test/SemaCXX/overloaded-operator.cpp30
-rw-r--r--test/SemaCXX/qual-id-test.cpp6
-rw-r--r--test/SemaCXX/qualified-id-lookup.cpp22
-rw-r--r--test/SemaCXX/ref-init-ambiguous.cpp2
-rw-r--r--test/SemaCXX/references.cpp4
-rw-r--r--test/SemaCXX/static-cast.cpp2
-rw-r--r--test/SemaCXX/storage-class.cpp4
-rw-r--r--test/SemaCXX/typedef-redecl.cpp13
-rw-r--r--test/SemaCXX/typeid-ref.cpp12
-rw-r--r--test/SemaCXX/typeid.cpp1
-rw-r--r--test/SemaCXX/unused-functions.cpp8
-rw-r--r--test/SemaCXX/user-defined-conversions.cpp15
-rw-r--r--test/SemaCXX/value-initialization.cpp6
-rw-r--r--test/SemaCXX/virtual-override.cpp2
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp49
-rw-r--r--test/SemaCXX/warn-missing-noreturn.cpp14
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp57
-rw-r--r--test/SemaCXX/warn-unused-parameters.cpp26
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp8
-rw-r--r--test/SemaCXX/warn-weak-vtables.cpp2
-rw-r--r--test/SemaObjC/argument-checking.m19
-rw-r--r--test/SemaObjC/block-type-safety.m18
-rw-r--r--test/SemaObjC/blocks.m12
-rw-r--r--test/SemaObjC/call-super-2.m2
-rw-r--r--test/SemaObjC/catch-stmt.m4
-rw-r--r--test/SemaObjC/class-bitfield.m2
-rw-r--r--test/SemaObjC/class-method-lookup.m2
-rw-r--r--test/SemaObjC/class-method-self.m6
-rw-r--r--test/SemaObjC/compatible-protocol-qualified-types.m4
-rw-r--r--test/SemaObjC/compound-init.m7
-rw-r--r--test/SemaObjC/comptypes-1.m12
-rw-r--r--test/SemaObjC/comptypes-3.m18
-rw-r--r--test/SemaObjC/comptypes-6.m2
-rw-r--r--test/SemaObjC/comptypes-7.m32
-rw-r--r--test/SemaObjC/comptypes-legal.m4
-rw-r--r--test/SemaObjC/conditional-expr-2.m2
-rw-r--r--test/SemaObjC/conditional-expr-3.m4
-rw-r--r--test/SemaObjC/conditional-expr-4.m2
-rw-r--r--test/SemaObjC/conditional-expr.m4
-rw-r--r--test/SemaObjC/continuation-class-err.m6
-rw-r--r--test/SemaObjC/default-synthesize.m24
-rw-r--r--test/SemaObjC/ibaction.m15
-rw-r--r--test/SemaObjC/id.m4
-rw-r--r--test/SemaObjC/incompatible-protocol-qualified-types.m8
-rw-r--r--test/SemaObjC/invalid-code.m7
-rw-r--r--test/SemaObjC/invalid-objc-decls-1.m4
-rw-r--r--test/SemaObjC/invalid-receiver.m2
-rw-r--r--test/SemaObjC/ivar-in-class-extension-error.m8
-rw-r--r--test/SemaObjC/ivar-in-class-extension.m6
-rw-r--r--test/SemaObjC/ivar-lookup.m19
-rw-r--r--test/SemaObjC/message.m2
-rw-r--r--test/SemaObjC/method-arg-qualifier-warning.m6
-rw-r--r--test/SemaObjC/method-bad-param.m12
-rw-r--r--test/SemaObjC/objc-cstyle-args-in-methods.m20
-rw-r--r--test/SemaObjC/pedantic-dynamic-test.m16
-rw-r--r--test/SemaObjC/property-9.m4
-rw-r--r--test/SemaObjC/property-typecheck-1.m6
-rw-r--r--test/SemaObjC/protocol-id-test-3.m14
-rw-r--r--test/SemaObjC/protocol-typecheck.m4
-rw-r--r--test/SemaObjC/protocol-warn.m2
-rw-r--r--test/SemaObjC/stmts.m4
-rw-r--r--test/SemaObjC/super-class-protocol-conformance.m47
-rw-r--r--test/SemaObjC/super.m47
-rw-r--r--test/SemaObjC/synthesized-ivar.m3
-rw-r--r--test/SemaObjC/transparent-union.m22
-rw-r--r--test/SemaObjC/unused.m4
-rw-r--r--test/SemaObjC/warn-incompatible-builtin-types.m20
-rw-r--r--test/SemaObjC/warn-selector-selection.m2
-rw-r--r--test/SemaObjC/warn-superclass-method-mismatch.m2
-rw-r--r--test/SemaObjC/warn-unused-exception-param.m4
-rw-r--r--test/SemaObjC/warn-write-strings.m2
-rw-r--r--test/SemaObjCXX/blocks.mm4
-rw-r--r--test/SemaObjCXX/instantiate-expr.mm73
-rw-r--r--test/SemaObjCXX/instantiate-message.mm50
-rw-r--r--test/SemaObjCXX/instantiate-stmt.mm77
-rw-r--r--test/SemaObjCXX/ivar-lookup.mm18
-rw-r--r--test/SemaObjCXX/ivar-reference-type.mm5
-rw-r--r--test/SemaObjCXX/linkage-spec.mm8
-rw-r--r--test/SemaObjCXX/message.mm77
-rw-r--r--test/SemaObjCXX/objc-pointer-conv.mm4
-rw-r--r--test/SemaObjCXX/overload-1.mm25
-rw-r--r--test/SemaObjCXX/parameters.mm12
-rw-r--r--test/SemaObjCXX/void_to_obj.mm2
-rw-r--r--test/SemaTemplate/class-template-decl.cpp5
-rw-r--r--test/SemaTemplate/constructor-template.cpp15
-rw-r--r--test/SemaTemplate/default-expr-arguments-2.cpp19
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp30
-rw-r--r--test/SemaTemplate/dependent-names.cpp4
-rw-r--r--test/SemaTemplate/destructor-template.cpp8
-rw-r--r--test/SemaTemplate/elaborated-type-specifier.cpp36
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp2
-rw-r--r--test/SemaTemplate/friend-template.cpp80
-rw-r--r--test/SemaTemplate/friend.cpp19
-rw-r--r--test/SemaTemplate/fun-template-def.cpp2
-rw-r--r--test/SemaTemplate/injected-class-name.cpp12
-rw-r--r--test/SemaTemplate/instantiate-complete.cpp20
-rw-r--r--test/SemaTemplate/instantiate-default-assignment-operator.cpp8
-rw-r--r--test/SemaTemplate/instantiate-expr-2.cpp19
-rw-r--r--test/SemaTemplate/instantiate-expr-5.cpp36
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp5
-rw-r--r--test/SemaTemplate/instantiate-function-params.cpp41
-rw-r--r--test/SemaTemplate/instantiate-local-class.cpp4
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp9
-rw-r--r--test/SemaTemplate/instantiate-member-expr.cpp2
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp5
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp2
-rw-r--r--test/SemaTemplate/instantiate-method.cpp60
-rw-r--r--test/SemaTemplate/instantiate-non-type-template-parameter.cpp24
-rw-r--r--test/SemaTemplate/instantiate-typedef.cpp3
-rw-r--r--test/SemaTemplate/instantiate-using-decl.cpp2
-rw-r--r--test/SemaTemplate/instantiation-depth.cpp10
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp13
-rw-r--r--test/SemaTemplate/qualified-id.cpp1
-rw-r--r--test/SemaTemplate/temp_arg.cpp3
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp39
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp24
-rw-r--r--test/SemaTemplate/template-decl-fail.cpp4
-rw-r--r--test/SemaTemplate/typename-specifier-4.cpp2
-rw-r--r--test/SemaTemplate/typename-specifier.cpp15
-rw-r--r--tools/CIndex/CIndex.cpp108
-rw-r--r--tools/CIndex/CIndex.darwin.exports81
-rw-r--r--tools/CIndex/CIndex.exports161
-rw-r--r--tools/CIndex/CIndexCodeCompletion.cpp92
-rw-r--r--tools/CIndex/CIndexDiagnostic.cpp1
-rw-r--r--tools/CIndex/CIndexDiagnostic.h15
-rw-r--r--tools/CIndex/CIndexInclusionStack.cpp2
-rw-r--r--tools/CIndex/CIndexUSRs.cpp211
-rw-r--r--tools/CIndex/CIndexer.cpp1
-rw-r--r--tools/CIndex/CIndexer.h4
-rw-r--r--tools/CIndex/CMakeLists.txt6
-rw-r--r--tools/CIndex/CXCursor.cpp2
-rw-r--r--tools/CIndex/CXSourceLocation.h5
-rw-r--r--tools/CIndex/Makefile3
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/Makefile4
-rw-r--r--tools/c-index-test/CMakeLists.txt2
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c9
-rw-r--r--tools/driver/CMakeLists.txt3
-rw-r--r--tools/driver/cc1_main.cpp18
-rw-r--r--tools/libclang/CIndex.cpp2598
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp512
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp285
-rw-r--r--tools/libclang/CIndexDiagnostic.h53
-rw-r--r--tools/libclang/CIndexInclusionStack.cpp67
-rw-r--r--tools/libclang/CIndexUSRs.cpp477
-rw-r--r--tools/libclang/CIndexer.cpp154
-rw-r--r--tools/libclang/CIndexer.h78
-rw-r--r--tools/libclang/CMakeLists.txt57
-rw-r--r--tools/libclang/CXCursor.cpp370
-rw-r--r--tools/libclang/CXCursor.h112
-rw-r--r--tools/libclang/CXSourceLocation.h75
-rw-r--r--tools/libclang/Makefile55
-rw-r--r--tools/libclang/libclang.darwin.exports81
-rw-r--r--tools/libclang/libclang.exports81
-rwxr-xr-xtools/scan-build/ccc-analyzer7
-rwxr-xr-xutils/CIndex/completion_logger_server.py44
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/clang_video-05-25-2007.html2
-rw-r--r--www/clang_video-07-25-2007.html2
-rw-r--r--www/cxx_compatibility.html48
-rw-r--r--www/cxx_status.html31
-rw-r--r--www/menu.css2
747 files changed, 34158 insertions, 12055 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2001c7125d9a..1be646dfd2e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,26 @@ configure_file(
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+if( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE )
+ message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
+"the makefiles distributed with LLVM. Please create a directory and run cmake "
+"from there, passing the path to this source directory as the last argument. "
+"This process created the file `CMakeCache.txt' and the directory "
+"`CMakeFiles'. Please delete them.")
+endif()
+
+if( NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
+ file(GLOB_RECURSE
+ tablegenned_files_on_include_dir
+ "${CLANG_SOURCE_DIR}/include/clang/*.inc")
+ if( tablegenned_files_on_include_dir )
+ message(FATAL_ERROR "Apparently there is a previous in-source build, "
+"probably as the result of running `configure' and `make' on "
+"${CLANG_SOURCE_DIR}. This may cause problems. The suspicious files are:\n"
+"${tablegenned_files_on_include_dir}\nPlease clean the source directory.")
+ endif()
+endif()
+
# Compute the Clang version from the contents of VER
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VER CLANG_VERSION_DATA)
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
@@ -95,6 +115,7 @@ install(DIRECTORY include/
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include
FILES_MATCHING
+ PATTERN "CMakeFiles" EXCLUDE
PATTERN "*.inc"
)
diff --git a/Makefile b/Makefile
index f7e9e85bce83..39cf9c6f57a1 100644
--- a/Makefile
+++ b/Makefile
@@ -37,30 +37,3 @@ cscope.files:
-or -name '*.h' > cscope.files
.PHONY: test report clean cscope.files
-
-install-local::
- $(Echo) Installing include files
- $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
- $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \
- cd $(PROJ_SRC_ROOT)/tools/clang/include && \
- for hdr in `find . -type f '!' '(' -name '*~' \
- -o -name '.#*' -o -name '*.in' -o -name '*.txt' \
- -o -name 'Makefile' -o -name '*.td' ')' -print \
- | grep -v CVS | grep -v .svn | grep -v .dir` ; do \
- instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
- if test \! -d "$$instdir" ; then \
- $(EchoCmd) Making install directory $$instdir ; \
- $(MKDIR) $$instdir ;\
- fi ; \
- $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
- done ; \
- fi
-ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
- $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \
- cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
- for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \
- | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
- $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
- done ; \
- fi
-endif
diff --git a/VER b/VER
index c239c60cba28..cd5ac039d67e 100644
--- a/VER
+++ b/VER
@@ -1 +1 @@
-1.5
+2.0
diff --git a/bindings/python/README.txt b/bindings/python/README.txt
index ccc2619ccf5b..742cf8fbb8fc 100644
--- a/bindings/python/README.txt
+++ b/bindings/python/README.txt
@@ -2,10 +2,9 @@
// Clang Python Bindings
//===----------------------------------------------------------------------===//
-This directory implements Python bindings for Clang. Currently, only bindings
-for the CIndex C API exist.
+This directory implements Python bindings for Clang.
-You may need to alter LD_LIBRARY_PATH so that the CIndex library can be
+You may need to alter LD_LIBRARY_PATH so that the Clang library can be
found. The unit tests are designed to be run with 'nosetests'. For example:
--
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index f4409aec3325..f0f81b5d6948 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -71,11 +71,11 @@ def get_cindex_library():
import platform
name = platform.system()
if name == 'Darwin':
- return cdll.LoadLibrary('libCIndex.dylib')
+ return cdll.LoadLibrary('libclang.dylib')
elif name == 'Windows':
- return cdll.LoadLibrary('libCIndex.dll')
+ return cdll.LoadLibrary('libclang.dll')
else:
- return cdll.LoadLibrary('libCIndex.so')
+ return cdll.LoadLibrary('libclang.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
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index efdc3b325193..6556bb4e6a8c 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -8,7 +8,6 @@
/* Begin PBXBuildFile section */
03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F50AC50D416EAA00B9CF60 /* Targets.cpp */; };
- 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */; };
1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; };
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; };
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; };
@@ -26,11 +25,9 @@
1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */; };
1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */; };
1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; };
- 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; };
1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; };
1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; };
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 */; };
@@ -45,15 +42,48 @@
1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */; };
1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; };
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; };
- 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; };
+ 1A81AA19108144F40094E50B /* CGVTables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVTables.cpp */; };
1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; };
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
- 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A96785111486FDC00F24372 /* RecordLayout.cpp */; };
1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A97825A1108BA18002B98FC /* CGVTT.cpp */; };
1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; };
- 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; };
- 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA963C310D85A7300786C86 /* FullExpr.cpp */; };
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
+ 1ABD23D61182449800A48E65 /* APValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B11182449800A48E65 /* APValue.cpp */; };
+ 1ABD23D71182449800A48E65 /* ASTConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */; };
+ 1ABD23D81182449800A48E65 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B31182449800A48E65 /* ASTContext.cpp */; };
+ 1ABD23D91182449800A48E65 /* ASTDiagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */; };
+ 1ABD23DA1182449800A48E65 /* ASTImporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B51182449800A48E65 /* ASTImporter.cpp */; };
+ 1ABD23DB1182449800A48E65 /* AttrImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B61182449800A48E65 /* AttrImpl.cpp */; };
+ 1ABD23DC1182449800A48E65 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */; };
+ 1ABD23DD1182449800A48E65 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B81182449800A48E65 /* Decl.cpp */; };
+ 1ABD23DE1182449800A48E65 /* DeclarationName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B91182449800A48E65 /* DeclarationName.cpp */; };
+ 1ABD23DF1182449800A48E65 /* DeclBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BA1182449800A48E65 /* DeclBase.cpp */; };
+ 1ABD23E01182449800A48E65 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */; };
+ 1ABD23E11182449800A48E65 /* DeclFriend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */; };
+ 1ABD23E21182449800A48E65 /* DeclGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */; };
+ 1ABD23E31182449800A48E65 /* DeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */; };
+ 1ABD23E41182449800A48E65 /* DeclPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */; };
+ 1ABD23E51182449800A48E65 /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */; };
+ 1ABD23E61182449800A48E65 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C11182449800A48E65 /* Expr.cpp */; };
+ 1ABD23E71182449800A48E65 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C21182449800A48E65 /* ExprConstant.cpp */; };
+ 1ABD23E81182449800A48E65 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C31182449800A48E65 /* ExprCXX.cpp */; };
+ 1ABD23E91182449800A48E65 /* FullExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C41182449800A48E65 /* FullExpr.cpp */; };
+ 1ABD23EA1182449800A48E65 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C51182449800A48E65 /* InheritViz.cpp */; };
+ 1ABD23EB1182449800A48E65 /* NestedNameSpecifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */; };
+ 1ABD23EC1182449800A48E65 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C71182449800A48E65 /* ParentMap.cpp */; };
+ 1ABD23ED1182449800A48E65 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C81182449800A48E65 /* RecordLayout.cpp */; };
+ 1ABD23EE1182449800A48E65 /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */; };
+ 1ABD23EF1182449800A48E65 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CB1182449800A48E65 /* Stmt.cpp */; };
+ 1ABD23F01182449800A48E65 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */; };
+ 1ABD23F11182449800A48E65 /* StmtIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */; };
+ 1ABD23F21182449800A48E65 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */; };
+ 1ABD23F31182449800A48E65 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */; };
+ 1ABD23F41182449800A48E65 /* StmtViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D01182449800A48E65 /* StmtViz.cpp */; };
+ 1ABD23F51182449800A48E65 /* TemplateBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D11182449800A48E65 /* TemplateBase.cpp */; };
+ 1ABD23F61182449800A48E65 /* TemplateName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D21182449800A48E65 /* TemplateName.cpp */; };
+ 1ABD23F71182449800A48E65 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D31182449800A48E65 /* Type.cpp */; };
+ 1ABD23F81182449800A48E65 /* TypeLoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D41182449800A48E65 /* TypeLoc.cpp */; };
+ 1ABD23F91182449800A48E65 /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D51182449800A48E65 /* TypePrinter.cpp */; };
1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */; };
1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */; };
1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DD1105820D0047B991 /* DeclXML.cpp */; };
@@ -63,11 +93,7 @@
1ACB57EA1105820D0047B991 /* LangStandards.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E11105820D0047B991 /* LangStandards.cpp */; };
1ACB57EB1105820D0047B991 /* TypeXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E21105820D0047B991 /* TypeXML.cpp */; };
1ACB57EC1105820D0047B991 /* VerifyDiagnosticsClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */; };
- 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795110A90C6100741BBA /* TypePrinter.cpp */; };
- 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795210A90C6100741BBA /* TypeLoc.cpp */; };
- 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 */; };
1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; };
1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8701161085D00AE030A /* ASTMerge.cpp */; };
1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */; };
@@ -78,12 +104,10 @@
352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */; };
352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */; };
352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */; };
- 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
352712510DAFE54700C76352 /* IdentifierResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352712500DAFE54700C76352 /* IdentifierResolver.cpp */; };
3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3534A01C0E129849002709B2 /* ParseCXXInlineMethods.cpp */; };
3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3536456A0E23EBF7009C6509 /* Environment.cpp */; };
3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */; };
- 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */; };
353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */; };
35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35475B1F0E79973F0000BFE4 /* CGCall.cpp */; };
355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355106850E9A8507006A4E44 /* MemRegion.cpp */; };
@@ -94,17 +118,14 @@
35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B850F5C7FD700D92AA9 /* RangeConstraintManager.cpp */; };
35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */; };
35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */; };
- 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1A80EB136B100C59739 /* InheritViz.cpp */; };
35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */; };
3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */; };
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */; };
357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 357EA27C0F2526F300439B60 /* SemaLookup.cpp */; };
- 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */; };
35862B0D0E3628CB0009F542 /* CheckDeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */; };
35862B120E3629850009F542 /* GRExprEngineInternalChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */; };
358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */; };
- 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */; };
358F51520E529AA4007F2102 /* GRState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358F51510E529AA4007F2102 /* GRState.cpp */; };
3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3591853E0EFB1088000039AF /* SemaTemplate.cpp */; };
3593790A0DA48ABA0043B19C /* BugReporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 359379090DA48ABA0043B19C /* BugReporter.cpp */; };
@@ -115,20 +136,15 @@
35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */; };
35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */; };
35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */; };
- 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */; };
- 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */; };
35D55B270D81D8C60092E734 /* BasicValueFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */; };
35D55B280D81D8C60092E734 /* CFRefCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B250D81D8C60092E734 /* CFRefCount.cpp */; };
35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */; };
35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */; };
35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */; };
- 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */; };
- 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */; };
35EF67700DAD1D2C00B19414 /* SemaDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */; };
35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */; };
35F2A01E0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F2A01D0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp */; };
35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */; };
- 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */; };
72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */; };
84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */; };
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
@@ -162,8 +178,6 @@
DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06D42F0A8BB52D0050E87E /* Parser.cpp */; };
DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06E8130A8FF9330050E87E /* Action.h */; };
DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE0FCA620A95859D00248FD5 /* Expr.h */; };
- DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE0FCB330A9C21F100248FD5 /* Expr.cpp */; };
- DE1733000B068B700080B521 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE1732FF0B068B700080B521 /* ASTContext.cpp */; };
DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE17336D0B068DC20080B521 /* DeclSpec.cpp */; };
DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE17336F0B068DC60080B521 /* DeclSpec.h */; };
DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE1F22020A7D852A00FBF588 /* Parser.h */; };
@@ -174,7 +188,6 @@
DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */; };
DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */; };
DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3450D60AEB543100DBC861 /* DirectoryLookup.h */; };
- DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3452400AEF1A2D00DBC861 /* Stmt.cpp */; };
DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3452800AEF1B1800DBC861 /* Stmt.h */; };
DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345C190AFC658B00DBC861 /* StmtVisitor.h */; };
DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345F210AFD347900DBC861 /* StmtNodes.def */; };
@@ -184,11 +197,9 @@
DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */; };
DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */; };
DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */; };
- DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */; };
DE3464220B03040900DBC861 /* Type.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3464210B03040900DBC861 /* Type.h */; };
DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE37252D0FE481AD00CF2CC2 /* Builtins.cpp */; };
DE38CD500D794D0100A273B6 /* CGObjCGNU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */; };
- DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */; };
DE3986F00CB8D4B300223765 /* IdentifierTable.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3986EF0CB8D4B300223765 /* IdentifierTable.h */; };
DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */; };
DE4121350D7F1C1C0080F80A /* SymbolManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */; };
@@ -218,13 +229,11 @@
DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */; };
DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704DD10D1668A4009C7762 /* HeaderMap.cpp */; };
DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; };
- DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; };
DE85CD810D8380B10070E26E /* TokenLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CD800D8380B10070E26E /* TokenLexer.cpp */; };
DE85CDA30D8383B20070E26E /* MacroArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDA20D8383B20070E26E /* MacroArgs.cpp */; };
DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */; };
DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAF0D838C390070E26E /* PPDirectives.cpp */; };
DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */; };
- DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE8823CA0ED0046600CBC30A /* APValue.cpp */; };
DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B120C05659200231DA4 /* ModuleBuilder.cpp */; };
DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */; };
DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B7C0C0A615100231DA4 /* CodeGenModule.h */; };
@@ -233,7 +242,6 @@
DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */; };
DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */; };
DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEED4A0A5AF89A0045101B /* NOTES.txt */; };
- DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */; };
DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */; };
DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */; };
DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; };
@@ -246,7 +254,6 @@
DECB77F70FA5850200F5FBC7 /* PCHWriterDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */; };
DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */; };
DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED626C80AE0C065001E80A4 /* TargetInfo.cpp */; };
- DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */; };
DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7310A524295003AD0FB /* Diagnostic.h */; };
DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7330A524295003AD0FB /* FileManager.h */; };
DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7350A524295003AD0FB /* SourceLocation.h */; };
@@ -269,7 +276,6 @@
DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7D70A524302003AD0FB /* README.txt */; };
DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D9170A52518C003AD0FB /* ScratchBuffer.h */; };
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
- DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */; };
DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6450F7B3B4E0035BD10 /* driver.cpp */; };
DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6480F7B3B830035BD10 /* Types.cpp */; };
DEDFE65B0F7B3B830035BD10 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64A0F7B3B830035BD10 /* Tools.cpp */; };
@@ -286,7 +292,6 @@
DEDFE6660F7B3B830035BD10 /* Tool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6570F7B3B830035BD10 /* Tool.cpp */; };
DEDFE6670F7B3B830035BD10 /* HostInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */; };
DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6590F7B3B830035BD10 /* Driver.cpp */; };
- DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFF8870F848CF80035BD10 /* TemplateName.cpp */; };
DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBBD430C19C5D200A9FE82 /* TODO.txt */; };
DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */; };
DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */; };
@@ -294,7 +299,6 @@
DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF165740F8FB3510098507F /* PCHReader.cpp */; };
DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */; };
DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */; };
- DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */; };
DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */; };
DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */; };
DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */; };
@@ -365,7 +369,15 @@
/* Begin PBXFileReference section */
035611470DA6A45C00D2EF2A /* DeclBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclBase.h; path = clang/AST/DeclBase.h; sourceTree = "<group>"; tabWidth = 2; };
03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclPrinter.cpp; path = lib/AST/DeclPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C407118226980092260D /* ASTImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTImporter.h; path = clang/AST/ASTImporter.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C408118226980092260D /* ASTVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTVector.h; path = clang/AST/ASTVector.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C409118226980092260D /* CharUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CharUnits.h; path = clang/AST/CharUnits.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40A118226980092260D /* DeclAccessPair.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclAccessPair.h; path = clang/AST/DeclAccessPair.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40B118226980092260D /* DeclFriend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclFriend.h; path = clang/AST/DeclFriend.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40C118226980092260D /* DependentDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DependentDiagnostic.h; path = clang/AST/DependentDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40D118226980092260D /* TemplateBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateBase.h; path = clang/AST/TemplateBase.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40E118226980092260D /* UnresolvedSet.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UnresolvedSet.h; path = clang/AST/UnresolvedSet.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UsuallyTinyPtrVector.h; path = clang/AST/UsuallyTinyPtrVector.h; sourceTree = "<group>"; tabWidth = 2; };
1A2193CB0F45EEB700C0713D /* ABIInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ABIInfo.h; path = lib/CodeGen/ABIInfo.h; sourceTree = "<group>"; tabWidth = 2; };
1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -386,12 +398,10 @@
1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Warnings.cpp; path = lib/Frontend/Warnings.cpp; sourceTree = "<group>"; };
1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = "<group>"; tabWidth = 2; };
1A31B27210ACE6DA009E0C8B /* GlobalDecl.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = GlobalDecl.h; path = lib/CodeGen/GlobalDecl.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGClass.cpp; path = lib/CodeGen/CGClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 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>"; };
+ 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; tabWidth = 2; };
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; };
@@ -422,19 +432,52 @@
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAccess.cpp; path = lib/Sema/SemaAccess.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = "<group>"; tabWidth = 2; };
1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A81AA18108144F40094E50B /* CGVtable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVtable.cpp; path = lib/CodeGen/CGVtable.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; };
+ 1A81AA18108144F40094E50B /* CGVTables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTables.cpp; path = lib/CodeGen/CGVTables.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A81AA5D108278A20094E50B /* CGVTables.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVTables.h; path = lib/CodeGen/CGVTables.h; sourceTree = "<group>"; tabWidth = 2; };
1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; };
1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; };
- 1A96785111486FDC00F24372 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayout.cpp; path = lib/AST/RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
1AA963AB10D8576800786C86 /* FullExpr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FullExpr.h; path = clang/AST/FullExpr.h; sourceTree = "<group>"; tabWidth = 2; };
- 1AA963C310D85A7300786C86 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = FullExpr.cpp; path = lib/AST/FullExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = "<group>"; };
+ 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = "<group>"; };
+ 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = "<group>"; };
+ 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = "<group>"; };
+ 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = "<group>"; };
+ 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = "<group>"; };
+ 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = "<group>"; };
+ 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = "<group>"; };
+ 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = "<group>"; };
+ 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = "<group>"; };
+ 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = "<group>"; };
+ 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = "<group>"; };
+ 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = "<group>"; };
+ 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = "<group>"; };
+ 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = "<group>"; };
+ 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = "<group>"; };
+ 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = "<group>"; };
+ 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = "<group>"; };
+ 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = "<group>"; };
+ 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = "<group>"; };
+ 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = "<group>"; };
+ 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = "<group>"; };
+ 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = "<group>"; };
+ 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = "<group>"; };
+ 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = "<group>"; };
+ 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordLayoutBuilder.h; sourceTree = "<group>"; };
+ 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = "<group>"; };
+ 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = "<group>"; };
+ 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = "<group>"; };
+ 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = "<group>"; };
+ 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = "<group>"; };
+ 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = "<group>"; };
+ 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = "<group>"; };
+ 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = "<group>"; };
+ 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = "<group>"; };
+ 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = "<group>"; };
+ 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = "<group>"; };
1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = "<group>"; };
1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = "<group>"; };
1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = "<group>"; };
@@ -444,12 +487,8 @@
1ACB57E11105820D0047B991 /* LangStandards.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LangStandards.cpp; path = lib/Frontend/LangStandards.cpp; sourceTree = "<group>"; };
1ACB57E21105820D0047B991 /* TypeXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeXML.cpp; path = lib/Frontend/TypeXML.cpp; sourceTree = "<group>"; };
1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDiagnosticsClient.cpp; path = lib/Frontend/VerifyDiagnosticsClient.cpp; sourceTree = "<group>"; };
- 1ADD795110A90C6100741BBA /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypePrinter.cpp; path = lib/AST/TypePrinter.cpp; sourceTree = "<group>"; };
- 1ADD795210A90C6100741BBA /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeLoc.cpp; path = lib/AST/TypeLoc.cpp; sourceTree = "<group>"; };
- 1ADD795310A90C6100741BBA /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateBase.cpp; path = lib/AST/TemplateBase.cpp; sourceTree = "<group>"; };
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; };
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; };
1AFDD8701161085D00AE030A /* ASTMerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTMerge.cpp; path = lib/Frontend/ASTMerge.cpp; sourceTree = "<group>"; };
1AFDD8711161085D00AE030A /* CodeGenAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenAction.cpp; path = lib/Frontend/CodeGenAction.cpp; sourceTree = "<group>"; };
@@ -460,7 +499,6 @@
352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlistDiagnostics.cpp; path = lib/Frontend/PlistDiagnostics.cpp; sourceTree = "<group>"; };
352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = lib/Frontend/TextDiagnosticBuffer.cpp; sourceTree = "<group>"; };
352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = lib/Frontend/TextDiagnosticPrinter.cpp; sourceTree = "<group>"; };
- 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = lib/AST/ExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
3527124F0DAFE54700C76352 /* IdentifierResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = IdentifierResolver.h; path = lib/Sema/IdentifierResolver.h; sourceTree = "<group>"; tabWidth = 2; };
352712500DAFE54700C76352 /* IdentifierResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = IdentifierResolver.cpp; path = lib/Sema/IdentifierResolver.cpp; sourceTree = "<group>"; tabWidth = 2; };
352C19DC0CA321C80045DB98 /* CFGRecStmtDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtDeclVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h; sourceTree = "<group>"; };
@@ -473,7 +511,6 @@
3537AA0C0ECD088F008F7CDC /* BlkExprDeclBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlkExprDeclBitVector.h; path = clang/Analysis/Support/BlkExprDeclBitVector.h; sourceTree = "<group>"; };
3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreprocessorLexer.cpp; sourceTree = "<group>"; };
3538FDB60ED24A2C005EC283 /* DeclarationName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclarationName.h; path = clang/AST/DeclarationName.h; sourceTree = "<group>"; tabWidth = 2; };
- 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclarationName.cpp; path = lib/AST/DeclarationName.cpp; sourceTree = "<group>"; };
353959D40EE5F88A00E82461 /* ParseTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseTemplate.cpp; path = lib/Parse/ParseTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; tabWidth = 2; };
35475B1F0E79973F0000BFE4 /* CGCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCall.cpp; path = lib/CodeGen/CGCall.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -492,7 +529,6 @@
35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SimpleConstraintManager.cpp; path = lib/Analysis/SimpleConstraintManager.cpp; sourceTree = "<group>"; };
35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleConstraintManager.h; path = lib/Analysis/SimpleConstraintManager.h; sourceTree = "<group>"; };
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiate.cpp; path = lib/Sema/SemaTemplateInstantiate.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 3557D1A80EB136B100C59739 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = InheritViz.cpp; path = lib/AST/InheritViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = lib/Sema/CXXFieldCollector.h; sourceTree = "<group>"; tabWidth = 2; };
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaOverload.cpp; path = lib/Sema/SemaOverload.cpp; sourceTree = "<group>"; tabWidth = 2; };
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaOverload.h; path = lib/Sema/SemaOverload.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -504,12 +540,10 @@
35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SourceLocation.cpp; sourceTree = "<group>"; tabWidth = 2; };
357EA27C0F2526F300439B60 /* SemaLookup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaLookup.cpp; path = lib/Sema/SemaLookup.cpp; sourceTree = "<group>"; tabWidth = 2; };
35847BE30CC7DB9000C40FFF /* StmtIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtIterator.h; path = clang/AST/StmtIterator.h; sourceTree = "<group>"; tabWidth = 2; };
- 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtIterator.cpp; path = lib/AST/StmtIterator.cpp; sourceTree = "<group>"; tabWidth = 2; };
35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckDeadStores.cpp; path = lib/Analysis/CheckDeadStores.cpp; sourceTree = "<group>"; };
35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngineInternalChecks.cpp; path = lib/Analysis/GRExprEngineInternalChecks.cpp; sourceTree = "<group>"; };
358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicConstraintManager.cpp; path = lib/Analysis/BasicConstraintManager.cpp; sourceTree = "<group>"; };
358D23090E8BEB850003DDCC /* DeclGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclGroup.h; path = clang/AST/DeclGroup.h; sourceTree = "<group>"; tabWidth = 2; };
- 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclGroup.cpp; path = lib/AST/DeclGroup.cpp; sourceTree = "<group>"; tabWidth = 2; };
358F514F0E529A87007F2102 /* GRState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRState.h; path = clang/Analysis/PathSensitive/GRState.h; sourceTree = "<group>"; };
358F51510E529AA4007F2102 /* GRState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRState.cpp; path = lib/Analysis/GRState.cpp; sourceTree = "<group>"; };
3591853E0EFB1088000039AF /* SemaTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplate.cpp; path = lib/Sema/SemaTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -528,10 +562,8 @@
35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathDiagnostic.cpp; path = lib/Analysis/PathDiagnostic.cpp; sourceTree = "<group>"; };
35B820740ECB811A0020BEC0 /* PreprocessorLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreprocessorLexer.h; sourceTree = "<group>"; };
35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckNSError.cpp; path = lib/Analysis/CheckNSError.cpp; sourceTree = "<group>"; };
- 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumer.cpp; path = lib/AST/ASTConsumer.cpp; sourceTree = "<group>"; tabWidth = 2; };
35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTConsumer.h; path = clang/AST/ASTConsumer.h; sourceTree = "<group>"; tabWidth = 2; };
35CEA05A0DF9E82700A41296 /* ExprObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprObjC.h; path = clang/AST/ExprObjC.h; sourceTree = "<group>"; tabWidth = 2; };
- 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtViz.cpp; path = lib/AST/StmtViz.cpp; sourceTree = "<group>"; tabWidth = 2; };
35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtGraphTraits.h; path = clang/AST/StmtGraphTraits.h; sourceTree = "<group>"; tabWidth = 2; };
35D1DDD10CA9C6D50096E967 /* DataflowSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowSolver.h; path = clang/Analysis/FlowSensitive/DataflowSolver.h; sourceTree = "<group>"; };
35D1DDD20CA9C6D50096E967 /* DataflowValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowValues.h; path = clang/Analysis/FlowSensitive/DataflowValues.h; sourceTree = "<group>"; };
@@ -543,8 +575,6 @@
35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = "<group>"; };
35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = "<group>"; tabWidth = 2; };
35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = "<group>"; tabWidth = 2; };
- 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclCXX.cpp; path = lib/AST/DeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParentMap.cpp; path = lib/AST/ParentMap.cpp; sourceTree = "<group>"; tabWidth = 2; };
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclCXX.cpp; path = lib/Sema/SemaDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRTransferFuncs.cpp; path = lib/Analysis/GRTransferFuncs.cpp; sourceTree = "<group>"; };
35F1ACE60E66166C001F4532 /* ConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConstraintManager.h; path = clang/Analysis/PathSensitive/ConstraintManager.h; sourceTree = "<group>"; };
@@ -555,7 +585,6 @@
35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicObjCFoundationChecks.cpp; path = lib/Analysis/BasicObjCFoundationChecks.cpp; sourceTree = "<group>"; };
35F9B1550D1C6B2E00DDFDAE /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/Analyses/LiveVariables.h; sourceTree = "<group>"; };
35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UninitializedValues.h; path = clang/Analysis/Analyses/UninitializedValues.h; sourceTree = "<group>"; };
- 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclBase.cpp; path = lib/AST/DeclBase.cpp; sourceTree = "<group>"; tabWidth = 2; };
72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLRewrite.cpp; path = lib/Rewrite/HTMLRewrite.cpp; sourceTree = "<group>"; };
7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; sourceTree = "<group>"; };
84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -565,13 +594,13 @@
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>"; };
- 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>"; };
- 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = "<group>"; };
- 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = "<group>"; };
- 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = "<group>"; };
- 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = "<group>"; };
+ 904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = "<group>"; };
9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; };
9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = "<group>"; };
@@ -580,9 +609,9 @@
906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = "<group>"; };
906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = "<group>"; };
90F9EFA9104ABDED00D09A15 /* c-index-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "c-index-test.c"; path = "tools/c-index-test/c-index-test.c"; sourceTree = "<group>"; };
- 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; };
- 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; };
- 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = "<group>"; };
+ 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; tabWidth = 2; };
+ 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
+ 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = "<group>"; tabWidth = 2; };
90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = "<group>"; };
90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = "<group>"; };
90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = "<group>"; };
@@ -640,9 +669,7 @@
DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = lib/Parse/Parser.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE06E8130A8FF9330050E87E /* Action.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Parse/Action.h; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
DE0FCA620A95859D00248FD5 /* Expr.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Expr.h; path = clang/AST/Expr.h; sourceTree = "<group>"; tabWidth = 2; };
- DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = lib/AST/Expr.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE1263C20EF2341900F56D2B /* Ownership.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Ownership.h; path = clang/Parse/Ownership.h; sourceTree = "<group>"; tabWidth = 2; };
- DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = lib/AST/ASTContext.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = lib/Parse/DeclSpec.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE17336F0B068DC60080B521 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Parse/DeclSpec.h; sourceTree = "<group>"; tabWidth = 2; };
DE1F22020A7D852A00FBF588 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Parser.h; path = clang/Parse/Parser.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -653,7 +680,6 @@
DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = "<group>"; };
DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = "<group>"; };
DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = "<group>"; };
- DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = lib/AST/Stmt.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3452800AEF1B1800DBC861 /* Stmt.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Stmt.h; path = clang/AST/Stmt.h; sourceTree = "<group>"; tabWidth = 2; };
DE345C190AFC658B00DBC861 /* StmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtVisitor.h; path = clang/AST/StmtVisitor.h; sourceTree = "<group>"; tabWidth = 2; };
DE345F210AFD347900DBC861 /* StmtNodes.def */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = text; name = StmtNodes.def; path = clang/AST/StmtNodes.def; sourceTree = "<group>"; tabWidth = 2; };
@@ -663,7 +689,6 @@
DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = lib/Parse/ParseDecl.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = lib/Parse/ParseExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = lib/Parse/MinimalAction.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = lib/AST/StmtPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3464210B03040900DBC861 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Type.h; path = clang/AST/Type.h; sourceTree = "<group>"; tabWidth = 2; };
DE37251C0FE4818000CF2CC2 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Builtins.h; sourceTree = "<group>"; };
DE37252A0FE4818F00CF2CC2 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Builtins.def; sourceTree = "<group>"; };
@@ -673,7 +698,6 @@
DE3725330FE4827200CF2CC2 /* BuiltinsPPC.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BuiltinsPPC.def; sourceTree = "<group>"; };
DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGObjCRuntime.h; path = lib/CodeGen/CGObjCRuntime.h; sourceTree = "<group>"; tabWidth = 2; };
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCGNU.cpp; path = lib/CodeGen/CGObjCGNU.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclObjC.cpp; path = lib/AST/DeclObjC.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = "<group>"; tabWidth = 2; };
DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -717,7 +741,6 @@
DE704BD10D1647E7009C7762 /* HeaderMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeaderMap.h; sourceTree = "<group>"; };
DE704DD10D1668A4009C7762 /* HeaderMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderMap.cpp; sourceTree = "<group>"; };
DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = "<group>"; tabWidth = 2; };
- DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = lib/AST/Type.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE85CD800D8380B10070E26E /* TokenLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenLexer.cpp; sourceTree = "<group>"; };
DE85CD840D8380F20070E26E /* TokenLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenLexer.h; sourceTree = "<group>"; };
DE85CD9E0D8382DD0070E26E /* MacroArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroArgs.h; sourceTree = "<group>"; };
@@ -726,7 +749,6 @@
DE85CDAF0D838C390070E26E /* PPDirectives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPDirectives.cpp; sourceTree = "<group>"; };
DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPLexerChange.cpp; sourceTree = "<group>"; };
DE8822350EC80C0A00CBC30A /* CGBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGBuilder.h; path = lib/CodeGen/CGBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
- DE8823CA0ED0046600CBC30A /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = APValue.cpp; path = lib/AST/APValue.cpp; sourceTree = "<group>"; };
DE8823DE0ED0B78600CBC30A /* PTHLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHLexer.h; sourceTree = "<group>"; };
DE8824530ED1243E00CBC30A /* OperatorKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OperatorKinds.h; sourceTree = "<group>"; };
DE8824560ED1244600CBC30A /* OperatorKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OperatorKinds.def; sourceTree = "<group>"; };
@@ -744,7 +766,6 @@
DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = "<group>"; };
DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = "<group>"; };
DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
- DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; };
DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = "<group>"; };
DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = "<group>"; };
DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -755,15 +776,13 @@
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = "<group>"; tabWidth = 2; };
DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitPreprocessor.h; path = clang/Frontend/InitPreprocessor.h; sourceTree = "<group>"; };
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>"; };
+ DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = "<group>"; tabWidth = 2; };
+ DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = "<group>"; tabWidth = 2; };
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>"; };
- DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessSpecifier.h; path = clang/Parse/AccessSpecifier.h; sourceTree = "<group>"; };
DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = "<group>"; tabWidth = 2; };
- DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = lib/AST/Decl.cpp; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
DED7D7310A524295003AD0FB /* Diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = Diagnostic.h; sourceTree = "<group>"; tabWidth = 2; };
DED7D7330A524295003AD0FB /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = "<group>"; tabWidth = 2; };
DED7D7350A524295003AD0FB /* SourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SourceLocation.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -787,8 +806,7 @@
DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = "<group>"; };
DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = "<group>"; };
DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = "<group>"; tabWidth = 2; };
- DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = "<group>"; };
- DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NestedNameSpecifier.cpp; path = lib/AST/NestedNameSpecifier.cpp; sourceTree = "<group>"; };
+ DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = "<group>"; tabWidth = 2; };
DEDFE6450F7B3B4E0035BD10 /* driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = driver.cpp; path = tools/driver/driver.cpp; sourceTree = "<group>"; };
DEDFE6480F7B3B830035BD10 /* Types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Types.cpp; path = lib/Driver/Types.cpp; sourceTree = "<group>"; };
DEDFE6490F7B3B830035BD10 /* Tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = lib/Driver/Tools.h; sourceTree = "<group>"; };
@@ -808,8 +826,7 @@
DEDFE6570F7B3B830035BD10 /* Tool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tool.cpp; path = lib/Driver/Tool.cpp; sourceTree = "<group>"; };
DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HostInfo.cpp; path = lib/Driver/HostInfo.cpp; sourceTree = "<group>"; };
DEDFE6590F7B3B830035BD10 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = lib/Driver/Driver.cpp; sourceTree = "<group>"; };
- DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = "<group>"; };
- DEDFF8870F848CF80035BD10 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateName.cpp; path = lib/AST/TemplateName.cpp; sourceTree = "<group>"; };
+ DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = "<group>"; tabWidth = 2; };
DEDFFF070F959EE60035BD10 /* Diagnostic.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Diagnostic.td; sourceTree = "<group>"; };
DEDFFF530F9704580035BD10 /* DiagnosticGroups.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticGroups.td; sourceTree = "<group>"; };
DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = "<group>"; };
@@ -847,10 +864,9 @@
DEF168620F9549250098507F /* FixItRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FixItRewriter.h; path = clang/Frontend/FixItRewriter.h; sourceTree = "<group>"; };
DEF169220F9645960098507F /* FrontendDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendDiagnostic.h; path = clang/Frontend/FrontendDiagnostic.h; sourceTree = "<group>"; };
DEF1692C0F9645BF0098507F /* AnalysisDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisDiagnostic.h; path = clang/Analysis/AnalysisDiagnostic.h; sourceTree = "<group>"; };
- DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = "<group>"; };
- DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = "<group>"; };
+ DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = "<group>"; tabWidth = 2; };
+ DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = "<group>"; tabWidth = 2; };
DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = "<group>"; };
- DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = lib/AST/StmtDumper.cpp; sourceTree = "<group>"; tabWidth = 2; };
DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = lib/CodeGen/CGExprAgg.cpp; sourceTree = "<group>"; tabWidth = 2; };
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = lib/Sema/SemaChecking.cpp; sourceTree = "<group>"; tabWidth = 2; };
DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Rewriter.h; path = clang/Rewrite/Rewriter.h; sourceTree = "<group>"; };
@@ -1363,8 +1379,8 @@
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */,
35475B230E7997680000BFE4 /* CGValue.h */,
- 1A81AA18108144F40094E50B /* CGVtable.cpp */,
- 1A81AA5D108278A20094E50B /* CGVtable.h */,
+ 1A81AA18108144F40094E50B /* CGVTables.cpp */,
+ 1A81AA5D108278A20094E50B /* CGVTables.h */,
1A97825A1108BA18002B98FC /* CGVTT.cpp */,
DE928B800C0A615B00231DA4 /* CodeGenFunction.h */,
DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */,
@@ -1393,6 +1409,15 @@
DEC8D98B0A9433BC00353FCA /* AST */ = {
isa = PBXGroup;
children = (
+ 1A15C407118226980092260D /* ASTImporter.h */,
+ 1A15C408118226980092260D /* ASTVector.h */,
+ 1A15C409118226980092260D /* CharUnits.h */,
+ 1A15C40A118226980092260D /* DeclAccessPair.h */,
+ 1A15C40B118226980092260D /* DeclFriend.h */,
+ 1A15C40C118226980092260D /* DependentDiagnostic.h */,
+ 1A15C40D118226980092260D /* TemplateBase.h */,
+ 1A15C40E118226980092260D /* UnresolvedSet.h */,
+ 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */,
904753791096376F00CBDDDD /* CXXInheritance.h */,
9047537A1096376F00CBDDDD /* Redeclarable.h */,
9047537B1096376F00CBDDDD /* TypeLoc.h */,
@@ -1400,7 +1425,6 @@
9047537D1096376F00CBDDDD /* TypeLocNodes.def */,
9047537E1096376F00CBDDDD /* TypeLocVisitor.h */,
9047537F1096376F00CBDDDD /* TypeVisitor.h */,
- DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */,
DE613EF30E0E148D00B05B79 /* APValue.h */,
DEC8D9A30A94346E00353FCA /* AST.h */,
35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */,
@@ -1445,41 +1469,46 @@
DEC8D9920A9433F400353FCA /* AST */ = {
isa = PBXGroup;
children = (
- DE8823CA0ED0046600CBC30A /* APValue.cpp */,
- 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */,
- DE1732FF0B068B700080B521 /* ASTContext.cpp */,
- 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */,
- 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */,
- DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */,
- 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */,
- 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */,
- 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */,
- 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */,
- DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */,
- DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */,
- DE0FCB330A9C21F100248FD5 /* Expr.cpp */,
- 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */,
- 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */,
- 1AA963C310D85A7300786C86 /* FullExpr.cpp */,
- 3557D1A80EB136B100C59739 /* InheritViz.cpp */,
- DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */,
- 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */,
- 1A96785111486FDC00F24372 /* RecordLayout.cpp */,
- 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */,
- 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */,
- DE3452400AEF1A2D00DBC861 /* Stmt.cpp */,
- DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */,
- 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */,
- DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */,
- 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */,
- 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */,
- 1ADD795310A90C6100741BBA /* TemplateBase.cpp */,
- DEDFF8870F848CF80035BD10 /* TemplateName.cpp */,
- DE75EDF00B06880E0020CF81 /* Type.cpp */,
- 1ADD795210A90C6100741BBA /* TypeLoc.cpp */,
- 1ADD795110A90C6100741BBA /* TypePrinter.cpp */,
+ 1ABD23B11182449800A48E65 /* APValue.cpp */,
+ 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */,
+ 1ABD23B31182449800A48E65 /* ASTContext.cpp */,
+ 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */,
+ 1ABD23B51182449800A48E65 /* ASTImporter.cpp */,
+ 1ABD23B61182449800A48E65 /* AttrImpl.cpp */,
+ 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */,
+ 1ABD23B81182449800A48E65 /* Decl.cpp */,
+ 1ABD23B91182449800A48E65 /* DeclarationName.cpp */,
+ 1ABD23BA1182449800A48E65 /* DeclBase.cpp */,
+ 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */,
+ 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */,
+ 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */,
+ 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */,
+ 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */,
+ 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */,
+ 1ABD23C11182449800A48E65 /* Expr.cpp */,
+ 1ABD23C21182449800A48E65 /* ExprConstant.cpp */,
+ 1ABD23C31182449800A48E65 /* ExprCXX.cpp */,
+ 1ABD23C41182449800A48E65 /* FullExpr.cpp */,
+ 1ABD23C51182449800A48E65 /* InheritViz.cpp */,
+ 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */,
+ 1ABD23C71182449800A48E65 /* ParentMap.cpp */,
+ 1ABD23C81182449800A48E65 /* RecordLayout.cpp */,
+ 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */,
+ 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */,
+ 1ABD23CB1182449800A48E65 /* Stmt.cpp */,
+ 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */,
+ 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */,
+ 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */,
+ 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */,
+ 1ABD23D01182449800A48E65 /* StmtViz.cpp */,
+ 1ABD23D11182449800A48E65 /* TemplateBase.cpp */,
+ 1ABD23D21182449800A48E65 /* TemplateName.cpp */,
+ 1ABD23D31182449800A48E65 /* Type.cpp */,
+ 1ABD23D41182449800A48E65 /* TypeLoc.cpp */,
+ 1ABD23D51182449800A48E65 /* TypePrinter.cpp */,
);
name = AST;
+ path = lib/AST;
sourceTree = "<group>";
};
DED7D72E0A524295003AD0FB /* include */ = {
@@ -1791,20 +1820,14 @@
DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */,
DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */,
DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */,
- DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */,
DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */,
- DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */,
DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */,
- DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */,
DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */,
DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */,
DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */,
DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */,
DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */,
DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */,
- DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */,
- DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */,
- DE1733000B068B700080B521 /* ASTContext.cpp in Sources */,
DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */,
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */,
DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */,
@@ -1823,24 +1846,19 @@
DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */,
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */,
DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */,
- DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */,
DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */,
DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */,
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */,
DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */,
1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */,
DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */,
- 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
DEF7D9F90C9C8B1D0001F598 /* Rewriter.cpp in Sources */,
- 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */,
DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */,
- 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */,
35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */,
DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */,
DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */,
- 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */,
DE47999C0D2EBE1A00706D2D /* SemaExprObjC.cpp in Sources */,
03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */,
1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */,
@@ -1859,7 +1877,6 @@
DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */,
DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */,
DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */,
- DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */,
72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */,
35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */,
35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */,
@@ -1871,12 +1888,8 @@
35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */,
35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */,
3599299B0DE2425300A8A33E /* SemaInit.cpp in Sources */,
- 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */,
- 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */,
- 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */,
3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */,
DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */,
- 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */,
3595AFB80E1C8D62004CDF09 /* CheckObjCDealloc.cpp in Sources */,
3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */,
3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */,
@@ -1891,7 +1904,6 @@
358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */,
35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */,
35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */,
- 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */,
355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */,
3551068C0E9A8546006A4E44 /* ParsePragma.cpp in Sources */,
3551068D0E9A8546006A4E44 /* ParseTentative.cpp in Sources */,
@@ -1899,17 +1911,13 @@
35A057E20EAE2D950069249F /* RegionStore.cpp in Sources */,
35A057E30EAE2D950069249F /* SVals.cpp in Sources */,
35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */,
- 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */,
35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */,
35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */,
35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */,
3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */,
- DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */,
- 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */,
353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */,
3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */,
357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */,
- DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */,
1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */,
DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */,
1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */,
@@ -1922,7 +1930,6 @@
35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */,
35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */,
35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */,
- DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */,
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */,
DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */,
DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */,
@@ -1942,7 +1949,6 @@
DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */,
1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */,
906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */,
- DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */,
DEF165710F8FB34D0098507F /* PCHWriter.cpp in Sources */,
DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */,
DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */,
@@ -1969,11 +1975,8 @@
1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */,
1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */,
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */,
- 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */,
DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */,
- 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */,
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */,
- 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */,
90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */,
90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */,
90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */,
@@ -1993,16 +1996,11 @@
1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */,
1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */,
1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */,
- 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */,
1A6C01F7108128710072DEE4 /* CGRTTI.cpp in Sources */,
- 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */,
+ 1A81AA19108144F40094E50B /* CGVTables.cpp in Sources */,
1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */,
- 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */,
- 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */,
- 1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */,
1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */,
E16B523510D30B2400430AC9 /* cc1_main.cpp in Sources */,
- 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */,
1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */,
1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */,
1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */,
@@ -2019,7 +2017,6 @@
1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */,
1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */,
1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */,
- 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */,
BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */,
BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */,
BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */,
@@ -2027,6 +2024,42 @@
BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */,
1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */,
1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */,
+ 1ABD23D61182449800A48E65 /* APValue.cpp in Sources */,
+ 1ABD23D71182449800A48E65 /* ASTConsumer.cpp in Sources */,
+ 1ABD23D81182449800A48E65 /* ASTContext.cpp in Sources */,
+ 1ABD23D91182449800A48E65 /* ASTDiagnostic.cpp in Sources */,
+ 1ABD23DA1182449800A48E65 /* ASTImporter.cpp in Sources */,
+ 1ABD23DB1182449800A48E65 /* AttrImpl.cpp in Sources */,
+ 1ABD23DC1182449800A48E65 /* CXXInheritance.cpp in Sources */,
+ 1ABD23DD1182449800A48E65 /* Decl.cpp in Sources */,
+ 1ABD23DE1182449800A48E65 /* DeclarationName.cpp in Sources */,
+ 1ABD23DF1182449800A48E65 /* DeclBase.cpp in Sources */,
+ 1ABD23E01182449800A48E65 /* DeclCXX.cpp in Sources */,
+ 1ABD23E11182449800A48E65 /* DeclFriend.cpp in Sources */,
+ 1ABD23E21182449800A48E65 /* DeclGroup.cpp in Sources */,
+ 1ABD23E31182449800A48E65 /* DeclObjC.cpp in Sources */,
+ 1ABD23E41182449800A48E65 /* DeclPrinter.cpp in Sources */,
+ 1ABD23E51182449800A48E65 /* DeclTemplate.cpp in Sources */,
+ 1ABD23E61182449800A48E65 /* Expr.cpp in Sources */,
+ 1ABD23E71182449800A48E65 /* ExprConstant.cpp in Sources */,
+ 1ABD23E81182449800A48E65 /* ExprCXX.cpp in Sources */,
+ 1ABD23E91182449800A48E65 /* FullExpr.cpp in Sources */,
+ 1ABD23EA1182449800A48E65 /* InheritViz.cpp in Sources */,
+ 1ABD23EB1182449800A48E65 /* NestedNameSpecifier.cpp in Sources */,
+ 1ABD23EC1182449800A48E65 /* ParentMap.cpp in Sources */,
+ 1ABD23ED1182449800A48E65 /* RecordLayout.cpp in Sources */,
+ 1ABD23EE1182449800A48E65 /* RecordLayoutBuilder.cpp in Sources */,
+ 1ABD23EF1182449800A48E65 /* Stmt.cpp in Sources */,
+ 1ABD23F01182449800A48E65 /* StmtDumper.cpp in Sources */,
+ 1ABD23F11182449800A48E65 /* StmtIterator.cpp in Sources */,
+ 1ABD23F21182449800A48E65 /* StmtPrinter.cpp in Sources */,
+ 1ABD23F31182449800A48E65 /* StmtProfile.cpp in Sources */,
+ 1ABD23F41182449800A48E65 /* StmtViz.cpp in Sources */,
+ 1ABD23F51182449800A48E65 /* TemplateBase.cpp in Sources */,
+ 1ABD23F61182449800A48E65 /* TemplateName.cpp in Sources */,
+ 1ABD23F71182449800A48E65 /* Type.cpp in Sources */,
+ 1ABD23F81182449800A48E65 /* TypeLoc.cpp in Sources */,
+ 1ABD23F91182449800A48E65 /* TypePrinter.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt
index 6fb75da40490..dd1203605333 100644
--- a/docs/Block-ABI-Apple.txt
+++ b/docs/Block-ABI-Apple.txt
@@ -31,10 +31,11 @@ THE SOFTWARE.
2008/10/30 - add __weak support
2010/3/16 - rev for stret return, signature field
+2010/4/6 - improved wording
This document describes the Apple ABI implementation specification of Blocks.
-The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. Proposals have been made to enhance the blocks compiler and runtime, and these changes would form a new ABI called post-10.6.ABI if these changes were ever shipped in a product, which is purely speculative.
+The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. As of 2010/3/16, the following describes the ABI contract with the runtime and the compiler, and, as necessary, will be referred to as ABI.2010.3.16.
Since the Apple ABI references symbols from other elements of the system, any attempt to use this ABI on systems prior to SnowLeopard is undefined.
@@ -54,13 +55,13 @@ struct Block_literal_1 {
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
- // required post 10.6.ABI
+ // required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};
-The following flags bits are in use thusly for a possible post.10.6.ABI:
+The following flags bits are in use thusly for a possible ABI.2010.3.16:
enum {
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
@@ -75,8 +76,8 @@ In 10.6.ABI the (1<<29) was unconditionally set and ignored by the runtime - it
switch (flags & (3<<29)) {
case (0<<29): <unused> , error
case (1<<29): 10.6.ABI, no signature field available
- case (2<<29): post-10.6.ABI, regular calling convention, presence of signature field
- case (3<<29): post-10.6.ABI, stret calling convention, presence of signature field,
+ case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field
+ case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
}
The following discussions are presented as 10.6.ABI otherwise.
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index 5d75eaa45390..daec6b019415 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -145,13 +145,13 @@ diagnostic :).</p>
pieces, this section describes them and talks about best practices when adding
a new diagnostic.</p>
-<!-- ============================ -->
-<h4>The DiagnosticKinds.def file</h4>
-<!-- ============================ -->
+<!-- ============================== -->
+<h4>The Diagnostic*Kinds.def files</h4>
+<!-- ============================== -->
-<p>Diagnostics are created by adding an entry to the <tt><a
-href="http://llvm.org/svn/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def"
->DiagnosticKinds.def</a></tt> file. This file encodes the unique ID of the
+<p>Diagnostics are created by adding an entry to one of the <tt>
+clang/Basic/Diagnostic*Kinds.def</tt> files, depending on what library will
+be using it. This file encodes the unique ID of the
diagnostic (as an enum, the first argument), the severity of the diagnostic
(second argument) and the English translation + format string.</p>
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index fe364ef9c00a..838b65f27b81 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -199,7 +199,44 @@ is used in the file argument.</p>
<h2 id="builtinmacros">Builtin Macros</h2>
<!-- ======================================================================= -->
-<p>__BASE_FILE__, __INCLUDE_LEVEL__, __TIMESTAMP__, __COUNTER__</p>
+<dl>
+ <dt><code>__BASE_FILE__</code></dt>
+ <dd>Defined to a string that contains the name of the main input
+ file passed to Clang.</dd>
+
+ <dt><code>__COUNTER__</code></dt>
+ <dd>Defined to an integer value that starts at zero and is
+ incremented each time the <code>__COUNTER__</code> macro is
+ expanded.</dd>
+
+ <dt><code>__INCLUDE_LEVEL__</code></dt>
+ <dd>Defined to an integral value that is the include depth of the
+ file currently being translated. For the main file, this value is
+ zero.</dd>
+
+ <dt><code>__TIMESTAMP__</code></dt>
+ <dd>Defined to the date and time of the last modification of the
+ current source file.</dd>
+
+ <dt><code>__clang__</code></dt>
+ <dd>Defined when compiling with Clang</dd>
+
+ <dt><code>__clang_major__</code></dt>
+ <dd>Defined to the major version number of Clang (e.g., the 2 in
+ 2.0.1).</dd>
+
+ <dt><code>__clang_minor__</code></dt>
+ <dd>Defined to the minor version number of Clang (e.g., the 0 in
+ 2.0.1).</dd>
+
+ <dt><code>__clang_patchlevel__</code></dt>
+ <dd>Defined to the patch level of Clang (e.g., the 1 in 2.0.1).</dd>
+
+ <dt><code>__clang_version__</code></dt>
+ <dd>Defined to a string that captures the Clang version, including
+ the Subversion tag or revision number, e.g., "1.5 (trunk
+ 102332)".</dd>
+</dl>
<!-- ======================================================================= -->
<h2 id="vectors">Vectors and Extended Vectors</h2>
@@ -271,9 +308,9 @@ attribute parsing with C++0x's square bracket notation is enabled.
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
deleted function definitions (with <tt>= delete</tt>) is enabled.
-<h3 id="cxx_concepts">C++ TR <tt>concepts</tt></h3>
+<h3 id="cxx_concepts">C++ TR concepts</h3>
-<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_concepts)</tt> to determine if support for
concepts is enabled. clang does not currently implement this feature.
<h3 id="cxx_lambdas">C++0x lambdas</h3>
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index e7ea133ce91a..7d7f2631ab5e 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -189,6 +189,12 @@ introduces the language selection and other high level options like -c, -g, etc.
<p><b>-pedantic-errors</b>: Error on language extensions.</p>
<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
+<p><b>-ferror-limit=123</b>: Stop emitting diagnostics after 123 errors have
+ been produced. The default is 20, and the error limit can be disabled with
+ -ferror-limit=0.</p>
+
+<p><b>-ftemplate-backtrace-limit=123</b>: Only emit up to 123 template instantiation notes within the template instantiation backtrace for a single warning or error. The default is 10, and the limit can be disabled with -ftemplate-backtrace-limit=0.</p>
+
<!-- ================================================= -->
<h4 id="cl_diag_formatting">Formatting of Diagnostics</h4>
<!-- ================================================= -->
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index 4eaa1dddc5e4..86239548d340 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -107,8 +107,10 @@ int main(int argc, const char **argv, char * const *envp) {
// Initialize a compiler invocation object from the clang (-cc1) arguments.
const driver::ArgStringList &CCArgs = Cmd->getArguments();
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
- (const char**) CCArgs.data()+CCArgs.size(),
+ CompilerInvocation::CreateFromArgs(*CI,
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) +
+ CCArgs.size(),
Diags);
// Show the invocation, with -v.
@@ -126,7 +128,7 @@ int main(int argc, const char **argv, char * const *envp) {
Clang.setInvocation(CI.take());
// Create the compilers actual diagnostics engine.
- Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data());
+ Clang.createDiagnostics(int(CCArgs.size()),const_cast<char**>(CCArgs.data()));
if (!Clang.hasDiagnostics())
return 1;
diff --git a/include/Makefile b/include/Makefile
index 47daabc7fa69..f686d6a64606 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -1,4 +1,4 @@
LEVEL = ../../..
-DIRS := clang
+DIRS := clang clang-c
include $(LEVEL)/Makefile.common
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 6120c4863fd7..1bf5a4688a2c 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -609,7 +609,9 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
*
* \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.
+ * those files. The contents and name of these files (as specified by
+ * CXUnsavedFile) are copied when necessary, so the client only needs to
+ * guarantee their validity until the call to this function returns.
*
* \param diag_callback callback function that will receive any diagnostics
* emitted while processing this source file. If NULL, diagnostics will be
@@ -698,7 +700,11 @@ enum CXCursorKind {
CXCursor_ObjCCategoryImplDecl = 19,
/** \brief A typedef */
CXCursor_TypedefDecl = 20,
- CXCursor_LastDecl = 20,
+
+ /** \brief A C++ class method. */
+ CXCursor_CXXMethod = 21,
+
+ CXCursor_LastDecl = 21,
/* References */
CXCursor_FirstRef = 40, /* Decl references */
@@ -763,7 +769,11 @@ enum CXCursorKind {
/** \brief An expression that sends a message to an Objective-C
object or class. */
CXCursor_ObjCMessageExpr = 104,
- CXCursor_LastExpr = 104,
+
+ /** \brief An expression that represents a block literal. */
+ CXCursor_BlockExpr = 105,
+
+ CXCursor_LastExpr = 105,
/* Statements */
CXCursor_FirstStmt = 200,
@@ -930,11 +940,26 @@ enum CXLinkageKind {
};
/**
- * \brief Determine the linkage of the entity referred to be a given cursor.
+ * \brief Determine the linkage of the entity referred to by a given cursor.
*/
CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor);
/**
+ * \brief Describe the "language" of the entity referred to by a cursor.
+ */
+CINDEX_LINKAGE enum CXLanguageKind {
+ CXLanguage_Invalid = 0,
+ CXLanguage_C,
+ CXLanguage_ObjC,
+ CXLanguage_CPlusPlus
+};
+
+/**
+ * \brief Determine the "language" of the entity referred to by a given cursor.
+ */
+CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor);
+
+/**
* @}
*/
@@ -1697,7 +1722,9 @@ typedef struct {
*
* \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.
+ * those files. The contents and name of these files (as specified by
+ * CXUnsavedFile) are copied when necessary, so the client only needs to
+ * guarantee their validity until the call to this function returns.
*
* \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
diff --git a/include/clang-c/Makefile b/include/clang-c/Makefile
new file mode 100644
index 000000000000..5e3522f79137
--- /dev/null
+++ b/include/clang-c/Makefile
@@ -0,0 +1,31 @@
+LEVEL = ../../../..
+DIRS :=
+
+include $(LEVEL)/Makefile.common
+
+install-local::
+ $(Echo) Installing Clang C API include files
+ $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
+ $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang-c" ; then \
+ cd $(PROJ_SRC_ROOT)/tools/clang/include && \
+ for hdr in `find clang-c -type f '!' '(' -name '*~' \
+ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \
+ -o -name 'Makefile' -o -name '*.td' ')' -print \
+ | grep -v CVS | grep -v .svn | grep -v .dir` ; do \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+ $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang-c" ; then \
+ cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
+ for hdr in `find clang-c -type f '!' '(' -name 'Makefile' ')' -print \
+ | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+endif
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 9d4bff893f02..5effa9057a4e 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -122,13 +122,17 @@ public:
return const_cast<APValue*>(this)->getFloat();
}
- APValue &getVectorElt(unsigned i) const {
+ APValue &getVectorElt(unsigned i) {
assert(isVector() && "Invalid accessor");
return ((Vec*)(char*)Data)->Elts[i];
}
+ const APValue &getVectorElt(unsigned i) const {
+ assert(isVector() && "Invalid accessor");
+ return ((const Vec*)(const char*)Data)->Elts[i];
+ }
unsigned getVectorLength() const {
assert(isVector() && "Invalid accessor");
- return ((Vec*)(void *)Data)->NumElts;
+ return ((const Vec*)(const void *)Data)->NumElts;
}
APSInt &getComplexIntReal() {
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index c41857ec0200..f8a8f179ae58 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -25,6 +25,7 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
+#include "clang/AST/UsuallyTinyPtrVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/OwningPtr.h"
@@ -34,6 +35,7 @@
namespace llvm {
struct fltSemantics;
+ class raw_ostream;
}
namespace clang {
@@ -70,28 +72,6 @@ namespace clang {
namespace Builtin { class Context; }
-/// \brief A vector of C++ member functions that is optimized for
-/// storing a single method.
-class CXXMethodVector {
- /// \brief Storage for the vector.
- ///
- /// When the low bit is zero, this is a const CXXMethodDecl *. When the
- /// low bit is one, this is a std::vector<const CXXMethodDecl *> *.
- mutable uintptr_t Storage;
-
- typedef std::vector<const CXXMethodDecl *> vector_type;
-
-public:
- CXXMethodVector() : Storage(0) { }
-
- typedef const CXXMethodDecl **iterator;
- iterator begin() const;
- iterator end() const;
-
- void push_back(const CXXMethodDecl *Method);
- void Destroy();
-};
-
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
class ASTContext {
@@ -164,6 +144,8 @@ class ASTContext {
QualType ObjCConstantStringType;
RecordDecl *CFConstantStringTypeDecl;
+ RecordDecl *NSConstantStringTypeDecl;
+
RecordDecl *ObjCFastEnumerationStateTypeDecl;
/// \brief The type for the C FILE type.
@@ -250,6 +232,7 @@ class ASTContext {
/// Since most C++ member functions aren't virtual and therefore
/// don't override anything, we store the overridden functions in
/// this map on the side rather than within the CXXMethodDecl structure.
+ typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
TranslationUnitDecl *TUDecl;
@@ -617,11 +600,13 @@ public:
QualType getTemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon = QualType());
+ QualType Canon = QualType(),
+ bool IsCurrentInstantiation = false);
QualType getTemplateSpecializationType(TemplateName T,
const TemplateArgumentListInfo &Args,
- QualType Canon = QualType());
+ QualType Canon = QualType(),
+ bool IsCurrentInstantiation = false);
TypeSourceInfo *
getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
@@ -688,6 +673,19 @@ public:
// constant CFStrings.
QualType getCFConstantStringType();
+ // getNSConstantStringType - Return the C structure type used to represent
+ // constant NSStrings.
+ QualType getNSConstantStringType();
+ /// Get the structure type used to representation NSStrings, or NULL
+ /// if it hasn't yet been built.
+ QualType getRawNSConstantStringType() {
+ if (NSConstantStringTypeDecl)
+ return getTagDeclType(NSConstantStringTypeDecl);
+ return QualType();
+ }
+ void setNSConstantStringType(QualType T);
+
+
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() {
@@ -937,6 +935,8 @@ public:
/// layout of the specified Objective-C interface.
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D);
+ void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS);
+
/// getASTObjCImplementationLayout - Get or compute information about
/// the layout of the specified Objective-C implementation. This may
/// differ from the interface if synthesized ivars are present.
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
new file mode 100644
index 000000000000..217dfade525f
--- /dev/null
+++ b/include/clang/AST/ASTVector.h
@@ -0,0 +1,397 @@
+//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides ASTVector, a vector ADT whose contents are
+// allocated using the allocator associated with an ASTContext..
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
+// We can refactor this core logic into something common.
+
+#ifndef LLVM_CLANG_AST_VECTOR
+#define LLVM_CLANG_AST_VECTOR
+
+#include "llvm/Support/type_traits.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include <algorithm>
+#include <memory>
+#include <cstring>
+
+#ifdef _MSC_VER
+namespace std {
+#if _MSC_VER <= 1310
+ // Work around flawed VC++ implementation of std::uninitialized_copy. Define
+ // additional overloads so that elements with pointer types are recognized as
+ // scalars and not objects, causing bizarre type conversion errors.
+ template<class T1, class T2>
+ inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) {
+ _Scalar_ptr_iterator_tag _Cat;
+ return _Cat;
+ }
+
+ template<class T1, class T2>
+ inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) {
+ _Scalar_ptr_iterator_tag _Cat;
+ return _Cat;
+ }
+#else
+ // FIXME: It is not clear if the problem is fixed in VS 2005. What is clear
+ // is that the above hack won't work if it wasn't fixed.
+#endif
+}
+#endif
+
+namespace clang {
+
+template<typename T>
+class ASTVector {
+ T *Begin, *End, *Capacity;
+
+ void setEnd(T *P) { this->End = P; }
+
+public:
+ // Default ctor - Initialize to empty.
+ explicit ASTVector(ASTContext &C, unsigned N = 0)
+ : Begin(NULL), End(NULL), Capacity(NULL) {
+ reserve(C, N);
+ }
+
+ ~ASTVector() {
+ if (llvm::is_class<T>::value) {
+ // Destroy the constructed elements in the vector.
+ destroy_range(Begin, End);
+ }
+ }
+
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+
+ // forward iterator creation methods.
+ iterator begin() { return Begin; }
+ const_iterator begin() const { return Begin; }
+ iterator end() { return End; }
+ const_iterator end() const { return End; }
+
+ // reverse iterator creation methods.
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
+
+ bool empty() const { return Begin == End; }
+ size_type size() const { return End-Begin; }
+
+ reference operator[](unsigned idx) {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+ const_reference operator[](unsigned idx) const {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+
+ reference front() {
+ return begin()[0];
+ }
+ const_reference front() const {
+ return begin()[0];
+ }
+
+ reference back() {
+ return end()[-1];
+ }
+ const_reference back() const {
+ return end()[-1];
+ }
+
+ void pop_back() {
+ --End;
+ End->~T();
+ }
+
+ T pop_back_val() {
+ T Result = back();
+ pop_back();
+ return Result;
+ }
+
+ void clear() {
+ if (llvm::is_class<T>::value) {
+ destroy_range(Begin, End);
+ }
+ End = Begin;
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ pointer data() {
+ return pointer(Begin);
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ const_pointer data() const {
+ return const_pointer(Begin);
+ }
+
+ void push_back(const_reference Elt, ASTContext &C) {
+ if (End < Capacity) {
+ Retry:
+ new (End) T(Elt);
+ ++End;
+ return;
+ }
+ grow(C);
+ goto Retry;
+ }
+
+ void reserve(ASTContext &C, unsigned N) {
+ if (unsigned(Capacity-Begin) < N)
+ grow(C, N);
+ }
+
+ /// capacity - Return the total number of elements in the currently allocated
+ /// buffer.
+ size_t capacity() const { return Capacity - Begin; }
+
+ /// append - Add the specified range to the end of the SmallVector.
+ ///
+ template<typename in_iter>
+ void append(ASTContext &C, in_iter in_start, in_iter in_end) {
+ size_type NumInputs = std::distance(in_start, in_end);
+
+ if (NumInputs == 0)
+ return;
+
+ // Grow allocated space if needed.
+ if (NumInputs > size_type(this->capacity_ptr()-this->end()))
+ this->grow(C, this->size()+NumInputs);
+
+ // Copy the new elements over.
+ // TODO: NEED To compile time dispatch on whether in_iter is a random access
+ // iterator to use the fast uninitialized_copy.
+ std::uninitialized_copy(in_start, in_end, this->end());
+ this->setEnd(this->end() + NumInputs);
+ }
+
+ /// append - Add the specified range to the end of the SmallVector.
+ ///
+ void append(ASTContext &C, size_type NumInputs, const T &Elt) {
+ // Grow allocated space if needed.
+ if (NumInputs > size_type(this->capacity_ptr()-this->end()))
+ this->grow(C, this->size()+NumInputs);
+
+ // Copy the new elements over.
+ std::uninitialized_fill_n(this->end(), NumInputs, Elt);
+ this->setEnd(this->end() + NumInputs);
+ }
+
+ /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
+ /// starting with "Dest", constructing elements into it as needed.
+ template<typename It1, typename It2>
+ static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
+ std::uninitialized_copy(I, E, Dest);
+ }
+
+ iterator insert(ASTContext &C, iterator I, const T &Elt) {
+ if (I == this->end()) { // Important special case for empty vector.
+ push_back(Elt);
+ return this->end()-1;
+ }
+
+ if (this->EndX < this->CapacityX) {
+ Retry:
+ new (this->end()) T(this->back());
+ this->setEnd(this->end()+1);
+ // Push everything else over.
+ std::copy_backward(I, this->end()-1, this->end());
+ *I = Elt;
+ return I;
+ }
+ size_t EltNo = I-this->begin();
+ this->grow(C);
+ I = this->begin()+EltNo;
+ goto Retry;
+ }
+
+ iterator insert(ASTContext &C, iterator I, size_type NumToInsert,
+ const T &Elt) {
+ if (I == this->end()) { // Important special case for empty vector.
+ append(C, NumToInsert, Elt);
+ return this->end()-1;
+ }
+
+ // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+ size_t InsertElt = I - this->begin();
+
+ // Ensure there is enough space.
+ reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
+
+ // Uninvalidate the iterator.
+ I = this->begin()+InsertElt;
+
+ // If there are more elements between the insertion point and the end of the
+ // range than there are being inserted, we can use a simple approach to
+ // insertion. Since we already reserved space, we know that this won't
+ // reallocate the vector.
+ if (size_t(this->end()-I) >= NumToInsert) {
+ T *OldEnd = this->end();
+ append(C, this->end()-NumToInsert, this->end());
+
+ // Copy the existing elements that get replaced.
+ std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
+
+ std::fill_n(I, NumToInsert, Elt);
+ return I;
+ }
+
+ // Otherwise, we're inserting more elements than exist already, and we're
+ // not inserting at the end.
+
+ // Copy over the elements that we're about to overwrite.
+ T *OldEnd = this->end();
+ this->setEnd(this->end() + NumToInsert);
+ size_t NumOverwritten = OldEnd-I;
+ this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
+
+ // Replace the overwritten part.
+ std::fill_n(I, NumOverwritten, Elt);
+
+ // Insert the non-overwritten middle part.
+ std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
+ return I;
+ }
+
+ template<typename ItTy>
+ iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) {
+ if (I == this->end()) { // Important special case for empty vector.
+ append(C, From, To);
+ return this->end()-1;
+ }
+
+ size_t NumToInsert = std::distance(From, To);
+ // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+ size_t InsertElt = I - this->begin();
+
+ // Ensure there is enough space.
+ reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
+
+ // Uninvalidate the iterator.
+ I = this->begin()+InsertElt;
+
+ // If there are more elements between the insertion point and the end of the
+ // range than there are being inserted, we can use a simple approach to
+ // insertion. Since we already reserved space, we know that this won't
+ // reallocate the vector.
+ if (size_t(this->end()-I) >= NumToInsert) {
+ T *OldEnd = this->end();
+ append(C, this->end()-NumToInsert, this->end());
+
+ // Copy the existing elements that get replaced.
+ std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
+
+ std::copy(From, To, I);
+ return I;
+ }
+
+ // Otherwise, we're inserting more elements than exist already, and we're
+ // not inserting at the end.
+
+ // Copy over the elements that we're about to overwrite.
+ T *OldEnd = this->end();
+ this->setEnd(this->end() + NumToInsert);
+ size_t NumOverwritten = OldEnd-I;
+ this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
+
+ // Replace the overwritten part.
+ for (; NumOverwritten > 0; --NumOverwritten) {
+ *I = *From;
+ ++I; ++From;
+ }
+
+ // Insert the non-overwritten middle part.
+ this->uninitialized_copy(From, To, OldEnd);
+ return I;
+ }
+
+ void resize(ASTContext &C, unsigned N, const T &NV) {
+ if (N < this->size()) {
+ this->destroy_range(this->begin()+N, this->end());
+ this->setEnd(this->begin()+N);
+ } else if (N > this->size()) {
+ if (this->capacity() < N)
+ this->grow(C, N);
+ construct_range(this->end(), this->begin()+N, NV);
+ this->setEnd(this->begin()+N);
+ }
+ }
+
+private:
+ /// grow - double the size of the allocated memory, guaranteeing space for at
+ /// least one more element or MinSize if specified.
+ void grow(ASTContext &C, size_type MinSize = 1);
+
+ void construct_range(T *S, T *E, const T &Elt) {
+ for (; S != E; ++S)
+ new (S) T(Elt);
+ }
+
+ void destroy_range(T *S, T *E) {
+ while (S != E) {
+ --E;
+ E->~T();
+ }
+ }
+
+protected:
+ iterator capacity_ptr() { return (iterator)this->Capacity; }
+};
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T>
+void ASTVector<T>::grow(ASTContext &C, size_t MinSize) {
+ size_t CurCapacity = Capacity-Begin;
+ size_t CurSize = size();
+ size_t NewCapacity = 2*CurCapacity;
+ if (NewCapacity < MinSize)
+ NewCapacity = MinSize;
+
+ // Allocate the memory from the ASTContext.
+ T *NewElts = new (C) T[NewCapacity];
+
+ // Copy the elements over.
+ if (llvm::is_class<T>::value) {
+ std::uninitialized_copy(Begin, End, NewElts);
+ // Destroy the original elements.
+ destroy_range(Begin, End);
+ }
+ else {
+ // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
+ memcpy(NewElts, Begin, CurSize * sizeof(T));
+ }
+
+ C.Deallocate(Begin);
+ Begin = NewElts;
+ End = NewElts+CurSize;
+ Capacity = Begin+NewCapacity;
+}
+
+} // end: clang namespace
+#endif
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index b2a87f617063..93dcad751221 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -263,6 +263,7 @@ public:
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 2cdb98351394..834c9a0c563f 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -31,7 +31,9 @@ class StringLiteral;
class TemplateArgumentList;
class MemberSpecializationInfo;
class FunctionTemplateSpecializationInfo;
+class DependentFunctionTemplateSpecializationInfo;
class TypeLoc;
+class UnresolvedSetImpl;
/// \brief A container of type source information.
///
@@ -196,6 +198,10 @@ public:
return DC->isRecord();
}
+ /// \brief Given that this declaration is a C++ class member,
+ /// determine whether it's an instance member of its class.
+ bool isCXXInstanceMember() const;
+
/// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const;
@@ -211,6 +217,12 @@ public:
static bool classofKind(Kind K) { return K >= NamedFirst && K <= NamedLast; }
};
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const NamedDecl *ND) {
+ ND->getDeclName().printName(OS);
+ return OS;
+}
+
/// NamespaceDecl - Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext {
SourceLocation LBracLoc, RBracLoc;
@@ -478,6 +490,7 @@ protected:
private:
// FIXME: This can be packed into the bitfields in Decl.
unsigned SClass : 3;
+ unsigned SClassAsWritten : 3;
bool ThreadSpecified : 1;
bool HasCXXDirectInit : 1;
@@ -485,14 +498,20 @@ private:
/// condition, e.g., if (int x = foo()) { ... }.
bool DeclaredInCondition : 1;
+ /// \brief Whether this variable is the exception variable in a C++ catch
+ /// or an Objective-C @catch statement.
+ bool ExceptionVar : 1;
+
friend class StmtIteratorBase;
protected:
VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, StorageClass SC)
+ QualType T, TypeSourceInfo *TInfo, StorageClass SC,
+ StorageClass SCAsWritten)
: DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(),
ThreadSpecified(false), HasCXXDirectInit(false),
- DeclaredInCondition(false) {
+ DeclaredInCondition(false), ExceptionVar(false) {
SClass = SC;
+ SClassAsWritten = SCAsWritten;
}
typedef Redeclarable<VarDecl> redeclarable_base;
@@ -509,7 +528,8 @@ public:
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, StorageClass S);
+ QualType T, TypeSourceInfo *TInfo, StorageClass S,
+ StorageClass SCAsWritten);
virtual void Destroy(ASTContext& C);
virtual ~VarDecl();
@@ -517,7 +537,11 @@ public:
virtual SourceRange getSourceRange() const;
StorageClass getStorageClass() const { return (StorageClass)SClass; }
+ StorageClass getStorageClassAsWritten() const {
+ return (StorageClass) SClassAsWritten;
+ }
void setStorageClass(StorageClass SC) { SClass = SC; }
+ void setStorageClassAsWritten(StorageClass SC) { SClassAsWritten = SC; }
void setThreadSpecified(bool T) { ThreadSpecified = T; }
bool isThreadSpecified() const {
@@ -536,6 +560,12 @@ public:
return getStorageClass() <= Register;
}
+ /// isStaticLocal - Returns true if a variable with function scope is a
+ /// static local variable.
+ bool isStaticLocal() const {
+ return getStorageClass() == Static && !isFileVarDecl();
+ }
+
/// hasExternStorage - Returns true if a variable has extern or
/// __private_extern__ storage.
bool hasExternalStorage() const {
@@ -815,6 +845,13 @@ public:
DeclaredInCondition = InCondition;
}
+ /// \brief Determine whether this variable is the exception variable in a
+ /// C++ catch statememt or an Objective-C @catch statement.
+ bool isExceptionVariable() const {
+ return ExceptionVar;
+ }
+ void setExceptionVariable(bool EV) { ExceptionVar = EV; }
+
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member
/// from which it was instantiated.
@@ -844,7 +881,7 @@ class ImplicitParamDecl : public VarDecl {
protected:
ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType Tw)
- : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, VarDecl::None) {}
+ : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, VarDecl::None, VarDecl::None) {}
public:
static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
@@ -866,9 +903,9 @@ class ParmVarDecl : public VarDecl {
protected:
ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg)
- : VarDecl(DK, DC, L, Id, T, TInfo, S),
- objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) {
+ StorageClass S, StorageClass SCAsWritten, Expr *DefArg)
+ : VarDecl(DK, DC, L, Id, T, TInfo, S, SCAsWritten),
+ objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) {
setDefaultArg(DefArg);
}
@@ -876,7 +913,8 @@ public:
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg);
+ StorageClass S, StorageClass SCAsWritten,
+ Expr *DefArg);
ObjCDeclQualifier getObjCDeclQualifier() const {
return ObjCDeclQualifier(objcDeclQualifier);
@@ -1002,6 +1040,7 @@ private:
// FIXME: This can be packed into the bitfields in Decl.
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
unsigned SClass : 2;
+ unsigned SClassAsWritten : 2;
bool IsInline : 1;
bool IsVirtualAsWritten : 1;
bool IsPure : 1;
@@ -1033,19 +1072,20 @@ private:
/// FunctionTemplateSpecializationInfo, which contains information about
/// the template being specialized and the template arguments involved in
/// that specialization.
- llvm::PointerUnion3<FunctionTemplateDecl *,
+ llvm::PointerUnion4<FunctionTemplateDecl *,
MemberSpecializationInfo *,
- FunctionTemplateSpecializationInfo *>
+ FunctionTemplateSpecializationInfo *,
+ DependentFunctionTemplateSpecializationInfo *>
TemplateOrSpecialization;
protected:
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, bool isInline)
+ StorageClass S, StorageClass SCAsWritten, bool isInline)
: DeclaratorDecl(DK, DC, L, N, T, TInfo),
DeclContext(DK),
ParamInfo(0), Body(),
- SClass(S), IsInline(isInline),
+ SClass(S), SClassAsWritten(SCAsWritten), IsInline(isInline),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
IsCopyAssignment(false),
@@ -1070,7 +1110,9 @@ public:
static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName N, QualType T,
TypeSourceInfo *TInfo,
- StorageClass S = None, bool isInline = false,
+ StorageClass S = None,
+ StorageClass SCAsWritten = None,
+ bool isInline = false,
bool hasWrittenPrototype = true);
virtual void getNameForDiagnostic(std::string &S,
@@ -1107,6 +1149,9 @@ public:
void setBody(Stmt *B);
void setLazyBody(uint64_t Offset) { Body = Offset; }
+ /// Whether this function is variadic.
+ bool isVariadic() const;
+
/// Whether this function is marked as virtual explicitly.
bool isVirtualAsWritten() const { return IsVirtualAsWritten; }
void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; }
@@ -1225,6 +1270,11 @@ public:
StorageClass getStorageClass() const { return StorageClass(SClass); }
void setStorageClass(StorageClass SC) { SClass = SC; }
+ StorageClass getStorageClassAsWritten() const {
+ return StorageClass(SClassAsWritten);
+ }
+ void setStorageClassAsWritten(StorageClass SC) { SClassAsWritten = SC; }
+
/// \brief Determine whether the "inline" keyword was specified for this
/// function.
bool isInlineSpecified() const { return IsInline; }
@@ -1361,6 +1411,18 @@ public:
void *InsertPos,
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
+ /// \brief Specifies that this function declaration is actually a
+ /// dependent function template specialization.
+ void setDependentTemplateSpecialization(ASTContext &Context,
+ const UnresolvedSetImpl &Templates,
+ const TemplateArgumentListInfo &TemplateArgs);
+
+ DependentFunctionTemplateSpecializationInfo *
+ getDependentSpecializationInfo() const {
+ return TemplateOrSpecialization.
+ dyn_cast<DependentFunctionTemplateSpecializationInfo*>();
+ }
+
/// \brief Determine what kind of template instantiation this function
/// represents.
TemplateSpecializationKind getTemplateSpecializationKind() const;
@@ -1961,7 +2023,7 @@ public:
///
class BlockDecl : public Decl, public DeclContext {
// FIXME: This can be packed into the bitfields in Decl.
- bool isVariadic : 1;
+ bool IsVariadic : 1;
/// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal
/// parameters of this function. This is null if a prototype or if there are
/// no formals.
@@ -1973,7 +2035,7 @@ class BlockDecl : public Decl, public DeclContext {
protected:
BlockDecl(DeclContext *DC, SourceLocation CaretLoc)
: Decl(Block, DC, CaretLoc), DeclContext(Block),
- isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {}
+ IsVariadic(false), ParamInfo(0), NumParams(0), Body(0) {}
virtual ~BlockDecl();
virtual void Destroy(ASTContext& C);
@@ -1983,8 +2045,8 @@ public:
SourceLocation getCaretLocation() const { return getLocation(); }
- bool IsVariadic() const { return isVariadic; }
- void setIsVariadic(bool value) { isVariadic = value; }
+ bool isVariadic() const { return IsVariadic; }
+ void setIsVariadic(bool value) { IsVariadic = value; }
CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; }
Stmt *getBody() const { return (Stmt*) Body; }
diff --git a/include/clang/AST/DeclAccessPair.h b/include/clang/AST/DeclAccessPair.h
new file mode 100644
index 000000000000..7ecd8f8bcd78
--- /dev/null
+++ b/include/clang/AST/DeclAccessPair.h
@@ -0,0 +1,72 @@
+//===--- DeclAccessPair.h - A decl bundled with its path access -*- 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 DeclAccessPair class, which provides an
+// efficient representation of a pair of a NamedDecl* and an
+// AccessSpecifier. Generally the access specifier gives the
+// natural access of a declaration when named in a class, as
+// defined in C++ [class.access.base]p1.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H
+#define LLVM_CLANG_AST_DECLACCESSPAIR_H
+
+#include "clang/Basic/Specifiers.h"
+
+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 DeclAccessPair is POD.
+namespace llvm {
+template<typename> struct isPodLike;
+template<> struct isPodLike<clang::DeclAccessPair> {
+ static const bool value = true;
+};
+}
+
+#endif
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index d5913e236c2c..a9b948eee546 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -76,26 +76,68 @@ public:
#include "clang/AST/DeclNodes.def"
};
- /// IdentifierNamespace - According to C99 6.2.3, there are four
- /// namespaces, labels, tags, members and ordinary
- /// identifiers. These are meant as bitmasks, so that searches in
- /// C++ can look into the "tag" namespace during ordinary lookup. We
- /// use additional namespaces for Objective-C entities. We also put
- /// C++ friend declarations (of previously-undeclared entities) in
- /// shadow namespaces, and 'using' declarations (as opposed to their
- /// implicit shadow declarations) can be found in their own
- /// namespace.
+ /// IdentifierNamespace - The different namespaces in which
+ /// declarations may appear. According to C99 6.2.3, there are
+ /// four namespaces, labels, tags, members and ordinary
+ /// identifiers. C++ describes lookup completely differently:
+ /// certain lookups merely "ignore" certain kinds of declarations,
+ /// usually based on whether the declaration is of a type, etc.
+ ///
+ /// These are meant as bitmasks, so that searches in
+ /// C++ can look into the "tag" namespace during ordinary lookup.
+ ///
+ /// Decl currently provides 16 bits of IDNS bits.
enum IdentifierNamespace {
- IDNS_Label = 0x1,
- IDNS_Tag = 0x2,
- IDNS_Member = 0x4,
- IDNS_Ordinary = 0x8,
- IDNS_ObjCProtocol = 0x10,
- IDNS_ObjCImplementation = 0x20,
- IDNS_ObjCCategoryName = 0x40,
- IDNS_OrdinaryFriend = 0x80,
- IDNS_TagFriend = 0x100,
- IDNS_Using = 0x200
+ /// Labels, declared with 'x:' and referenced with 'goto x'.
+ IDNS_Label = 0x0001,
+
+ /// Tags, declared with 'struct foo;' and referenced with
+ /// 'struct foo'. All tags are also types. This is what
+ /// elaborated-type-specifiers look for in C.
+ IDNS_Tag = 0x0002,
+
+ /// Types, declared with 'struct foo', typedefs, etc.
+ /// This is what elaborated-type-specifiers look for in C++,
+ /// but note that it's ill-formed to find a non-tag.
+ IDNS_Type = 0x0004,
+
+ /// Members, declared with object declarations within tag
+ /// definitions. In C, these can only be found by "qualified"
+ /// lookup in member expressions. In C++, they're found by
+ /// normal lookup.
+ IDNS_Member = 0x0008,
+
+ /// Namespaces, declared with 'namespace foo {}'.
+ /// Lookup for nested-name-specifiers find these.
+ IDNS_Namespace = 0x0010,
+
+ /// Ordinary names. In C, everything that's not a label, tag,
+ /// or member ends up here.
+ IDNS_Ordinary = 0x0020,
+
+ /// Objective C @protocol.
+ IDNS_ObjCProtocol = 0x0040,
+
+ /// This declaration is a friend function. A friend function
+ /// declaration is always in this namespace but may also be in
+ /// IDNS_Ordinary if it was previously declared.
+ IDNS_OrdinaryFriend = 0x0080,
+
+ /// This declaration is a friend class. A friend class
+ /// declaration is always in this namespace but may also be in
+ /// IDNS_Tag|IDNS_Type if it was previously declared.
+ IDNS_TagFriend = 0x0100,
+
+ /// This declaration is a using declaration. A using declaration
+ /// *introduces* a number of other declarations into the current
+ /// scope, and those declarations use the IDNS of their targets,
+ /// but the actual using declarations go in this namespace.
+ IDNS_Using = 0x0200,
+
+ /// This declaration is a C++ operator declared in a non-class
+ /// context. All such operators are also in IDNS_Ordinary.
+ /// C++ lexical operator lookup looks for these.
+ IDNS_NonMemberOperator = 0x0400
};
/// ObjCDeclQualifier - Qualifier used on types in method declarations
@@ -313,6 +355,13 @@ public:
}
static unsigned getIdentifierNamespaceForKind(Kind DK);
+ bool hasTagIdentifierNamespace() const {
+ return isTagIdentifierNamespace(getIdentifierNamespace());
+ }
+ static bool isTagIdentifierNamespace(unsigned NS) {
+ // TagDecls have Tag and Type set and may also have TagFriend.
+ return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type);
+ }
/// getLexicalDeclContext - The declaration context where this Decl was
/// lexically declared (LexicalDC). May be different from
@@ -455,14 +504,14 @@ public:
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
"namespace includes neither ordinary nor tag");
- assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
+ assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
"namespace includes other than ordinary or tag");
IdentifierNamespace = 0;
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
@@ -489,6 +538,14 @@ public:
FOK_Declared : FOK_Undeclared);
}
+ /// Specifies that this declaration is a C++ overloaded non-member.
+ void setNonMemberOperator() {
+ assert(getKind() == Function || getKind() == FunctionTemplate);
+ assert((IdentifierNamespace & IDNS_Ordinary) &&
+ "visible non-member operators should be in ordinary namespace");
+ IdentifierNamespace |= IDNS_NonMemberOperator;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *) { return true; }
static bool classofKind(Kind K) { return true; }
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 23769af46b36..aa649c811115 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -471,6 +471,11 @@ public:
friend_iterator friend_end() const;
void pushFriendDecl(FriendDecl *FD);
+ /// Determines whether this record has any friends.
+ bool hasFriends() const {
+ return data().FirstFriend != 0;
+ }
+
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
@@ -931,15 +936,16 @@ class CXXMethodDecl : public FunctionDecl {
protected:
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
- bool isStatic, bool isInline)
+ bool isStatic, StorageClass SCAsWritten, bool isInline)
: FunctionDecl(DK, RD, L, N, T, TInfo, (isStatic ? Static : None),
- isInline) {}
+ SCAsWritten, isInline) {}
public:
static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
bool isStatic = false,
+ StorageClass SCAsWritten = FunctionDecl::None,
bool isInline = false);
bool isStatic() const { return getStorageClass() == Static; }
@@ -960,6 +966,10 @@ public:
/// delete or delete[] operator with a particular signature.
bool isUsualDeallocationFunction() const;
+ /// \brief Determine whether this is a copy-assignment operator, regardless
+ /// of whether it was declared implicitly or explicitly.
+ bool isCopyAssignmentOperator() const;
+
const CXXMethodDecl *getCanonicalDecl() const {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
}
@@ -1052,6 +1062,10 @@ class CXXBaseOrMemberInitializer {
/// and AnonUnionMember holds field decl for au_i1.
FieldDecl *AnonUnionMember;
+ /// IsVirtual - If the initializer is a base initializer, this keeps track
+ /// of whether the base is virtual or not.
+ bool IsVirtual;
+
/// LParenLoc - Location of the left paren of the ctor-initializer.
SourceLocation LParenLoc;
@@ -1062,7 +1076,7 @@ public:
/// CXXBaseOrMemberInitializer - Creates a new base-class initializer.
explicit
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo,
+ TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L,
Expr *Init,
SourceLocation R);
@@ -1095,7 +1109,14 @@ public:
/// Otherwise, returns NULL.
const Type *getBaseClass() const;
Type *getBaseClass();
-
+
+ /// Returns whether the base is virtual or not.
+ bool isBaseVirtual() const {
+ assert(isBaseInitializer() && "Must call this on base initializer!");
+
+ return IsVirtual;
+ }
+
/// \brief Returns the declarator information for a base class initializer.
TypeSourceInfo *getBaseClassInfo() const {
return BaseOrMember.dyn_cast<TypeSourceInfo *>();
@@ -1171,7 +1192,8 @@ class CXXConstructorDecl : public CXXMethodDecl {
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
bool isExplicitSpecified, bool isInline,
bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, isInline),
+ : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false,
+ FunctionDecl::None, isInline),
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) {
setImplicit(isImplicitlyDeclared);
@@ -1199,7 +1221,7 @@ public:
/// defined. If false, then this constructor was defined by the
/// user. This operation can only be invoked if the constructor has
/// already been defined.
- bool isImplicitlyDefined(ASTContext &C) const {
+ bool isImplicitlyDefined() const {
assert(isThisDeclarationADefinition() &&
"Can only get the implicit-definition flag once the "
"constructor has been defined");
@@ -1314,7 +1336,8 @@ class CXXDestructorDecl : public CXXMethodDecl {
CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T,
bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*TInfo=*/0, false, isInline),
+ : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*TInfo=*/0, false,
+ FunctionDecl::None, isInline),
ImplicitlyDefined(false), OperatorDelete(0) {
setImplicit(isImplicitlyDeclared);
}
@@ -1370,7 +1393,8 @@ class CXXConversionDecl : public CXXMethodDecl {
CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L,
DeclarationName N, QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicitSpecified)
- : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, isInline),
+ : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false,
+ FunctionDecl::None, isInline),
IsExplicitSpecified(isExplicitSpecified) { }
public:
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 16cb491344bc..2a4b12ac2eaf 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -230,7 +230,7 @@ public:
// Tag declarations always go at the end of the list so that an
// iterator which points at the first tag will start a span of
// decls that only contains tags.
- if (D->getIdentifierNamespace() == Decl::IDNS_Tag)
+ if (D->hasTagIdentifierNamespace())
Vec.push_back(reinterpret_cast<uintptr_t>(D));
// Resolved using declarations go at the front of the list so that
@@ -251,7 +251,7 @@ public:
// tag declarations. But we can be clever about tag declarations
// because there can only ever be one in a scope.
} else if (reinterpret_cast<NamedDecl *>(Vec.back())
- ->getIdentifierNamespace() == Decl::IDNS_Tag) {
+ ->hasTagIdentifierNamespace()) {
uintptr_t TagD = Vec.back();
Vec.back() = reinterpret_cast<uintptr_t>(D);
Vec.push_back(TagD);
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 99ef738980cc..a20625da56b7 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -48,10 +48,6 @@ private:
// Location of the 'friend' specifier.
SourceLocation FriendLoc;
- // FIXME: Hack to keep track of whether this was a friend function
- // template specialization.
- bool WasSpecialization;
-
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
@@ -60,8 +56,7 @@ private:
: Decl(Decl::Friend, DC, L),
Friend(Friend),
NextFriend(0),
- FriendLoc(FriendL),
- WasSpecialization(false) {
+ FriendLoc(FriendL) {
}
public:
@@ -88,9 +83,6 @@ public:
return FriendLoc;
}
- bool wasSpecialization() const { return WasSpecialization; }
- void setSpecialization(bool WS) { WasSpecialization = WS; }
-
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def
index 082299c41f50..5b03ff8d9119 100644
--- a/include/clang/AST/DeclNodes.def
+++ b/include/clang/AST/DeclNodes.def
@@ -105,14 +105,14 @@ ABSTRACT_DECL(Named, Decl)
DECL(ImplicitParam, VarDecl)
DECL(ParmVar, VarDecl)
DECL(NonTypeTemplateParm, VarDecl)
- DECL(Template, NamedDecl)
+ ABSTRACT_DECL(Template, NamedDecl)
DECL(FunctionTemplate, TemplateDecl)
DECL(ClassTemplate, TemplateDecl)
DECL(TemplateTemplateParm, TemplateDecl)
DECL(Using, NamedDecl)
DECL(UsingShadow, NamedDecl)
DECL(ObjCMethod, NamedDecl)
- DECL(ObjCContainer, NamedDecl)
+ ABSTRACT_DECL(ObjCContainer, NamedDecl)
DECL(ObjCCategory, ObjCContainerDecl)
DECL(ObjCProtocol, ObjCContainerDecl)
DECL(ObjCInterface, ObjCContainerDecl)
@@ -143,7 +143,7 @@ LAST_DECL_CONTEXT(Block)
// Declaration ranges
DECL_RANGE(Named, Namespace, ObjCCompatibleAlias)
-DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation)
+DECL_RANGE(ObjCContainer, ObjCCategory, ObjCImplementation)
DECL_RANGE(Field, Field, ObjCAtDefsField)
DECL_RANGE(Type, Typedef, TemplateTypeParm)
DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
@@ -151,7 +151,7 @@ DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
DECL_RANGE(Declarator, Function, NonTypeTemplateParm)
DECL_RANGE(Function, Function, CXXConversion)
-DECL_RANGE(Template, Template, TemplateTemplateParm)
+DECL_RANGE(Template, FunctionTemplate, TemplateTemplateParm)
DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation)
LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm)
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 9b2b6096e81d..e34ec9ffcdf0 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -29,6 +29,7 @@ class ObjCProtocolDecl;
class ObjCCategoryDecl;
class ObjCPropertyDecl;
class ObjCPropertyImplDecl;
+class CXXBaseOrMemberInitializer;
class ObjCListBase {
void operator=(const ObjCListBase &); // DO NOT IMPLEMENT
@@ -136,6 +137,9 @@ private:
/// in, inout, etc.
unsigned objcDeclQualifier : 6;
+ // Number of args separated by ':' in a method declaration.
+ unsigned NumSelectorArgs;
+
// Result type of this method.
QualType MethodDeclType;
@@ -167,13 +171,15 @@ private:
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
- ImplementationControl impControl = None)
+ ImplementationControl impControl = None,
+ unsigned numSelectorArgs = 0)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod),
IsInstance(isInstance), IsVariadic(isVariadic),
IsSynthesized(isSynthesized),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
- MethodDeclType(T), ResultTInfo(ResultTInfo),
+ NumSelectorArgs(numSelectorArgs), MethodDeclType(T),
+ ResultTInfo(ResultTInfo),
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
virtual ~ObjCMethodDecl() {}
@@ -197,7 +203,8 @@ public:
bool isInstance = true,
bool isVariadic = false,
bool isSynthesized = false,
- ImplementationControl impControl = None);
+ ImplementationControl impControl = None,
+ unsigned numSelectorArgs = 0);
virtual ObjCMethodDecl *getCanonicalDecl();
const ObjCMethodDecl *getCanonicalDecl() const {
@@ -209,6 +216,11 @@ public:
}
void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; }
+ unsigned getNumSelectorArgs() const { return NumSelectorArgs; }
+ void setNumSelectorArgs(unsigned numSelectorArgs) {
+ NumSelectorArgs = numSelectorArgs;
+ }
+
// Location information, modeled after the Stmt API.
SourceLocation getLocStart() const { return getLocation(); }
SourceLocation getLocEnd() const { return EndLoc; }
@@ -235,9 +247,16 @@ public:
typedef ObjCList<ParmVarDecl>::iterator param_iterator;
param_iterator param_begin() const { return ParamInfo.begin(); }
param_iterator param_end() const { return ParamInfo.end(); }
+ // This method returns and of the parameters which are part of the selector
+ // name mangling requirements.
+ param_iterator sel_param_end() const {
+ return ParamInfo.begin() + NumSelectorArgs;
+ }
- void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num) {
+ void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num,
+ unsigned numSelectorArgs) {
ParamInfo.set(List, Num, C);
+ NumSelectorArgs = numSelectorArgs;
}
// Iterator access to parameter types.
@@ -1114,6 +1133,9 @@ public:
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const ObjCCategoryImplDecl *CID);
+
/// ObjCImplementationDecl - Represents a class definition - this is where
/// method definitions are specified. For example:
///
@@ -1131,18 +1153,54 @@ public:
class ObjCImplementationDecl : public ObjCImplDecl {
/// Implementation Class's super class.
ObjCInterfaceDecl *SuperClass;
-
+ /// Support for ivar initialization.
+ /// IvarInitializers - The arguments used to initialize the ivars
+ CXXBaseOrMemberInitializer **IvarInitializers;
+ unsigned NumIvarInitializers;
+
ObjCImplementationDecl(DeclContext *DC, SourceLocation L,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl)
: ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
- SuperClass(superDecl){}
+ SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0) {}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl);
-
+
+ /// init_iterator - Iterates through the ivar initializer list.
+ typedef CXXBaseOrMemberInitializer **init_iterator;
+
+ /// init_const_iterator - Iterates through the ivar initializer list.
+ typedef CXXBaseOrMemberInitializer * const * init_const_iterator;
+
+ /// init_begin() - Retrieve an iterator to the first initializer.
+ init_iterator init_begin() { return IvarInitializers; }
+ /// begin() - Retrieve an iterator to the first initializer.
+ init_const_iterator init_begin() const { return IvarInitializers; }
+
+ /// init_end() - Retrieve an iterator past the last initializer.
+ init_iterator init_end() {
+ return IvarInitializers + NumIvarInitializers;
+ }
+ /// end() - Retrieve an iterator past the last initializer.
+ init_const_iterator init_end() const {
+ return IvarInitializers + NumIvarInitializers;
+ }
+ /// getNumArgs - Number of ivars which must be initialized.
+ unsigned getNumIvarInitializers() const {
+ return NumIvarInitializers;
+ }
+
+ void setNumIvarInitializers(unsigned numNumIvarInitializers) {
+ NumIvarInitializers = numNumIvarInitializers;
+ }
+
+ void setIvarInitializers(ASTContext &C,
+ CXXBaseOrMemberInitializer ** initializers,
+ unsigned numInitializers);
+
/// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation.
IdentifierInfo *getIdentifier() const {
@@ -1199,6 +1257,9 @@ public:
static bool classofKind(Kind K) { return K == ObjCImplementation; }
};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const ObjCImplementationDecl *ID);
+
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
/// declared as @compatibility_alias alias class.
class ObjCCompatibleAliasDecl : public NamedDecl {
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 8d1a4caccb23..1ec38bacb51f 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -376,6 +376,81 @@ public:
PointOfInstantiation = POI;
}
};
+
+/// \brief Provides information about a dependent function-template
+/// specialization declaration. Since explicit function template
+/// specialization and instantiation declarations can only appear in
+/// namespace scope, and you can only specialize a member of a
+/// fully-specialized class, the only way to get one of these is in
+/// a friend declaration like the following:
+///
+/// template <class T> void foo(T);
+/// template <class T> class A {
+/// friend void foo<>(T);
+/// };
+class DependentFunctionTemplateSpecializationInfo {
+ union {
+ // Force sizeof to be a multiple of sizeof(void*) so that the
+ // trailing data is aligned.
+ void *Aligner;
+
+ struct {
+ /// The number of potential template candidates.
+ unsigned NumTemplates;
+
+ /// The number of template arguments.
+ unsigned NumArgs;
+ } d;
+ };
+
+ /// The locations of the left and right angle brackets.
+ SourceRange AngleLocs;
+
+ FunctionTemplateDecl * const *getTemplates() const {
+ return reinterpret_cast<FunctionTemplateDecl*const*>(this+1);
+ }
+
+ const TemplateArgumentLoc *getTemplateArgs() const {
+ return reinterpret_cast<const TemplateArgumentLoc*>(
+ &getTemplates()[getNumTemplates()]);
+ }
+
+public:
+ DependentFunctionTemplateSpecializationInfo(
+ const UnresolvedSetImpl &Templates,
+ const TemplateArgumentListInfo &TemplateArgs);
+
+ /// \brief Returns the number of function templates that this might
+ /// be a specialization of.
+ unsigned getNumTemplates() const {
+ return d.NumTemplates;
+ }
+
+ /// \brief Returns the i'th template candidate.
+ FunctionTemplateDecl *getTemplate(unsigned I) const {
+ assert(I < getNumTemplates() && "template index out of range");
+ return getTemplates()[I];
+ }
+
+ /// \brief Returns the number of explicit template arguments that were given.
+ unsigned getNumTemplateArgs() const {
+ return d.NumArgs;
+ }
+
+ /// \brief Returns the nth template argument.
+ const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
+ assert(I < getNumTemplateArgs() && "template arg index out of range");
+ return getTemplateArgs()[I];
+ }
+
+ SourceLocation getLAngleLoc() const {
+ return AngleLocs.getBegin();
+ }
+
+ SourceLocation getRAngleLoc() const {
+ return AngleLocs.getEnd();
+ }
+};
/// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl {
@@ -652,7 +727,8 @@ class NonTypeTemplateParmDecl
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo)
- : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, VarDecl::None),
+ : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, VarDecl::None,
+ VarDecl::None),
TemplateParmPosition(D, P), DefaultArgument(0)
{ }
@@ -935,6 +1011,11 @@ class ClassTemplatePartialSpecializationDecl
TemplateArgumentLoc *ArgsAsWritten;
unsigned NumArgsAsWritten;
+ /// \brief Sequence number indicating when this class template partial
+ /// specialization was added to the set of partial specializations for
+ /// its owning class template.
+ unsigned SequenceNumber;
+
/// \brief The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
@@ -950,13 +1031,15 @@ class ClassTemplatePartialSpecializationDecl
TemplateArgumentListBuilder &Builder,
TemplateArgumentLoc *ArgInfos,
unsigned NumArgInfos,
- ClassTemplatePartialSpecializationDecl *PrevDecl)
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
DC, L, SpecializedTemplate, Builder,
PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- NumArgsAsWritten(NumArgInfos), InstantiatedFromMember(0, false) { }
+ NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
+ InstantiatedFromMember(0, false) { }
public:
static ClassTemplatePartialSpecializationDecl *
@@ -966,7 +1049,8 @@ public:
TemplateArgumentListBuilder &Builder,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl);
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber);
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
@@ -983,6 +1067,10 @@ public:
return NumArgsAsWritten;
}
+ /// \brief Get the sequence number for this class template partial
+ /// specialization.
+ unsigned getSequenceNumber() const { return SequenceNumber; }
+
/// \brief Retrieve the member class template partial specialization from
/// which this particular class template partial specialization was
/// instantiated.
@@ -1046,6 +1134,15 @@ public:
"Only member templates can be member template specializations");
return First->InstantiatedFromMember.setInt(true);
}
+
+ /// Retrieves the injected specialization type for this partial
+ /// specialization. This is not the same as the type-decl-type for
+ /// this partial specialization, which is an InjectedClassNameType.
+ QualType getInjectedSpecializationType() const {
+ assert(getTypeForDecl() && "partial specialization has no type set!");
+ return cast<InjectedClassNameType>(getTypeForDecl())
+ ->getInjectedSpecializationType();
+ }
// FIXME: Add Profile support!
@@ -1141,6 +1238,10 @@ public:
return CommonPtr->PartialSpecializations;
}
+ /// \brief Retrieve the partial specializations as an ordered list.
+ void getPartialSpecializations(
+ llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
+
/// \brief Find a class template partial specialization with the given
/// type T.
///
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 6225069c602f..94017865d4c6 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -198,9 +198,12 @@ public:
/// callee in a call expression with dependent arguments.
bool isDependentName() const;
- /// getName - Retrieve the human-readable string for this name.
+ /// getNameAsString - Retrieve the human-readable string for this name.
std::string getAsString() const;
+ /// printName - Print the human-readable name to a stream.
+ void printName(llvm::raw_ostream &OS) const;
+
/// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in
/// this declaration name, or NULL if this declaration name isn't a
/// simple identifier.
@@ -331,13 +334,15 @@ public:
/// getCXXConstructorName - Returns the name of a C++ constructor
/// for the given Type.
DeclarationName getCXXConstructorName(CanQualType Ty) {
- return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty);
+ return getCXXSpecialName(DeclarationName::CXXConstructorName,
+ Ty.getUnqualifiedType());
}
/// getCXXDestructorName - Returns the name of a C++ destructor
/// for the given Type.
DeclarationName getCXXDestructorName(CanQualType Ty) {
- return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty);
+ return getCXXSpecialName(DeclarationName::CXXDestructorName,
+ Ty.getUnqualifiedType());
}
/// getCXXConversionFunctionName - Returns the name of a C++
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
index 1954a282e802..2bbe5020cb3a 100644
--- a/include/clang/AST/DependentDiagnostic.h
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/Type.h"
namespace clang {
@@ -42,6 +43,7 @@ public:
AccessSpecifier AS,
NamedDecl *TargetDecl,
CXXRecordDecl *NamingClass,
+ QualType BaseObjectType,
const PartialDiagnostic &PDiag) {
DependentDiagnostic *DD = Create(Context, Parent, PDiag);
DD->AccessData.Loc = Loc.getRawEncoding();
@@ -49,6 +51,7 @@ public:
DD->AccessData.Access = AS;
DD->AccessData.TargetDecl = TargetDecl;
DD->AccessData.NamingClass = NamingClass;
+ DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
return DD;
}
@@ -81,6 +84,11 @@ public:
return AccessData.NamingClass;
}
+ QualType getAccessBaseObjectType() const {
+ assert(getKind() == Access);
+ return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
+ }
+
const PartialDiagnostic &getDiagnostic() const {
return Diag;
}
@@ -107,6 +115,7 @@ private:
unsigned IsMember : 1;
NamedDecl *TargetDecl;
CXXRecordDecl *NamingClass;
+ void *BaseObjectType;
} AccessData;
};
};
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index a687ee5f01c8..2946e464a7cf 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -17,6 +17,9 @@
#include "clang/AST/APValue.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
+#include "clang/AST/DeclAccessPair.h"
+#include "clang/AST/ASTVector.h"
+#include "clang/AST/UsuallyTinyPtrVector.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
@@ -32,11 +35,15 @@ namespace clang {
class NamedDecl;
class ValueDecl;
class BlockDecl;
+ class CXXBaseSpecifier;
class CXXOperatorCallExpr;
class CXXMemberCallExpr;
class TemplateArgumentLoc;
class TemplateArgumentListInfo;
+/// \brief A simple array of base specifiers.
+typedef UsuallyTinyPtrVector<const CXXBaseSpecifier> CXXBaseSpecifierArray;
+
/// Expr - This represents one expression. Note that Expr's are subclasses of
/// Stmt. This allows an expression to be transparently used any place a Stmt
/// is required.
@@ -197,6 +204,12 @@ public:
/// \brief Returns whether this expression refers to a vector element.
bool refersToVectorElement() const;
+ /// isKnownToHaveBooleanValue - Return true if this is an integer expression
+ /// that is known to return 0 or 1. This happens for _Bool/bool expressions
+ /// but also int expressions which are produced by things like comparisons in
+ /// C.
+ bool isKnownToHaveBooleanValue() 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
@@ -210,7 +223,7 @@ public:
}
/// isConstantInitializer - Returns true if this expression is a constant
/// initializer, which can be emitted at compile-time.
- bool isConstantInitializer(ASTContext &Ctx) const;
+ bool isConstantInitializer(ASTContext &Ctx) const;
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult {
@@ -302,7 +315,7 @@ public:
/// its subexpression. If that subexpression is also a ParenExpr,
/// then this method recursively returns its subexpression, and so forth.
/// Otherwise, the method returns the current Expr.
- Expr* IgnoreParens();
+ Expr *IgnoreParens();
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
/// or CastExprs, returning their operand.
@@ -331,7 +344,7 @@ public:
/// temporary object.
const Expr *getTemporaryObject() const;
- const Expr* IgnoreParens() const {
+ const Expr *IgnoreParens() const {
return const_cast<Expr*>(this)->IgnoreParens();
}
const Expr *IgnoreParenCasts() const {
@@ -901,7 +914,7 @@ public:
///
/// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose
/// subexpression is a compound literal with the various MemberExpr and
-/// ArraySubscriptExpr's applied to it.
+/// ArraySubscriptExpr's applied to it. (This is only used in C)
///
class UnaryOperator : public Expr {
public:
@@ -990,6 +1003,205 @@ public:
virtual child_iterator child_end();
};
+/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form
+/// offsetof(record-type, member-designator). For example, given:
+/// @code
+/// struct S {
+/// float f;
+/// double d;
+/// };
+/// struct T {
+/// int i;
+/// struct S s[10];
+/// };
+/// @endcode
+/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d).
+
+class OffsetOfExpr : public Expr {
+public:
+ // __builtin_offsetof(type, identifier(.identifier|[expr])*)
+ class OffsetOfNode {
+ public:
+ /// \brief The kind of offsetof node we have.
+ enum Kind {
+ /// \brief An index into an array.
+ Array = 0x00,
+ /// \brief A field.
+ Field = 0x01,
+ /// \brief A field in a dependent type, known only by its name.
+ Identifier = 0x02,
+ /// \brief An implicit indirection through a C++ base class, when the
+ /// field found is in a base class.
+ Base = 0x03
+ };
+
+ private:
+ enum { MaskBits = 2, Mask = 0x03 };
+
+ /// \brief The source range that covers this part of the designator.
+ SourceRange Range;
+
+ /// \brief The data describing the designator, which comes in three
+ /// different forms, depending on the lower two bits.
+ /// - An unsigned index into the array of Expr*'s stored after this node
+ /// in memory, for [constant-expression] designators.
+ /// - A FieldDecl*, for references to a known field.
+ /// - An IdentifierInfo*, for references to a field with a given name
+ /// when the class type is dependent.
+ /// - A CXXBaseSpecifier*, for references that look at a field in a
+ /// base class.
+ uintptr_t Data;
+
+ public:
+ /// \brief Create an offsetof node that refers to an array element.
+ OffsetOfNode(SourceLocation LBracketLoc, unsigned Index,
+ SourceLocation RBracketLoc)
+ : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { }
+
+ /// \brief Create an offsetof node that refers to a field.
+ OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field,
+ SourceLocation NameLoc)
+ : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
+ Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) { }
+
+ /// \brief Create an offsetof node that refers to an identifier.
+ OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc)
+ : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
+ Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { }
+
+ /// \brief Create an offsetof node that refers into a C++ base class.
+ explicit OffsetOfNode(const CXXBaseSpecifier *Base)
+ : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
+
+ /// \brief Determine what kind of offsetof node this is.
+ Kind getKind() const {
+ return static_cast<Kind>(Data & Mask);
+ }
+
+ /// \brief For an array element node, returns the index into the array
+ /// of expressions.
+ unsigned getArrayExprIndex() const {
+ assert(getKind() == Array);
+ return Data >> 2;
+ }
+
+ /// \brief For a field offsetof node, returns the field.
+ FieldDecl *getField() const {
+ assert(getKind() == Field);
+ return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask);
+ }
+
+ /// \brief For a field or identifier offsetof node, returns the name of
+ /// the field.
+ IdentifierInfo *getFieldName() const;
+
+ /// \brief For a base class node, returns the base specifier.
+ CXXBaseSpecifier *getBase() const {
+ assert(getKind() == Base);
+ return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
+ }
+
+ /// \brief Retrieve the source range that covers this offsetof node.
+ ///
+ /// For an array element node, the source range contains the locations of
+ /// the square brackets. For a field or identifier node, the source range
+ /// contains the location of the period (if there is one) and the
+ /// identifier.
+ SourceRange getRange() const { return Range; }
+ };
+
+private:
+
+ SourceLocation OperatorLoc, RParenLoc;
+ // Base type;
+ TypeSourceInfo *TSInfo;
+ // Number of sub-components (i.e. instances of OffsetOfNode).
+ unsigned NumComps;
+ // Number of sub-expressions (i.e. array subscript expressions).
+ unsigned NumExprs;
+
+ OffsetOfExpr(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc);
+
+ explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
+ : Expr(OffsetOfExprClass, EmptyShell()),
+ TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}
+
+public:
+
+ static OffsetOfExpr *Create(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc);
+
+ static OffsetOfExpr *CreateEmpty(ASTContext &C,
+ unsigned NumComps, unsigned NumExprs);
+
+ /// getOperatorLoc - Return the location of the operator.
+ SourceLocation getOperatorLoc() const { return OperatorLoc; }
+ void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
+
+ /// \brief Return the location of the right parentheses.
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation R) { RParenLoc = R; }
+
+ TypeSourceInfo *getTypeSourceInfo() const {
+ return TSInfo;
+ }
+ void setTypeSourceInfo(TypeSourceInfo *tsi) {
+ TSInfo = tsi;
+ }
+
+ const OffsetOfNode &getComponent(unsigned Idx) {
+ assert(Idx < NumComps && "Subscript out of range");
+ return reinterpret_cast<OffsetOfNode *> (this + 1)[Idx];
+ }
+
+ void setComponent(unsigned Idx, OffsetOfNode ON) {
+ assert(Idx < NumComps && "Subscript out of range");
+ reinterpret_cast<OffsetOfNode *> (this + 1)[Idx] = ON;
+ }
+
+ unsigned getNumComponents() const {
+ return NumComps;
+ }
+
+ Expr* getIndexExpr(unsigned Idx) {
+ assert(Idx < NumExprs && "Subscript out of range");
+ return reinterpret_cast<Expr **>(
+ reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx];
+ }
+
+ void setIndexExpr(unsigned Idx, Expr* E) {
+ assert(Idx < NumComps && "Subscript out of range");
+ reinterpret_cast<Expr **>(
+ reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx] = E;
+ }
+
+ unsigned getNumExpressions() const {
+ return NumExprs;
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(OperatorLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OffsetOfExprClass;
+ }
+
+ static bool classof(const OffsetOfExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of
/// types and expressions.
class SizeOfAlignOfExpr : public Expr {
@@ -1274,7 +1486,7 @@ public:
class MemberExpr : public Expr {
/// Extra data stored in some member expressions.
struct MemberNameQualifier : public NameQualifier {
- NamedDecl *FoundDecl;
+ DeclAccessPair FoundDecl;
};
/// Base - the expression for the base pointer or structure references. In
@@ -1349,7 +1561,7 @@ public:
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, SourceRange qualrange,
- ValueDecl *memberdecl, NamedDecl *founddecl,
+ ValueDecl *memberdecl, DeclAccessPair founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty);
@@ -1365,9 +1577,10 @@ public:
void setMemberDecl(ValueDecl *D) { MemberDecl = D; }
/// \brief Retrieves the declaration found by lookup.
- NamedDecl *getFoundDecl() const {
+ DeclAccessPair getFoundDecl() const {
if (!HasQualifierOrFoundDecl)
- return getMemberDecl();
+ return DeclAccessPair::make(getMemberDecl(),
+ getMemberDecl()->getAccess());
return getMemberQualifier()->FoundDecl;
}
@@ -1636,8 +1849,53 @@ public:
private:
CastKind Kind;
Stmt *Op;
+
+ /// BasePath - For derived-to-base and base-to-derived casts, the base array
+ /// contains the inheritance path.
+ CXXBaseSpecifierArray BasePath;
+
+ void CheckBasePath() const {
+#ifndef NDEBUG
+ switch (getCastKind()) {
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_BaseToDerived:
+ case CK_BaseToDerivedMemberPointer:
+ assert(!BasePath.empty() && "Cast kind should have a base path!");
+ break;
+
+ // These should not have an inheritance path.
+ case CK_Unknown:
+ case CK_BitCast:
+ case CK_NoOp:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToMemberPointer:
+ case CK_UserDefinedConversion:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralCast:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingCast:
+ case CK_MemberPointerToBoolean:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ assert(BasePath.empty() && "Cast kind should not have a base path!");
+ break;
+ }
+#endif
+ }
+
protected:
- CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op) :
+ CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op,
+ CXXBaseSpecifierArray BasePath) :
Expr(SC, ty,
// Cast expressions are type-dependent if the type is
// dependent (C++ [temp.dep.expr]p3).
@@ -1645,12 +1903,16 @@ protected:
// Cast expressions are value-dependent if the type is
// dependent or if the subexpression is value-dependent.
ty->isDependentType() || (op && op->isValueDependent())),
- Kind(kind), Op(op) {}
+ Kind(kind), Op(op), BasePath(BasePath) {
+ CheckBasePath();
+ }
/// \brief Construct an empty cast.
CastExpr(StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty) { }
+ virtual void DoDestroy(ASTContext &C);
+
public:
CastKind getCastKind() const { return Kind; }
void setCastKind(CastKind K) { Kind = K; }
@@ -1667,10 +1929,12 @@ public:
const Expr *getSubExprAsWritten() const {
return const_cast<CastExpr *>(this)->getSubExprAsWritten();
}
-
+
+ const CXXBaseSpecifierArray& getBasePath() const { return BasePath; }
+
static bool classof(const Stmt *T) {
StmtClass SC = T->getStmtClass();
- if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
+ if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass)
return true;
if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass)
@@ -1706,14 +1970,15 @@ class ImplicitCastExpr : public CastExpr {
bool LvalueCast;
public:
- ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, bool Lvalue) :
- CastExpr(ImplicitCastExprClass, ty, kind, op), LvalueCast(Lvalue) { }
+ ImplicitCastExpr(QualType ty, CastKind kind, Expr *op,
+ CXXBaseSpecifierArray BasePath, bool Lvalue)
+ : CastExpr(ImplicitCastExprClass, ty, kind, op, BasePath),
+ LvalueCast(Lvalue) { }
/// \brief Construct an empty implicit cast.
explicit ImplicitCastExpr(EmptyShell Shell)
: CastExpr(ImplicitCastExprClass, Shell) { }
-
virtual SourceRange getSourceRange() const {
return getSubExpr()->getSourceRange();
}
@@ -1753,8 +2018,9 @@ class ExplicitCastExpr : public CastExpr {
protected:
ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind,
- Expr *op, TypeSourceInfo *writtenTy)
- : CastExpr(SC, exprTy, kind, op), TInfo(writtenTy) {}
+ Expr *op, CXXBaseSpecifierArray BasePath,
+ TypeSourceInfo *writtenTy)
+ : CastExpr(SC, exprTy, kind, op, BasePath), TInfo(writtenTy) {}
/// \brief Construct an empty explicit cast.
ExplicitCastExpr(StmtClass SC, EmptyShell Shell)
@@ -1774,7 +2040,7 @@ public:
StmtClass SC = T->getStmtClass();
if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass)
return true;
- if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass)
+ if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass)
return true;
return false;
@@ -1790,10 +2056,10 @@ class CStyleCastExpr : public ExplicitCastExpr {
SourceLocation RPLoc; // the location of the right paren
public:
CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op,
- TypeSourceInfo *writtenTy,
- SourceLocation l, SourceLocation r) :
- ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy),
- LPLoc(l), RPLoc(r) {}
+ CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy,
+ SourceLocation l, SourceLocation r)
+ : ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, BasePath,
+ writtenTy), LPLoc(l), RPLoc(r) {}
/// \brief Construct an empty C-style explicit cast.
explicit CStyleCastExpr(EmptyShell Shell)
@@ -2362,7 +2628,7 @@ public:
virtual child_iterator child_end();
};
-/// VAArgExpr, used for the builtin function __builtin_va_start.
+/// VAArgExpr, used for the builtin function __builtin_va_arg.
class VAArgExpr : public Expr {
Stmt *Val;
SourceLocation BuiltinLoc, RParenLoc;
@@ -2373,7 +2639,7 @@ public:
BuiltinLoc(BLoc),
RParenLoc(RPLoc) { }
- /// \brief Create an empty __builtin_va_start expression.
+ /// \brief Create an empty __builtin_va_arg expression.
explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { }
const Expr *getSubExpr() const { return cast<Expr>(Val); }
@@ -2438,7 +2704,8 @@ public:
/// serves as its syntactic form.
class InitListExpr : public Expr {
// FIXME: Eliminate this vector in favor of ASTContext allocation
- std::vector<Stmt *> InitExprs;
+ typedef ASTVector<Stmt *> InitExprsTy;
+ InitExprsTy InitExprs;
SourceLocation LBraceLoc, RBraceLoc;
/// Contains the initializer list that describes the syntactic form
@@ -2454,11 +2721,13 @@ class InitListExpr : public Expr {
bool HadArrayRangeDesignator;
public:
- InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
+ InitListExpr(ASTContext &C, SourceLocation lbraceloc,
+ Expr **initexprs, unsigned numinits,
SourceLocation rbraceloc);
/// \brief Build an empty initializer list.
- explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty) { }
+ explicit InitListExpr(ASTContext &C, EmptyShell Empty)
+ : Expr(InitListExprClass, Empty), InitExprs(C) { }
unsigned getNumInits() const { return InitExprs.size(); }
@@ -2478,7 +2747,7 @@ public:
}
/// \brief Reserve space for some number of initializers.
- void reserveInits(unsigned NumInits);
+ void reserveInits(ASTContext &C, unsigned NumInits);
/// @brief Specify the number of initializers
///
@@ -2495,7 +2764,7 @@ public:
/// When @p Init is out of range for this initializer list, the
/// initializer list will be extended with NULL expressions to
/// accomodate the new entry.
- Expr *updateInit(unsigned Init, Expr *expr);
+ Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
/// \brief If this initializes a union, specifies which field in the
/// union to initialize.
@@ -2541,8 +2810,8 @@ public:
virtual child_iterator child_begin();
virtual child_iterator child_end();
- typedef std::vector<Stmt *>::iterator iterator;
- typedef std::vector<Stmt *>::reverse_iterator reverse_iterator;
+ typedef InitExprsTy::iterator iterator;
+ typedef InitExprsTy::reverse_iterator reverse_iterator;
iterator begin() { return InitExprs.begin(); }
iterator end() { return InitExprs.end(); }
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 6e2e832e3542..f9ca78ad292d 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -118,8 +118,9 @@ private:
protected:
CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op,
- TypeSourceInfo *writtenTy, SourceLocation l)
- : ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {}
+ CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy,
+ SourceLocation l)
+ : ExplicitCastExpr(SC, ty, kind, op, BasePath, writtenTy), Loc(l) {}
explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell)
: ExplicitCastExpr(SC, Shell) { }
@@ -137,7 +138,6 @@ public:
}
static bool classof(const Stmt *T) {
switch (T->getStmtClass()) {
- case CXXNamedCastExprClass:
case CXXStaticCastExprClass:
case CXXDynamicCastExprClass:
case CXXReinterpretCastExprClass:
@@ -156,9 +156,10 @@ public:
/// @c static_cast<int>(1.0).
class CXXStaticCastExpr : public CXXNamedCastExpr {
public:
- CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op,
- TypeSourceInfo *writtenTy, SourceLocation l)
- : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {}
+ CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op,
+ CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy,
+ SourceLocation l)
+ : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, BasePath, writtenTy, l) {}
explicit CXXStaticCastExpr(EmptyShell Empty)
: CXXNamedCastExpr(CXXStaticCastExprClass, Empty) { }
@@ -177,9 +178,11 @@ public:
/// @c dynamic_cast<Derived*>(BasePtr).
class CXXDynamicCastExpr : public CXXNamedCastExpr {
public:
- CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op,
- TypeSourceInfo *writtenTy, SourceLocation l)
- : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {}
+ CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op,
+ CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy,
+ SourceLocation l)
+ : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, BasePath,
+ writtenTy, l) {}
explicit CXXDynamicCastExpr(EmptyShell Empty)
: CXXNamedCastExpr(CXXDynamicCastExprClass, Empty) { }
@@ -199,8 +202,9 @@ public:
class CXXReinterpretCastExpr : public CXXNamedCastExpr {
public:
CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op,
+ CXXBaseSpecifierArray BasePath,
TypeSourceInfo *writtenTy, SourceLocation l)
- : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op,
+ : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, BasePath,
writtenTy, l) {}
explicit CXXReinterpretCastExpr(EmptyShell Empty)
@@ -221,7 +225,8 @@ class CXXConstCastExpr : public CXXNamedCastExpr {
public:
CXXConstCastExpr(QualType ty, Expr *op, TypeSourceInfo *writtenTy,
SourceLocation l)
- : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {}
+ : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op,
+ CXXBaseSpecifierArray(), writtenTy, l) {}
explicit CXXConstCastExpr(EmptyShell Empty)
: CXXNamedCastExpr(CXXConstCastExprClass, Empty) { }
@@ -293,37 +298,41 @@ public:
/// This represents code like @c typeid(int) or @c typeid(*objPtr)
class CXXTypeidExpr : public Expr {
private:
- bool isTypeOp : 1;
- union {
- void *Ty;
- Stmt *Ex;
- } Operand;
+ llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand;
SourceRange Range;
public:
- CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) :
- Expr(CXXTypeidExprClass, Ty,
+ CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R)
+ : Expr(CXXTypeidExprClass, Ty,
+ // typeid is never type-dependent (C++ [temp.dep.expr]p4)
+ false,
+ // typeid is value-dependent if the type or expression are dependent
+ Operand->getType()->isDependentType()),
+ Operand(Operand), Range(R) { }
+
+ CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R)
+ : Expr(CXXTypeidExprClass, Ty,
// typeid is never type-dependent (C++ [temp.dep.expr]p4)
false,
// typeid is value-dependent if the type or expression are dependent
- (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType()
- : static_cast<Expr*>(op)->isValueDependent())),
- isTypeOp(isTypeOp), Range(r) {
- if (isTypeOp)
- Operand.Ty = op;
- else
- // op was an Expr*, so cast it back to that to be safe
- Operand.Ex = static_cast<Expr*>(op);
- }
+ Operand->isTypeDependent() || Operand->isValueDependent()),
+ Operand(Operand), Range(R) { }
+
+ bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
+
+ /// \brief Retrieves the type operand of this typeid() expression after
+ /// various required adjustments (removing reference types, cv-qualifiers).
+ QualType getTypeOperand() const;
- bool isTypeOperand() const { return isTypeOp; }
- QualType getTypeOperand() const {
+ /// \brief Retrieve source information for the type operand.
+ TypeSourceInfo *getTypeOperandSourceInfo() const {
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
- return QualType::getFromOpaquePtr(Operand.Ty);
+ return Operand.get<TypeSourceInfo *>();
}
+
Expr* getExprOperand() const {
assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
- return static_cast<Expr*>(Operand.Ex);
+ return static_cast<Expr*>(Operand.get<Stmt *>());
}
virtual SourceRange getSourceRange() const {
@@ -621,12 +630,20 @@ public:
/// CXXConstructExpr - Represents a call to a C++ constructor.
class CXXConstructExpr : public Expr {
+public:
+ enum ConstructionKind {
+ CK_Complete,
+ CK_NonVirtualBase,
+ CK_VirtualBase
+ };
+
+private:
CXXConstructorDecl *Constructor;
SourceLocation Loc;
bool Elidable : 1;
bool ZeroInitialization : 1;
- bool BaseInitialization : 1;
+ unsigned ConstructKind : 2;
Stmt **Args;
unsigned NumArgs;
@@ -636,7 +653,7 @@ protected:
CXXConstructorDecl *d, bool elidable,
Expr **args, unsigned numargs,
bool ZeroInitialization = false,
- bool BaseInitialization = false);
+ ConstructionKind ConstructKind = CK_Complete);
~CXXConstructExpr() { }
virtual void DoDestroy(ASTContext &C);
@@ -651,7 +668,7 @@ public:
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool ZeroInitialization = false,
- bool BaseInitialization = false);
+ ConstructionKind ConstructKind = CK_Complete);
CXXConstructorDecl* getConstructor() const { return Constructor; }
@@ -673,8 +690,12 @@ public:
/// \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; }
+ ConstructionKind getConstructionKind() const {
+ return (ConstructionKind)ConstructKind;
+ }
+ void setConstructionKind(ConstructionKind CK) {
+ ConstructKind = CK;
+ }
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
@@ -725,9 +746,10 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr {
public:
CXXFunctionalCastExpr(QualType ty, TypeSourceInfo *writtenTy,
SourceLocation tyBeginLoc, CastKind kind,
- Expr *castExpr, SourceLocation rParenLoc)
+ Expr *castExpr, CXXBaseSpecifierArray BasePath,
+ SourceLocation rParenLoc)
: ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr,
- writtenTy),
+ BasePath, writtenTy),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {}
explicit CXXFunctionalCastExpr(EmptyShell Shell)
@@ -774,7 +796,8 @@ public:
CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons,
QualType writtenTy, SourceLocation tyBeginLoc,
Expr **Args,unsigned NumArgs,
- SourceLocation rParenLoc);
+ SourceLocation rParenLoc,
+ bool ZeroInitialization = false);
~CXXTemporaryObjectExpr() { }
@@ -1290,6 +1313,9 @@ public:
Results.append(Begin, End);
}
+ /// Gets the naming class of this lookup, if any.
+ CXXRecordDecl *getNamingClass() const;
+
typedef UnresolvedSetImpl::iterator decls_iterator;
decls_iterator decls_begin() const { return Results.begin(); }
decls_iterator decls_end() const { return Results.end(); }
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 6f43973a3e1d..8a09f4e9a6a9 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -59,13 +59,14 @@ public:
/// and behavior as StringLiteral except that the string initializer is obtained
/// from ASTContext with the encoding type as an argument.
class ObjCEncodeExpr : public Expr {
- QualType EncType;
+ TypeSourceInfo *EncodedType;
SourceLocation AtLoc, RParenLoc;
public:
- ObjCEncodeExpr(QualType T, QualType ET,
+ ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType,
SourceLocation at, SourceLocation rp)
- : Expr(ObjCEncodeExprClass, T, ET->isDependentType(),
- ET->isDependentType()), EncType(ET), AtLoc(at), RParenLoc(rp) {}
+ : Expr(ObjCEncodeExprClass, T, EncodedType->getType()->isDependentType(),
+ EncodedType->getType()->isDependentType()),
+ EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {}
explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){}
@@ -75,9 +76,12 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- QualType getEncodedType() const { return EncType; }
- void setEncodedType(QualType T) { EncType = T; }
+ QualType getEncodedType() const { return EncodedType->getType(); }
+ TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; }
+ void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) {
+ EncodedType = EncType;
+ }
virtual SourceRange getSourceRange() const {
return SourceRange(AtLoc, RParenLoc);
@@ -177,11 +181,12 @@ class ObjCIvarRefExpr : public Expr {
public:
ObjCIvarRefExpr(ObjCIvarDecl *d,
- QualType t, SourceLocation l, Expr *base=0,
+ QualType t, SourceLocation l, Expr *base,
bool arrow = false, bool freeIvar = false) :
- Expr(ObjCIvarRefExprClass, t, false, false), D(d),
- Loc(l), Base(base), IsArrow(arrow),
- IsFreeIvar(freeIvar) {}
+ Expr(ObjCIvarRefExprClass, t, /*TypeDependent=*/false,
+ base->isValueDependent()), D(d),
+ Loc(l), Base(base), IsArrow(arrow),
+ IsFreeIvar(freeIvar) {}
explicit ObjCIvarRefExpr(EmptyShell Empty)
: Expr(ObjCIvarRefExprClass, Empty) {}
@@ -228,8 +233,9 @@ private:
public:
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
SourceLocation l, Expr *base)
- : Expr(ObjCPropertyRefExprClass, t, false, false), AsProperty(PD),
- IdLoc(l), Base(base) {
+ : Expr(ObjCPropertyRefExprClass, t, /*TypeDependent=*/false,
+ base->isValueDependent()),
+ AsProperty(PD), IdLoc(l), Base(base) {
}
explicit ObjCPropertyRefExpr(EmptyShell Empty)
@@ -293,7 +299,8 @@ public:
QualType t,
ObjCMethodDecl *setter,
SourceLocation l, Expr *base)
- : Expr(ObjCImplicitSetterGetterRefExprClass, t, false, false),
+ : Expr(ObjCImplicitSetterGetterRefExprClass, t, /*TypeDependent=*/false,
+ base->isValueDependent()),
Setter(setter), Getter(getter), MemberLoc(l), Base(base),
InterfaceDecl(0), ClassLoc(SourceLocation()) {
}
@@ -339,152 +346,376 @@ public:
virtual child_iterator child_end();
};
+/// \brief An expression that sends a message to the given Objective-C
+/// object or class.
+///
+/// The following contains two message send expressions:
+///
+/// \code
+/// [[NSString alloc] initWithString:@"Hello"]
+/// \endcode
+///
+/// The innermost message send invokes the "alloc" class method on the
+/// NSString class, while the outermost message send invokes the
+/// "initWithString" instance method on the object returned from
+/// NSString's "alloc". In all, an Objective-C message send can take
+/// on four different (although related) forms:
+///
+/// 1. Send to an object instance.
+/// 2. Send to a class.
+/// 3. Send to the superclass instance of the current class.
+/// 4. Send to the superclass of the current class.
+///
+/// All four kinds of message sends are modeled by the ObjCMessageExpr
+/// class, and can be distinguished via \c getReceiverKind(). Example:
+///
class ObjCMessageExpr : public Expr {
- // SubExprs - The receiver and arguments of the message expression.
- Stmt **SubExprs;
+ /// \brief The number of arguments in the message send, not
+ /// including the receiver.
+ unsigned NumArgs : 16;
+
+ /// \brief The kind of message send this is, which is one of the
+ /// ReceiverKind values.
+ ///
+ /// We pad this out to a byte to avoid excessive masking and shifting.
+ unsigned Kind : 8;
+
+ /// \brief Whether we have an actual method prototype in \c
+ /// SelectorOrMethod.
+ ///
+ /// When non-zero, we have a method declaration; otherwise, we just
+ /// have a selector.
+ unsigned HasMethod : 8;
+
+ /// \brief When the message expression is a send to 'super', this is
+ /// the location of the 'super' keyword.
+ SourceLocation SuperLoc;
+
+ /// \brief Stores either the selector that this message is sending
+ /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer
+ /// referring to the method that we type-checked against.
+ uintptr_t SelectorOrMethod;
+
+ /// \brief The source locations of the open and close square
+ /// brackets ('[' and ']', respectively).
+ SourceLocation LBracLoc, RBracLoc;
+
+ ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
+ : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
+ HasMethod(0), SelectorOrMethod(0) { }
+
+ ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+ ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+ ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+
+ /// \brief Retrieve the pointer value of the message receiver.
+ void *getReceiverPointer() const {
+ return *const_cast<void **>(
+ reinterpret_cast<const void * const*>(this + 1));
+ }
- // NumArgs - The number of arguments (not including the receiver) to the
- // message expression.
- unsigned NumArgs;
+ /// \brief Set the pointer value of the message receiver.
+ void setReceiverPointer(void *Value) {
+ *reinterpret_cast<void **>(this + 1) = Value;
+ }
- /// \brief The location of the class name in a class message.
- SourceLocation ClassNameLoc;
+public:
+ /// \brief The kind of receiver this message is sending to.
+ enum ReceiverKind {
+ /// \brief The receiver is a class.
+ Class = 0,
+ /// \brief The receiver is an object instance.
+ Instance,
+ /// \brief The receiver is a superclass.
+ SuperClass,
+ /// \brief The receiver is the instance of the superclass object.
+ SuperInstance
+ };
- // A unigue name for this message.
- Selector SelName;
+ /// \brief Create a message send to super.
+ ///
+ /// \param Context The ASTContext in which this expression will be created.
+ ///
+ /// \param T The result type of this message.
+ ///
+ /// \param LBrac The location of the open square bracket '['.
+ ///
+ /// \param SuperLoc The location of the "super" keyword.
+ ///
+ /// \param IsInstanceSuper Whether this is an instance "super"
+ /// message (otherwise, it's a class "super" message).
+ ///
+ /// \param Sel The selector used to determine which method gets called.
+ ///
+ /// \param Method The Objective-C method against which this message
+ /// send was type-checked. May be NULL.
+ ///
+ /// \param Args The message send arguments.
+ ///
+ /// \param NumArgs The number of arguments.
+ ///
+ /// \param RBracLoc The location of the closing square bracket ']'.
+ static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+
+ /// \brief Create a class message send.
+ ///
+ /// \param Context The ASTContext in which this expression will be created.
+ ///
+ /// \param T The result type of this message.
+ ///
+ /// \param LBrac The location of the open square bracket '['.
+ ///
+ /// \param Receiver The type of the receiver, including
+ /// source-location information.
+ ///
+ /// \param Sel The selector used to determine which method gets called.
+ ///
+ /// \param Method The Objective-C method against which this message
+ /// send was type-checked. May be NULL.
+ ///
+ /// \param Args The message send arguments.
+ ///
+ /// \param NumArgs The number of arguments.
+ ///
+ /// \param RBracLoc The location of the closing square bracket ']'.
+ static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+
+ /// \brief Create an instance message send.
+ ///
+ /// \param Context The ASTContext in which this expression will be created.
+ ///
+ /// \param T The result type of this message.
+ ///
+ /// \param LBrac The location of the open square bracket '['.
+ ///
+ /// \param Receiver The expression used to produce the object that
+ /// will receive this message.
+ ///
+ /// \param Sel The selector used to determine which method gets called.
+ ///
+ /// \param Method The Objective-C method against which this message
+ /// send was type-checked. May be NULL.
+ ///
+ /// \param Args The message send arguments.
+ ///
+ /// \param NumArgs The number of arguments.
+ ///
+ /// \param RBracLoc The location of the closing square bracket ']'.
+ static ObjCMessageExpr *Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc);
+
+ /// \brief Create an empty Objective-C message expression, to be
+ /// filled in by subsequent calls.
+ ///
+ /// \param Context The context in which the message send will be created.
+ ///
+ /// \param NumArgs The number of message arguments, not including
+ /// the receiver.
+ static ObjCMessageExpr *CreateEmpty(ASTContext &Context, unsigned NumArgs);
+
+ /// \brief Determine the kind of receiver that this message is being
+ /// sent to.
+ ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; }
+
+ /// \brief Determine whether this is an instance message to either a
+ /// computed object or to super.
+ bool isInstanceMessage() const {
+ return getReceiverKind() == Instance || getReceiverKind() == SuperInstance;
+ }
- // A method prototype for this message (optional).
- // FIXME: Since method decls contain the selector, and most messages have a
- // prototype, consider devising a scheme for unifying SelName/MethodProto.
- ObjCMethodDecl *MethodProto;
+ /// \brief Determine whether this is an class message to either a
+ /// specified class or to super.
+ bool isClassMessage() const {
+ return getReceiverKind() == Class || getReceiverKind() == SuperClass;
+ }
- SourceLocation LBracloc, RBracloc;
+ /// \brief Returns the receiver of an instance message.
+ ///
+ /// \brief Returns the object expression for an instance message, or
+ /// NULL for a message that is not an instance message.
+ Expr *getInstanceReceiver() {
+ if (getReceiverKind() == Instance)
+ return static_cast<Expr *>(getReceiverPointer());
- // Constants for indexing into SubExprs.
- enum { RECEIVER=0, ARGS_START=1 };
+ return 0;
+ }
+ const Expr *getInstanceReceiver() const {
+ return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver();
+ }
- // Bit-swizzling flags.
- enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 };
- unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; }
+ /// \brief Turn this message send into an instance message that
+ /// computes the receiver object with the given expression.
+ void setInstanceReceiver(Expr *rec) {
+ Kind = Instance;
+ setReceiverPointer(rec);
+ }
+
+ /// \brief Returns the type of a class message send, or NULL if the
+ /// message is not a class message.
+ QualType getClassReceiver() const {
+ if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo())
+ return TSInfo->getType();
+
+ return QualType();
+ }
-public:
- /// This constructor is used to represent class messages where the
- /// ObjCInterfaceDecl* of the receiver is not known.
- ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType, ObjCMethodDecl *methDecl,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned NumArgs);
-
- /// This constructor is used to represent class messages where the
- /// ObjCInterfaceDecl* of the receiver is known.
- // FIXME: clsName should be typed to ObjCInterfaceType
- ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType, ObjCMethodDecl *methDecl,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned NumArgs);
-
- // constructor for instance messages.
- ObjCMessageExpr(ASTContext &C, Expr *receiver, Selector selInfo,
- QualType retType, ObjCMethodDecl *methDecl,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned NumArgs);
-
- explicit ObjCMessageExpr(EmptyShell Empty)
- : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {}
-
- 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
- /// class methods, use getClassName.
- /// FIXME: need to handle/detect 'super' usage within a class method.
- Expr *getReceiver() {
- uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
- return (x & Flags) == IsInstMeth ? (Expr*) x : 0;
- }
- const Expr *getReceiver() const {
- return const_cast<ObjCMessageExpr*>(this)->getReceiver();
- }
- // FIXME: need setters for different receiver types.
- void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; }
- Selector getSelector() const { return SelName; }
- void setSelector(Selector S) { SelName = S; }
+ /// \brief Returns a type-source information of a class message
+ /// send, or NULL if the message is not a class message.
+ TypeSourceInfo *getClassReceiverTypeInfo() const {
+ if (getReceiverKind() == Class)
+ return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer());
+ return 0;
+ }
+
+ void setClassReceiver(TypeSourceInfo *TSInfo) {
+ Kind = Class;
+ setReceiverPointer(TSInfo);
+ }
- const ObjCMethodDecl *getMethodDecl() const { return MethodProto; }
- ObjCMethodDecl *getMethodDecl() { return MethodProto; }
- void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; }
+ /// \brief Retrieve the location of the 'super' keyword for a class
+ /// or instance message to 'super', otherwise an invalid source location.
+ SourceLocation getSuperLoc() const {
+ if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass)
+ return SuperLoc;
- /// \brief Describes the class receiver of a message send.
- struct ClassInfo {
- /// \brief The interface declaration for the class that is
- /// receiving the message. May be NULL.
- ObjCInterfaceDecl *Decl;
+ return SourceLocation();
+ }
- /// \brief The name of the class that is receiving the
- /// message. This will never be NULL.
- IdentifierInfo *Name;
+ /// \brief Retrieve the Objective-C interface to which this message
+ /// is being directed, if known.
+ ///
+ /// This routine cross-cuts all of the different kinds of message
+ /// sends to determine what the underlying (statically known) type
+ /// of the receiver will be; use \c getReceiverKind() to determine
+ /// whether the message is a class or an instance method, whether it
+ /// is a send to super or not, etc.
+ ///
+ /// \returns The Objective-C interface if known, otherwise NULL.
+ ObjCInterfaceDecl *getReceiverInterface() const;
+
+ /// \brief Retrieve the type referred to by 'super'.
+ ///
+ /// The returned type will either be an ObjCInterfaceType (for an
+ /// class message to super) or an ObjCObjectPointerType that refers
+ /// to a class (for an instance message to super);
+ QualType getSuperType() const {
+ if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass)
+ return QualType::getFromOpaquePtr(getReceiverPointer());
+
+ return QualType();
+ }
- /// \brief The source location of the class name.
- SourceLocation Loc;
+ void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) {
+ Kind = IsInstanceSuper? SuperInstance : SuperClass;
+ SuperLoc = Loc;
+ setReceiverPointer(T.getAsOpaquePtr());
+ }
- ClassInfo() : Decl(0), Name(0), Loc() { }
+ Selector getSelector() const;
- ClassInfo(ObjCInterfaceDecl *Decl, IdentifierInfo *Name, SourceLocation Loc)
- : Decl(Decl), Name(Name), Loc(Loc) { }
- };
+ void setSelector(Selector S) {
+ HasMethod = false;
+ SelectorOrMethod = reinterpret_cast<uintptr_t>(S.getAsOpaquePtr());
+ }
- /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl*
- /// and IdentifierInfo* of the invoked class. Both can be NULL if this
- /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none
- /// was available when this ObjCMessageExpr object was constructed.
- ClassInfo getClassInfo() const;
- void setClassInfo(const ClassInfo &C);
+ const ObjCMethodDecl *getMethodDecl() const {
+ if (HasMethod)
+ return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod);
- /// getClassName - For class methods, this returns the invoked class,
- /// and returns NULL otherwise. For instance methods, use getReceiver.
- IdentifierInfo *getClassName() const {
- return getClassInfo().Name;
+ return 0;
}
- /// getNumArgs - Return the number of actual arguments to this call.
+ ObjCMethodDecl *getMethodDecl() {
+ if (HasMethod)
+ return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod);
+
+ return 0;
+ }
+
+ void setMethodDecl(ObjCMethodDecl *MD) {
+ HasMethod = true;
+ SelectorOrMethod = reinterpret_cast<uintptr_t>(MD);
+ }
+
+ /// \brief Return the number of actual arguments in this message,
+ /// not counting the receiver.
unsigned getNumArgs() const { return NumArgs; }
- void setNumArgs(unsigned nArgs) {
- NumArgs = nArgs;
- // FIXME: should always allocate SubExprs via the ASTContext's
- // allocator.
- if (!SubExprs)
- SubExprs = new Stmt* [NumArgs + 1];
+
+ /// \brief Retrieve the arguments to this message, not including the
+ /// receiver.
+ Stmt **getArgs() {
+ return reinterpret_cast<Stmt **>(this + 1) + 1;
+ }
+ const Stmt * const *getArgs() const {
+ return reinterpret_cast<const Stmt * const *>(this + 1) + 1;
}
/// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ return cast<Expr>(getArgs()[Arg]);
}
const Expr *getArg(unsigned Arg) const {
assert(Arg < NumArgs && "Arg access out of range!");
- return cast<Expr>(SubExprs[Arg+ARGS_START]);
+ return cast<Expr>(getArgs()[Arg]);
}
/// setArg - Set the specified argument.
void setArg(unsigned Arg, Expr *ArgExpr) {
assert(Arg < NumArgs && "Arg access out of range!");
- SubExprs[Arg+ARGS_START] = ArgExpr;
+ getArgs()[Arg] = ArgExpr;
}
- SourceLocation getLeftLoc() const { return LBracloc; }
- SourceLocation getRightLoc() const { return RBracloc; }
+ SourceLocation getLeftLoc() const { return LBracLoc; }
+ SourceLocation getRightLoc() const { return RBracLoc; }
- void setLeftLoc(SourceLocation L) { LBracloc = L; }
- void setRightLoc(SourceLocation L) { RBracloc = L; }
+ void setLeftLoc(SourceLocation L) { LBracLoc = L; }
+ void setRightLoc(SourceLocation L) { RBracLoc = L; }
void setSourceRange(SourceRange R) {
- LBracloc = R.getBegin();
- RBracloc = R.getEnd();
+ LBracLoc = R.getBegin();
+ RBracLoc = R.getEnd();
}
virtual SourceRange getSourceRange() const {
- return SourceRange(LBracloc, RBracloc);
+ return SourceRange(LBracLoc, RBracLoc);
}
static bool classof(const Stmt *T) {
@@ -499,14 +730,17 @@ public:
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
- arg_iterator arg_begin() { return &SubExprs[ARGS_START]; }
- arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; }
- const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; }
- const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; }
+ arg_iterator arg_begin() { return getArgs(); }
+ arg_iterator arg_end() { return getArgs() + NumArgs; }
+ const_arg_iterator arg_begin() const { return getArgs(); }
+ const_arg_iterator arg_end() const { return getArgs() + NumArgs; }
};
/// ObjCSuperExpr - Represents the "super" expression in Objective-C,
/// which refers to the object on which the current method is executing.
+///
+/// FIXME: This class is intended for removal, once its remaining
+/// clients have been altered to represent "super" internally.
class ObjCSuperExpr : public Expr {
SourceLocation Loc;
public:
@@ -542,7 +776,8 @@ class ObjCIsaExpr : public Expr {
bool IsArrow;
public:
ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
- : Expr(ObjCIsaExprClass, ty, false, false),
+ : Expr(ObjCIsaExprClass, ty, /*TypeDependent=*/false,
+ base->isValueDependent()),
Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
/// \brief Build an empty expression.
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index b8d80bc8978d..79e44511d32d 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -66,6 +66,13 @@ public:
/// building a new declaration.
virtual Decl *GetDecl(uint32_t ID) = 0;
+ /// \brief Resolve a selector ID into a selector.
+ virtual Selector GetSelector(uint32_t ID) = 0;
+
+ /// \brief Returns the number of selectors known to the external AST
+ /// source.
+ virtual uint32_t GetNumKnownSelectors() = 0;
+
/// \brief Resolve the offset of a statement in the decl stream into a
/// statement.
///
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 466848976cb3..0b68a4007363 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -70,13 +70,13 @@ namespace clang {
};
class ConstExprIterator {
- Stmt* const * I;
+ const Stmt * const *I;
public:
- ConstExprIterator(Stmt* const* i) : I(i) {}
+ ConstExprIterator(const Stmt * const *i) : I(i) {}
ConstExprIterator() : I(0) {}
ConstExprIterator& operator++() { ++I; return *this; }
- ConstExprIterator operator+(size_t i) { return I+i; }
- ConstExprIterator operator-(size_t i) { return I-i; }
+ ConstExprIterator operator+(size_t i) const { return I+i; }
+ ConstExprIterator operator-(size_t i) const { return I-i; }
const Expr * operator[](size_t idx) const;
signed operator-(const ConstExprIterator& R) const { return I - R.I; }
const Expr * operator*() const;
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index ec6149e55f11..3a23e49148d5 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -78,6 +78,7 @@ EXPR(StringLiteral , Expr)
EXPR(CharacterLiteral , Expr)
EXPR(ParenExpr , Expr)
EXPR(UnaryOperator , Expr)
+EXPR(OffsetOfExpr , Expr)
EXPR(SizeOfAlignOfExpr , Expr)
EXPR(ArraySubscriptExpr , Expr)
EXPR(CallExpr , Expr)
@@ -107,7 +108,7 @@ EXPR(GNUNullExpr , Expr)
// C++ Expressions.
EXPR(CXXOperatorCallExpr , CallExpr)
EXPR(CXXMemberCallExpr , CallExpr)
-EXPR(CXXNamedCastExpr , ExplicitCastExpr)
+ABSTRACT_EXPR(CXXNamedCastExpr , ExplicitCastExpr)
EXPR(CXXStaticCastExpr , CXXNamedCastExpr)
EXPR(CXXDynamicCastExpr , CXXNamedCastExpr)
EXPR(CXXReinterpretCastExpr , CXXNamedCastExpr)
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index 3fd8f1672deb..269aa4c6dab2 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -71,38 +71,31 @@ public:
/// ObjCAtCatchStmt - This represents objective-c's @catch statement.
class ObjCAtCatchStmt : public Stmt {
private:
- enum { BODY, NEXT_CATCH, END_EXPR };
- ParmVarDecl *ExceptionDecl;
- Stmt *SubExprs[END_EXPR];
+ VarDecl *ExceptionDecl;
+ Stmt *Body;
SourceLocation AtCatchLoc, RParenLoc;
public:
ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
- ParmVarDecl *catchVarDecl,
- Stmt *atCatchStmt, Stmt *atCatchList);
+ VarDecl *catchVarDecl,
+ Stmt *atCatchStmt)
+ : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl),
+ Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { }
explicit ObjCAtCatchStmt(EmptyShell Empty) :
Stmt(ObjCAtCatchStmtClass, Empty) { }
- const Stmt *getCatchBody() const { return SubExprs[BODY]; }
- Stmt *getCatchBody() { return SubExprs[BODY]; }
- void setCatchBody(Stmt *S) { SubExprs[BODY] = S; }
+ const Stmt *getCatchBody() const { return Body; }
+ Stmt *getCatchBody() { return Body; }
+ void setCatchBody(Stmt *S) { Body = S; }
- const ObjCAtCatchStmt *getNextCatchStmt() const {
- return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
- }
- ObjCAtCatchStmt *getNextCatchStmt() {
- return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
- }
- void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
-
- const ParmVarDecl *getCatchParamDecl() const {
+ const VarDecl *getCatchParamDecl() const {
return ExceptionDecl;
}
- ParmVarDecl *getCatchParamDecl() {
+ VarDecl *getCatchParamDecl() {
return ExceptionDecl;
}
- void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; }
+ void setCatchParamDecl(VarDecl *D) { ExceptionDecl = D; }
SourceLocation getAtCatchLoc() const { return AtCatchLoc; }
void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; }
@@ -110,7 +103,7 @@ public:
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
virtual SourceRange getSourceRange() const {
- return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
+ return SourceRange(AtCatchLoc, Body->getLocEnd());
}
bool hasEllipsis() const { return getCatchParamDecl() == 0; }
@@ -160,50 +153,94 @@ public:
/// @try ... @catch ... @finally statement.
class ObjCAtTryStmt : public Stmt {
private:
- enum { TRY, CATCH, FINALLY, END_EXPR };
- Stmt* SubStmts[END_EXPR];
-
+ // The location of the
SourceLocation AtTryLoc;
-public:
+
+ // The number of catch blocks in this statement.
+ unsigned NumCatchStmts : 16;
+
+ // Whether this statement has a @finally statement.
+ bool HasFinally : 1;
+
+ /// \brief Retrieve the statements that are stored after this @try statement.
+ ///
+ /// The order of the statements in memory follows the order in the source,
+ /// with the @try body first, followed by the @catch statements (if any) and,
+ /// finally, the @finally (if it exists).
+ Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); }
+ const Stmt* const *getStmts() const {
+ return reinterpret_cast<const Stmt * const*> (this + 1);
+ }
+
ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
- Stmt *atCatchStmt,
- Stmt *atFinallyStmt)
- : Stmt(ObjCAtTryStmtClass) {
- SubStmts[TRY] = atTryStmt;
- SubStmts[CATCH] = atCatchStmt;
- SubStmts[FINALLY] = atFinallyStmt;
- AtTryLoc = atTryLoc;
- }
- explicit ObjCAtTryStmt(EmptyShell Empty) :
- Stmt(ObjCAtTryStmtClass, Empty) { }
+ Stmt **CatchStmts, unsigned NumCatchStmts,
+ Stmt *atFinallyStmt);
+
+ explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts,
+ bool HasFinally)
+ : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts),
+ HasFinally(HasFinally) { }
+public:
+ static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc,
+ Stmt *atTryStmt,
+ Stmt **CatchStmts, unsigned NumCatchStmts,
+ Stmt *atFinallyStmt);
+ static ObjCAtTryStmt *CreateEmpty(ASTContext &Context,
+ unsigned NumCatchStmts,
+ bool HasFinally);
+
+ /// \brief Retrieve the location of the @ in the @try.
SourceLocation getAtTryLoc() const { return AtTryLoc; }
void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
- const Stmt *getTryBody() const { return SubStmts[TRY]; }
- Stmt *getTryBody() { return SubStmts[TRY]; }
- void setTryBody(Stmt *S) { SubStmts[TRY] = S; }
-
- const ObjCAtCatchStmt *getCatchStmts() const {
- return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+ /// \brief Retrieve the @try body.
+ const Stmt *getTryBody() const { return getStmts()[0]; }
+ Stmt *getTryBody() { return getStmts()[0]; }
+ void setTryBody(Stmt *S) { getStmts()[0] = S; }
+
+ /// \brief Retrieve the number of @catch statements in this try-catch-finally
+ /// block.
+ unsigned getNumCatchStmts() const { return NumCatchStmts; }
+
+ /// \brief Retrieve a @catch statement.
+ const ObjCAtCatchStmt *getCatchStmt(unsigned I) const {
+ assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+ return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
}
- ObjCAtCatchStmt *getCatchStmts() {
- return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+
+ /// \brief Retrieve a @catch statement.
+ ObjCAtCatchStmt *getCatchStmt(unsigned I) {
+ assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+ return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
}
- void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
-
+
+ /// \brief Set a particular catch statement.
+ void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) {
+ assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+ getStmts()[I + 1] = S;
+ }
+
+ /// Retrieve the @finally statement, if any.
const ObjCAtFinallyStmt *getFinallyStmt() const {
- return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+ if (!HasFinally)
+ return 0;
+
+ return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
}
ObjCAtFinallyStmt *getFinallyStmt() {
- return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+ if (!HasFinally)
+ return 0;
+
+ return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
}
- void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
-
- virtual SourceRange getSourceRange() const {
- return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
+ void setFinallyStmt(Stmt *S) {
+ assert(HasFinally && "@try does not have a @finally slot!");
+ getStmts()[1 + NumCatchStmts] = S;
}
+ virtual SourceRange getSourceRange() const;
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;
}
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index aafe96381192..f3de9fa011bc 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -25,6 +25,7 @@ namespace llvm {
namespace clang {
class DependentTemplateName;
+class DiagnosticBuilder;
class IdentifierInfo;
class NestedNameSpecifier;
struct PrintingPolicy;
@@ -173,6 +174,11 @@ public:
}
};
+/// Insertion operator for diagnostics. This allows sending TemplateName's
+/// into a diagnostic with <<.
+const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ TemplateName N);
+
/// \brief Represents a template name that was expressed as a
/// qualified name.
///
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 72793651c4be..030c74c64089 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -871,6 +871,7 @@ public:
bool isRecordType() const;
bool isClassType() const;
bool isStructureType() const;
+ bool isStructureOrClassType() const;
bool isUnionType() const;
bool isComplexIntegerType() const; // GCC _Complex integer type.
bool isVectorType() const; // GCC vector type.
@@ -922,6 +923,11 @@ public:
const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const;
const CXXRecordDecl *getCXXRecordDeclForPointerType() const;
+ /// \brief Retrieves the CXXRecordDecl that this type refers to, either
+ /// because the type is a RecordType or because it is the injected-class-name
+ /// type of a class template or class template partial specialization.
+ CXXRecordDecl *getAsCXXRecordDecl() const;
+
// Member-template getAs<specific type>'. This scheme will eventually
// replace the specific getAsXXXX methods above.
//
@@ -2433,8 +2439,11 @@ public:
class TemplateSpecializationType
: public Type, public llvm::FoldingSetNode {
- // FIXME: Currently needed for profiling expressions; can we avoid this?
- ASTContext &Context;
+ // The ASTContext is currently needed in order to profile expressions.
+ // FIXME: avoid this.
+ //
+ // The bool is whether this is a current instantiation.
+ llvm::PointerIntPair<ASTContext*, 1, bool> ContextAndCurrentInstantiation;
/// \brief The name of the template being specialized.
TemplateName Template;
@@ -2445,6 +2454,7 @@ class TemplateSpecializationType
TemplateSpecializationType(ASTContext &Context,
TemplateName T,
+ bool IsCurrentInstantiation,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon);
@@ -2476,6 +2486,12 @@ public:
static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &,
const PrintingPolicy &Policy);
+ /// True if this template specialization type matches a current
+ /// instantiation in the context in which it is found.
+ bool isCurrentInstantiation() const {
+ return ContextAndCurrentInstantiation.getInt();
+ }
+
typedef const TemplateArgument * iterator;
iterator begin() const { return getArgs(); }
@@ -2496,15 +2512,20 @@ public:
/// \precondition @c isArgType(Arg)
const TemplateArgument &getArg(unsigned Idx) const;
- bool isSugared() const { return !isDependentType(); }
+ bool isSugared() const {
+ return !isDependentType() || isCurrentInstantiation();
+ }
QualType desugar() const { return getCanonicalTypeInternal(); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Template, getArgs(), NumArgs, Context);
+ Profile(ID, Template, isCurrentInstantiation(), getArgs(), NumArgs,
+ *ContextAndCurrentInstantiation.getPointer());
}
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
- const TemplateArgument *Args, unsigned NumArgs,
+ bool IsCurrentInstantiation,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
ASTContext &Context);
static bool classof(const Type *T) {
@@ -2513,40 +2534,57 @@ public:
static bool classof(const TemplateSpecializationType *T) { return true; }
};
-/// \brief The injected class name of a C++ class template. Used to
-/// record that a type was spelled with a bare identifier rather than
-/// as a template-id; the equivalent for non-templated classes is just
-/// RecordType.
+/// \brief The injected class name of a C++ class template or class
+/// template partial specialization. Used to record that a type was
+/// spelled with a bare identifier rather than as a template-id; the
+/// equivalent for non-templated classes is just RecordType.
///
-/// For consistency, template instantiation turns these into RecordTypes.
+/// Injected class name types are always dependent. Template
+/// instantiation turns these into RecordTypes.
///
-/// The desugared form is always a unqualified TemplateSpecializationType.
-/// The canonical form is always either a TemplateSpecializationType
-/// (when dependent) or a RecordType (otherwise).
+/// Injected class name types are always canonical. This works
+/// because it is impossible to compare an injected class name type
+/// with the corresponding non-injected template type, for the same
+/// reason that it is impossible to directly compare template
+/// parameters from different dependent contexts: injected class name
+/// types can only occur within the scope of a particular templated
+/// declaration, and within that scope every template specialization
+/// will canonicalize to the injected class name (when appropriate
+/// according to the rules of the language).
class InjectedClassNameType : public Type {
CXXRecordDecl *Decl;
- QualType UnderlyingType;
+ /// The template specialization which this type represents.
+ /// For example, in
+ /// template <class T> class A { ... };
+ /// this is A<T>, whereas in
+ /// template <class X, class Y> class A<B<X,Y> > { ... };
+ /// this is A<B<X,Y> >.
+ ///
+ /// It is always unqualified, always a template specialization type,
+ /// and always dependent.
+ QualType InjectedType;
friend class ASTContext; // ASTContext creates these.
- InjectedClassNameType(CXXRecordDecl *D, QualType TST, QualType Canon)
- : Type(InjectedClassName, Canon, Canon->isDependentType()),
- Decl(D), UnderlyingType(TST) {
+ friend class TagDecl; // TagDecl mutilates the Decl
+ InjectedClassNameType(CXXRecordDecl *D, QualType TST)
+ : Type(InjectedClassName, QualType(), true),
+ Decl(D), InjectedType(TST) {
assert(isa<TemplateSpecializationType>(TST));
assert(!TST.hasQualifiers());
- assert(TST->getCanonicalTypeInternal() == Canon);
+ assert(TST->isDependentType());
}
public:
- QualType getUnderlyingType() const { return UnderlyingType; }
- const TemplateSpecializationType *getUnderlyingTST() const {
- return cast<TemplateSpecializationType>(UnderlyingType.getTypePtr());
+ QualType getInjectedSpecializationType() const { return InjectedType; }
+ const TemplateSpecializationType *getInjectedTST() const {
+ return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
}
CXXRecordDecl *getDecl() const { return Decl; }
- bool isSugared() const { return true; }
- QualType desugar() const { return UnderlyingType; }
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
static bool classof(const Type *T) {
return T->getTypeClass() == InjectedClassName;
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 7e8b73c7a5f9..c665073025f7 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -91,7 +91,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type)
NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
NON_CANONICAL_TYPE(QualifiedName, Type)
-NON_CANONICAL_TYPE(InjectedClassName, Type)
+DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
TYPE(ObjCInterface, Type)
TYPE(ObjCObjectPointer, Type)
@@ -105,6 +105,8 @@ LAST_TYPE(ObjCObjectPointer)
#ifdef LEAF_TYPE
LEAF_TYPE(Enum)
LEAF_TYPE(Builtin)
+LEAF_TYPE(Record)
+LEAF_TYPE(InjectedClassName)
LEAF_TYPE(ObjCInterface)
LEAF_TYPE(TemplateTypeParm)
#undef LEAF_TYPE
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 553f04d76aec..cad7e61d553c 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -17,56 +17,7 @@
#include <iterator>
#include "llvm/ADT/SmallVector.h"
-#include "clang/Basic/Specifiers.h"
-
-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;
-};
-}
+#include "clang/AST/DeclAccessPair.h"
namespace clang {
diff --git a/include/clang/AST/UsuallyTinyPtrVector.h b/include/clang/AST/UsuallyTinyPtrVector.h
new file mode 100644
index 000000000000..5ee40e05c956
--- /dev/null
+++ b/include/clang/AST/UsuallyTinyPtrVector.h
@@ -0,0 +1,105 @@
+//===-- UsuallyTinyPtrVector.h - Pointer vector class -----------*- 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 UsuallyTinyPtrVector class, which is a vector that
+// optimizes the case where there is only one element.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
+#define LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H
+
+#include <vector>
+
+namespace clang {
+
+/// \brief A vector class template that is optimized for storing a single
+/// pointer element.
+template<typename T>
+class UsuallyTinyPtrVector {
+ /// \brief Storage for the vector.
+ ///
+ /// When the low bit is zero, this is a T *. When the
+ /// low bit is one, this is a std::vector<T *> *.
+ mutable uintptr_t Storage;
+
+ typedef std::vector<T*> vector_type;
+
+public:
+ UsuallyTinyPtrVector() : Storage(0) { }
+ explicit UsuallyTinyPtrVector(T *Element)
+ : Storage(reinterpret_cast<uintptr_t>(Element)) { }
+
+ bool empty() const { return !Storage; }
+
+ typedef const T **iterator;
+ iterator begin() const;
+ iterator end() const;
+
+ void push_back(T *Method);
+ void Destroy();
+};
+
+template<typename T>
+typename UsuallyTinyPtrVector<T>::iterator
+UsuallyTinyPtrVector<T>::begin() const {
+ if ((Storage & 0x01) == 0)
+ return reinterpret_cast<iterator>(&Storage);
+
+ vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+ return &Vec->front();
+}
+
+
+template<typename T>
+typename UsuallyTinyPtrVector<T>::iterator
+UsuallyTinyPtrVector<T>::end() const {
+ if ((Storage & 0x01) == 0) {
+ if (Storage == 0)
+ return reinterpret_cast<iterator>(&Storage);
+
+ return reinterpret_cast<iterator>(&Storage) + 1;
+ }
+
+ vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+ return &Vec->front() + Vec->size();
+}
+
+template<typename T>
+void UsuallyTinyPtrVector<T>::push_back(T *Element) {
+ if (Storage == 0) {
+ // 0 -> 1 element.
+ Storage = reinterpret_cast<uintptr_t>(Element);
+ return;
+ }
+
+ vector_type *Vec;
+ if ((Storage & 0x01) == 0) {
+ // 1 -> 2 elements. Allocate a new vector and push the element into that
+ // vector.
+ Vec = new vector_type;
+ Vec->push_back(reinterpret_cast<T *>(Storage));
+ Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
+ } else
+ Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
+
+ // Add the new element to the vector.
+ Vec->push_back(Element);
+}
+
+template<typename T>
+void UsuallyTinyPtrVector<T>::Destroy() {
+ if (Storage & 0x01)
+ delete reinterpret_cast<vector_type *>(Storage & ~0x01);
+
+ Storage = 0;
+}
+
+}
+#endif
diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h
deleted file mode 100644
index a4e6d519a04f..000000000000
--- a/include/clang/Analysis/Support/Optional.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides Optional, a template class modeled in the spirit of
-// OCaml's 'opt' variant. The idea is to strongly type whether or not
-// a value can be optional.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL
-#define LLVM_CLANG_ANALYSIS_OPTIONAL
-
-namespace clang {
-
-template<typename T>
-class Optional {
- T x;
- unsigned hasVal : 1;
-public:
- 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; }
-};
-} //end clang namespace
-
-namespace llvm {
-
-template<typename T> struct simplify_type;
-
-template <typename T>
-struct simplify_type<const ::clang::Optional<T> > {
- typedef const T* SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::Optional<T> &Val) {
- return Val.getPointer();
- }
-};
-
-template <typename T>
-struct simplify_type< ::clang::Optional<T> >
- : public simplify_type<const ::clang::Optional<T> > {};
-} // end llvm namespace
-
-#endif
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 453f660c360a..b306954975f4 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -314,6 +314,7 @@ BUILTIN(__builtin_setjmp, "iv**", "")
BUILTIN(__builtin_longjmp, "vv**i", "r")
BUILTIN(__builtin_unwind_init, "v", "")
BUILTIN(__builtin_eh_return_data_regno, "ii", "nc")
+BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:")
BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
// GCC exception builtins
@@ -335,6 +336,7 @@ BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
+BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:")
BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:")
BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:")
@@ -346,12 +348,9 @@ BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
BUILTIN(__builtin_expect, "LiLiLi" , "nc")
BUILTIN(__builtin_prefetch, "vvC*.", "nc")
-BUILTIN(__builtin_abort, "v", "Fnr")
BUILTIN(__builtin_trap, "v", "nr")
BUILTIN(__builtin_unreachable, "v", "nr")
-
BUILTIN(__builtin_shufflevector, "v." , "nc")
-
BUILTIN(__builtin_alloca, "v*z" , "n")
// "Overloaded" Atomic operator builtins. These are overloaded to support data
@@ -473,6 +472,13 @@ BUILTIN(__sync_fetch_and_max, "ii*i", "n")
BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n")
BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n")
+// Random libc builtins.
+BUILTIN(__builtin_abort, "v", "Fnr")
+BUILTIN(__builtin_index, "c*cC*i", "Fn")
+BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
+
+
+
// C99 library functions
// C99 stdlib.h
LIBBUILTIN(abort, "v", "fr", "stdlib.h")
diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index 817a032d9237..287bba96df25 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -18,7 +18,97 @@
// The format of this database matches clang/Basic/Builtins.def.
// This is just a placeholder, the types and attributes are wrong.
-BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc")
+BUILTIN(__builtin_altivec_abs_v16qi, "V16UcV16Sc", "")
+BUILTIN(__builtin_altivec_abs_v8hi, "V8UsV8Ss", "")
+BUILTIN(__builtin_altivec_abs_v4si, "V4UiV4Si", "")
+
+BUILTIN(__builtin_altivec_abss_v16qi, "V16UcV16Sc", "")
+BUILTIN(__builtin_altivec_abss_v8hi, "V8UsV8Ss", "")
+BUILTIN(__builtin_altivec_abss_v4si, "V4UiV4Si", "")
+
+BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "")
+
+BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "")
+
+BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "")
+
+BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "")
+
+BUILTIN(__builtin_altivec_stvx, "vV4iiv*", "")
+BUILTIN(__builtin_altivec_stvxl, "vV4iiv*", "")
+BUILTIN(__builtin_altivec_stvebx, "vV16civ*", "")
+BUILTIN(__builtin_altivec_stvehx, "vV8siv*", "")
+BUILTIN(__builtin_altivec_stvewx, "vV4iiv*", "")
+
+BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "")
+BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "")
+BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "")
+BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "")
+BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "")
+BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "")
+
+BUILTIN(__builtin_altivec_mfvscr, "V8Us", "")
+
+BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "")
+BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "")
+
+BUILTIN(__builtin_altivec_mtvscr, "vV4i", "")
+
+BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "")
+BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "")
+BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "")
+BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "")
+
+BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "")
+BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "")
+BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "")
+BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "")
+BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "")
+BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "")
+BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "")
+
// FIXME: Obviously incomplete.
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 5c75d3799bcb..a878dd1bd1a3 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -245,7 +245,7 @@ BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "")
BUILTIN(__builtin_ia32_mwait, "vUiUi", "")
BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "")
BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cc", "")
-BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLic", "")
+BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cc", "")
BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "")
BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "")
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 57dd6967fc51..bf94af6cb60d 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -188,6 +188,9 @@ private:
bool ErrorsAsFatal; // Treat errors like fatal errors.
bool SuppressSystemWarnings; // Suppress warnings in system headers.
bool SuppressAllDiagnostics; // Suppress all diagnostics.
+ unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit.
+ unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack,
+ // 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
DiagnosticClient *Client;
@@ -211,9 +214,10 @@ private:
/// diagnostic that they follow.
Diagnostic::Level LastDiagLevel;
- unsigned NumDiagnostics; // Number of diagnostics reported
- unsigned NumErrors; // Number of diagnostics that are errors
-
+ unsigned NumWarnings; // Number of warnings reported
+ unsigned NumErrors; // Number of errors reported
+ unsigned NumErrorsSuppressed; // Number of errors suppressed
+
/// CustomDiagInfo - Information for uniquing and looking up custom diags.
diag::CustomDiagInfo *CustomDiagInfo;
@@ -270,6 +274,22 @@ public:
void setClient(DiagnosticClient* client) { Client = client; }
+ /// setErrorLimit - Specify a limit for the number of errors we should
+ /// emit before giving up. Zero disables the limit.
+ void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; }
+
+ /// \brief Specify the maximum number of template instantiation
+ /// notes to emit along with a given diagnostic.
+ void setTemplateBacktraceLimit(unsigned Limit) {
+ TemplateBacktraceLimit = Limit;
+ }
+
+ /// \brief Retrieve the maximum number of template instantiation
+ /// nodes to emit along with a given diagnostic.
+ unsigned getTemplateBacktraceLimit() const {
+ return TemplateBacktraceLimit;
+ }
+
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
@@ -324,8 +344,9 @@ public:
void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
- assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) &&
- "Cannot map errors!");
+ assert((isBuiltinWarningOrExtension(Diag) ||
+ (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
+ "Cannot map errors into warnings!");
setDiagnosticMappingInternal(Diag, Map, true);
}
@@ -338,7 +359,8 @@ public:
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
unsigned getNumErrors() const { return NumErrors; }
- unsigned getNumDiagnostics() const { return NumDiagnostics; }
+ unsigned getNumErrorsSuppressed() const { return NumErrorsSuppressed; }
+ unsigned getNumWarnings() const { return NumWarnings; }
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnosic, it is
@@ -383,7 +405,18 @@ public:
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
/// ID is for an extension of some sort.
///
- static bool isBuiltinExtensionDiag(unsigned DiagID);
+ static bool isBuiltinExtensionDiag(unsigned DiagID) {
+ bool ignored;
+ return isBuiltinExtensionDiag(DiagID, ignored);
+ }
+
+ /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
+ /// ID is for an extension of some sort. This also returns EnabledByDefault,
+ /// which is set to indicate whether the diagnostic is ignored by default (in
+ /// which case -pedantic enables it) or treated as a warning/error by default.
+ ///
+ static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
+
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
@@ -473,7 +506,7 @@ private:
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
/// specified builtin diagnostic. This returns the high bit encoding, or zero
/// if the field is completely uninitialized.
- unsigned getDiagnosticMappingInfo(diag::kind Diag) const {
+ diag::Mapping getDiagnosticMappingInfo(diag::kind Diag) const {
const DiagMappings &currentMappings = DiagMappingsStack.back();
return (diag::Mapping)((currentMappings[Diag/2] >> (Diag & 1)*4) & 15);
}
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 8e791c3422fc..88e7dc19aec5 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -13,6 +13,11 @@
let Component = "Common" in {
+// Basic.
+
+def fatal_too_many_errors
+ : Error<"too many errors emitted, stopping now">, DefaultFatal;
+
def note_previous_definition : Note<"previous definition is here">;
def note_previous_declaration : Note<"previous declaration is here">;
def note_previous_implicit_declaration : Note<
@@ -36,7 +41,7 @@ def err_expected_colon_after_setter_name : Error<
"must end with ':'">;
// Parse && Sema
-def err_no_declarators : Error<"declaration does not declare anything">;
+def ext_no_declarators : ExtWarn<"declaration does not declare anything">;
def err_param_redefinition : Error<"redefinition of parameter %0">;
def err_invalid_storage_class_in_func_decl : Error<
"invalid storage class specifier in function declarator">;
@@ -67,5 +72,6 @@ def err_target_invalid_feature : Error<"invalid target feature '%0'">;
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
def err_file_modified : Error<
"file '%0' modified since it was first processed">, DefaultFatal;
-
+def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but "
+ "encoding is not supported">, DefaultFatal;
}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 3dbe47f4cf54..3b7272e5acc5 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -94,5 +94,7 @@ def warn_drv_conflicting_deployment_targets : Warning<
def warn_drv_treating_input_as_cxx : Warning<
"treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">,
InGroup<Deprecated>;
+def warn_drv_objc_gc_unsupported : Warning<
+ "Objective-C garbage collection is not supported on this platform, ignoring '%0'">;
}
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 2e0b4bad6b5b..b73103067017 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -14,7 +14,10 @@ def err_fe_error_reading : Error<"error reading '%0'">;
def err_fe_error_reading_stdin : Error<"error reading stdin">;
def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
-def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal;
+def err_fe_invalid_ast_action : Error<"invalid action for AST input">,
+ DefaultFatal;
+def err_fe_inline_asm : Error<"%0">; // Error generated by the backend.
+def note_fe_inline_asm_here : Note<"generated from here">;
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">,
@@ -69,12 +72,12 @@ def err_fe_pth_file_has_no_source_header : Error<
def warn_fe_macro_contains_embedded_newline : Warning<
"macro '%0' contains embedded newline, text after the newline is ignored.">;
-def err_verify_bogus_characters : Error<
- "bogus characters before '{{' in expected string">;
def err_verify_missing_start : Error<
- "cannot find start ('{{') of expected string">;
+ "cannot find start ('{{') of expected %0">;
def err_verify_missing_end : Error<
- "cannot find end ('}}') of expected string">;
+ "cannot find end ('}}') of expected %0">;
+def err_verify_invalid_content : Error<
+ "invalid expected %0: %1">;
def err_verify_inconsistent_diags : Error<
"'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: %2">;
@@ -120,12 +123,18 @@ 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_no_constant_cfstrings : Error<
+ "Objctive-C NSstring generation support was %select{disabled|enabled}0 "
+ "in PCH file but currently %select{disabled|enabled}1">;
def warn_pch_extensions : Error<
"extensions were %select{enabled|disabled}0 in PCH file but are "
"currently %select{enabled|disabled}1">;
def warn_pch_gnu_extensions : Error<
"GNU extensions were %select{disabled|enabled}0 in PCH file but are "
"currently %select{disabled|enabled}1">;
+def warn_pch_gnu_keywords : Error<
+ "GNU keywords were %select{disabled|enabled}0 in PCH file but are "
+ "currently %select{disabled|enabled}1">;
def warn_pch_microsoft_extensions : Error<
"Microsoft extensions were %select{disabled|enabled}0 in PCH file but are "
"currently %select{disabled|enabled}1">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index b0c016bbfd28..c74a48c445fe 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -108,6 +108,7 @@ def : DiagGroup<"type-limits">;
def Uninitialized : DiagGroup<"uninitialized">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
def UnusedArgument : DiagGroup<"unused-argument">;
+def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnusedFunction : DiagGroup<"unused-function">;
def UnusedLabel : DiagGroup<"unused-label">;
def UnusedParameter : DiagGroup<"unused-parameter">;
@@ -138,7 +139,8 @@ def Conversion : DiagGroup<"conversion",
def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
- UnusedParameter, UnusedValue, UnusedVariable]>;
+ // UnusedParameter, (matches GCC's behavior)
+ UnusedValue, UnusedVariable]>;
// Format settings.
def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>;
@@ -156,23 +158,22 @@ def Extra : DiagGroup<"extra", [
]>;
def Most : DiagGroup<"most", [
+ CharSubscript,
Comment,
Format,
Implicit,
MismatchedTags,
MissingBraces,
MultiChar,
+ Reorder,
ReturnType,
Switch,
Trigraphs,
Uninitialized,
UnknownPragmas,
- UnusedValue,
- UnusedVariable,
+ Unused,
VectorConversions,
- VolatileRegisterVar,
- Reorder,
- CharSubscript
+ VolatileRegisterVar
]>;
// -Wall is -Wmost -Wparentheses
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3e0956fb9460..27958515462a 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -190,7 +190,9 @@ def err_objc_missing_end : Error<"missing @end">;
def warn_objc_protocol_qualifier_missing_id : Warning<
"protocol qualifiers without 'id' is archaic">;
def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
-
+def err_illegal_super_cast : Error<
+ "cannot cast 'super' (it isn't an expression)">;
+
def err_objc_illegal_visibility_spec : Error<
"illegal visibility specification">;
def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b66d6cc6e5a3..93ab85806540 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -85,6 +85,8 @@ def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,
InGroup<UnusedVariable>, DefaultIgnore;
+def warn_unused_exception_param : Warning<"unused exception parameter %0">,
+ InGroup<UnusedExceptionParameter>, 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<
@@ -215,7 +217,8 @@ def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">;
def err_statically_allocated_object : Error<
"interface type cannot be statically allocated">;
def err_object_cannot_be_passed_returned_by_value : Error<
- "interface type %1 cannot be %select{returned|passed}0 by value">;
+ "interface type %1 cannot be %select{returned|passed}0 by value"
+ "; did you forget * in %1">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
def warn_pragma_pack_invalid_alignment : Warning<
"expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">;
@@ -237,6 +240,8 @@ def err_duplicate_class_def : Error<
"duplicate interface definition for class %0">;
def err_undef_superclass : Error<
"cannot find interface declaration for %0, superclass of %1">;
+def err_no_nsconstant_string_class : Error<
+ "cannot find interface declaration for %0">;
def err_recursive_superclass : Error<
"trying to recursively use %0 as superclass of %1">;
def warn_previous_alias_decl : Warning<"previously declared alias is ignored">;
@@ -296,7 +301,7 @@ def warn_implements_nscopying : Warning<
def warn_multiple_method_decl : Warning<"multiple methods named %0 found">;
def warn_accessor_property_type_mismatch : Warning<
"type of property %0 does not match type of accessor %1">;
-def note_declared_at : Note<"declared at">;
+def note_declared_at : Note<"declared here">;
def err_setter_type_void : Error<"type of setter must be void">;
def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
def warn_missing_atend : Warning<"'@end' is missing in implementation context">;
@@ -322,8 +327,8 @@ def warn_atomic_property_rule : Warning<
"writable atomic property %0 cannot pair a synthesized setter/getter "
"with a user defined setter/getter">;
def err_use_continuation_class : Error<
- "property declaration in continuation class of %0 is to change a 'readonly' "
- "property to 'readwrite'">;
+ "illegal declaration of property in continuation class %0"
+ ": attribute must be readwrite, while its primary must be readonly">;
def err_continuation_class : Error<"continuation class has no primary class">;
def err_property_type : Error<"property cannot have array or function type %0">;
def error_missing_property_context : Error<
@@ -381,11 +386,13 @@ def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
-def err_enum_friend : Error<
- "enum types cannot be friends">;
+def ext_enum_friend : ExtWarn<
+ "enumeration type %0 cannot be a friend">;
+def ext_nonclass_type_friend : ExtWarn<
+ "non-class type %0 cannot be a friend">;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
-def err_unelaborated_friend_type : Error<
+def ext_unelaborated_friend_type : ExtWarn<
"must specify '%select{struct|union|class|enum}0' to befriend %1">;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
@@ -399,6 +406,9 @@ def err_abstract_type_in_decl : Error<
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
"allocation of an object of abstract type %0">;
+def err_throw_abstract_type : Error<
+ "cannot throw an object of abstract type %0">;
+def err_array_of_abstract_type : Error<"array of abstract class type %0">;
def err_multiple_final_overriders : Error<
"virtual function %q0 has more than one final overrider in %1">;
@@ -448,11 +458,20 @@ def warn_missing_exception_specification : Warning<
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
-def err_access :
- Error<"%1 is a %select{private|protected}0 member of %3">,
- NoSFINAE;
-def err_access_ctor :
- Error<"calling a %select{private|protected}0 constructor of class %2">,
+def err_access : Error<
+ "%1 is a %select{private|protected}0 member of %3">, NoSFINAE;
+def err_access_ctor : Error<
+ "calling a %select{private|protected}0 constructor of class %2">, NoSFINAE;
+def err_access_base : Error<
+ "%select{base class|inherited virtual base class}0 %1 has %select{private|"
+ "protected}3 %select{constructor|copy constructor|copy assignment operator|"
+ "destructor}2">, NoSFINAE;
+def err_access_field: Error<
+ "field of type %0 has %select{private|protected}2 %select{constructor|copy "
+ "constructor|copy assignment operator|destructor}1">, NoSFINAE;
+
+def err_access_ctor_field :
+ Error<"field of type %1 has %select{private|protected}2 constructor">,
NoSFINAE;
def err_access_dtor_base :
Error<"base class %0 has %select{private|protected}1 destructor">,
@@ -461,6 +480,9 @@ def err_access_dtor_vbase :
Error<"inherited virtual base class %0 has "
"%select{private|protected}1 destructor">,
NoSFINAE;
+def err_access_dtor_temp :
+ Error<"temporary of type %0 has %select{private|protected}1 destructor">,
+ NoSFINAE;
def err_access_dtor_field :
Error<"field of type %1 has %select{private|protected}2 destructor">,
NoSFINAE;
@@ -494,6 +516,9 @@ def note_access_constrained_by_path : Note<
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
+def err_dependent_nested_name_spec : Error<
+ "nested name specifier for a declaration cannot depend on a template "
+ "parameter">;
def err_nested_name_member_ref_lookup_ambiguous : Error<
"lookup of %0 in member access expression is ambiguous">;
def note_ambig_member_ref_object_type : Note<
@@ -542,6 +567,8 @@ def err_non_virtual_pure : Error<
def err_implicit_object_parameter_init : Error<
"cannot initialize object parameter of type %0 with an expression "
"of type %1">;
+def err_qualified_member_of_unrelated : Error<
+ "%q0 is not a member of class %1">;
def note_field_decl : Note<"member is declared here">;
def note_ivar_decl : Note<"ivar is declared here">;
@@ -592,6 +619,7 @@ def err_covariant_return_type_class_type_more_qualified : Error<
"return type of virtual function %0 is not covariant with the return type of "
"the function it overrides (class type %1 is more qualified than class "
"type %2">;
+
// C++ constructors
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
@@ -601,6 +629,11 @@ def err_constructor_return_type : Error<
def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
def err_constructor_byvalue_arg : Error<
"copy constructor must pass its first argument by reference">;
+def warn_no_constructor_for_refconst : Warning<
+ "%select{struct|union|class|enum}0 %1 does not declare any constructor to "
+ "initialize its non-modifiable members">;
+def note_refconst_member_not_initialized : Note<
+ "%select{const|reference}0 member %1 will never be initialized">;
// C++ destructors
def err_destructor_not_member : Error<
@@ -678,18 +711,23 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
InGroup<DiagGroup<"uninitialized">>;
def err_temp_copy_no_viable : Error<
- "no viable copy constructor %select{copying variable|copying parameter|"
+ "no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
- "element}0 of type %1">;
+ "element|allocating object|copying temporary|initializing base subobject|"
+ "initializing vector element}0 of type %1">;
def err_temp_copy_ambiguous : Error<
- "ambiguous copy constructor call when %select{copying variable|copying "
+ "ambiguous constructor call when %select{copying variable|copying "
"parameter|returning object|throwing object|copying member subobject|copying "
- "array element}0 of type %1">;
+ "array element|allocating object|copying temporary|initializing base subobject|"
+ "initializing vector element}0 of type %1">;
def err_temp_copy_deleted : Error<
"%select{copying variable|copying parameter|returning object|throwing "
- "object|copying member subobject|copying array element}0 of type %1 invokes "
- "deleted copy constructor">;
-
+ "object|copying member subobject|copying array element|allocating object|"
+ "copying temporary|initializing base subobject|initializing vector element}0 "
+ "of type %1 invokes deleted constructor">;
+def err_temp_copy_incomplete : Error<
+ "copying a temporary object of incomplete type %0">;
+
// C++0x decltype
def err_cannot_determine_declared_type_of_overloaded_function : Error<
"cannot determine the %select{type|declared type}0 of an overloaded "
@@ -1116,9 +1154,13 @@ def err_member_call_without_object : Error<
"call to non-static member function without an object argument">;
// C++ Address of Overloaded Function
+def err_addr_ovl_no_viable : Error<
+ "address of overloaded function %0 does not match required type %1">;
def err_addr_ovl_ambiguous : Error<
"address of overloaded function %0 is ambiguous">;
-
+def err_addr_ovl_not_func_ptrref : Error<
+ "address of overloaded function %0 cannot be converted to type %1">;
+
// C++ Template Declarations
def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
@@ -1178,6 +1220,8 @@ def err_template_decl_ref : Error<
"cannot refer to class template %0 without a template argument list">;
// C++ Template Argument Lists
+def err_template_missing_args : Error<
+ "use of class template %0 requires template arguments">;
def err_template_arg_list_different_arity : Error<
"%select{too few|too many}0 template arguments for "
"%select{class template|function template|template template parameter"
@@ -1231,9 +1275,6 @@ 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_unresolved_overloaded_function : Error<
- "overloaded function cannot be resolved to a non-type template parameter of "
- "type %0">;
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<
@@ -1414,7 +1455,10 @@ def note_prior_template_arg_substitution : Note<
" template parameter%1 %2">;
def note_template_default_arg_checking : Note<
"while checking a default template argument used here">;
-
+def note_instantiation_contexts_suppressed : Note<
+ "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
+ "see all)">;
+
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
def err_nested_name_spec_non_tag : Error<
@@ -1551,6 +1595,14 @@ def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_typedef : Error<
"typedef redefinition with different types (%0 vs %1)">;
+def err_tag_reference_non_tag : Error<
+ "elaborated type refers to %select{a non-tag type|a typedef|a template}0">;
+def err_tag_reference_conflict : Error<
+ "implicit declaration introduced by elaborated type conflicts with "
+ "%select{a declaration|a typedef|a template}0 of the same name">;
+def err_dependent_tag_decl : Error<
+ "%select{declaration|definition}0 of %select{struct|union|class|enum}1 "
+ "in a dependent scope">;
def err_tag_definition_of_typedef : Error<
"definition of type %0 conflicts with typedef of the same name">;
def err_conflicting_types : Error<"conflicting types for %0">;
@@ -1641,6 +1693,8 @@ def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">;
def err_illegal_initializer : Error<
"illegal initializer (only variables can be initialized)">;
def err_illegal_initializer_type : Error<"illegal initializer type %0">;
+def err_init_objc_class : Error<
+ "cannot initialize Objective-C class type %0">;
def err_implicit_empty_initializer : Error<
"initializer for aggregate with no elements requires explicit braces">;
def err_bitfield_has_negative_width : Error<
@@ -1649,9 +1703,18 @@ def err_anon_bitfield_has_negative_width : Error<
"anonymous bit-field has negative width (%0)">;
def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">;
def err_bitfield_width_exceeds_type_size : Error<
- "size of bit-field %0 exceeds size of its type (%1 bits)">;
+ "size of bit-field %0 (%1 bits) exceeds size of its type (%2 bits)">;
def err_anon_bitfield_width_exceeds_type_size : Error<
- "size of anonymous bit-field exceeds size of its type (%0 bits)">;
+ "size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">;
+
+// Used by C++ which allows bit-fields that are wider than the type.
+def warn_bitfield_width_exceeds_type_size: Warning<
+ "size of bit-field %0 (%1 bits) exceeds the size of its type; value will be "
+ "truncated to %2 bits">;
+def warn_anon_bitfield_width_exceeds_type_size : Warning<
+ "size of anonymous bit-field (%0 bits) exceeds size of its type; value will "
+ "be truncated to %1 bits">;
+
def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
InGroup<DiagGroup<"missing-braces">>, DefaultIgnore;
@@ -1758,6 +1821,7 @@ def ext_offsetof_extended_field_designator : Extension<
"using extended field designator is an extension">;
def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">,
InGroup<InvalidOffsetof>;
+def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
@@ -1773,6 +1837,8 @@ def warn_precedence_bitwise_rel : Warning<
InGroup<Parentheses>;
def note_precedence_bitwise_first : Note<
"place parentheses around the %0 expression to evaluate it first">;
+def note_precedence_bitwise_silence : Note<
+ "place parentheses around the %0 expression to silence this warning">;
def err_sizeof_nonfragile_interface : Error<
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
@@ -1807,9 +1873,9 @@ def err_typecheck_member_reference_arrow : Error<
def err_typecheck_member_reference_suggestion : Error<
"member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">;
def err_typecheck_member_reference_type : Error<
- "cannot refer to type member %0 with '%select{.|->}1'">;
+ "cannot refer to type member %0 in %1 with '%select{.|->}2'">;
def err_typecheck_member_reference_unknown : Error<
- "cannot refer to member %0 with '%select{.|->}1'">;
+ "cannot refer to member %0 in %1 with '%select{.|->}2'">;
def err_member_reference_needs_call : Error<
"base of member reference has function type %0; perhaps you meant to call "
"this function with '()'?">;
@@ -1835,6 +1901,8 @@ def err_out_of_line_declaration : Error<
def note_member_def_close_match : Note<"member declaration nearly matches">;
def err_typecheck_ivar_variable_size : Error<
"instance variables must have a constant size">;
+def err_ivar_reference_type : Error<
+ "instance variables cannot be of reference type">;
def err_typecheck_illegal_increment_decrement : Error<
"cannot %select{decrement|increment}1 value of type %0">;
def err_typecheck_arithmetic_incomplete_type : Error<
@@ -2003,10 +2071,16 @@ def error_no_super_class : Error<
"no super class declared in @interface for %0">;
def err_invalid_receiver_to_message : Error<
"invalid receiver to message expression">;
+def err_invalid_receiver_to_message_super : Error<
+ "'super' is only valid in a method body">;
+def err_invalid_receiver_class_message : Error<
+ "receiver type %0 is not an Objective-C class">;
def warn_bad_receiver_type : Warning<
"receiver type %0 is not 'id' or interface pointer, consider "
"casting it to 'id'">;
def err_bad_receiver_type : Error<"bad receiver type %0">;
+def err_unknown_receiver_suggest : Error<
+ "unknown receiver %0; did you mean %1?">;
def error_objc_throw_expects_object : Error<
"@throw requires an Objective-C object type (%0 invalid)">;
def error_objc_synchronized_expects_object : Error<
@@ -2019,8 +2093,15 @@ def err_catch_param_not_objc_type : Error<
"@catch parameter is not a pointer to an interface type">;
def err_illegal_qualifiers_on_catch_parm : Error<
"illegal qualifiers on @catch parameter">;
-def err_illegal_super_cast : Error<
- "cannot cast 'super' (it isn't an expression)">;
+def err_storage_spec_on_catch_parm : Error<
+ "@catch parameter cannot have storage specifier %select{|'typedef'|'extern'|"
+ "'static'|'auto'|'register'|'__private_extern__'|'mutable'}0">;
+def warn_register_objc_catch_parm : Warning<
+ "'register' storage specifier on @catch parameter will be ignored">;
+def err_qualified_objc_catch_parm : Error<
+ "@catch parameter declarator cannot be qualified">;
+
+
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
"use @synthesize, @dynamic or provide a method implementation">;
@@ -2029,7 +2110,10 @@ def warn_setter_getter_impl_required_in_category : Warning<
"use @dynamic or provide a method implementation in category">;
def note_property_impl_required : Note<
"implementation is here">;
-
+def note_parameter_named_here : Note<
+ "passing argument to parameter %0 here">;
+def note_parameter_here : Note<
+ "passing argument to parameter here">;
// C++ casts
// These messages adhere to the TryCast pattern: %0 is an int specifying the
@@ -2099,6 +2183,8 @@ def err_new_incomplete_type : Error<
"allocation of incomplete type %0">;
def err_new_array_nonconst : Error<
"only the first dimension of an allocated array may have dynamic size">;
+def err_new_array_init_args : Error<
+ "array 'new' cannot have initialization arguments">;
def err_new_paren_array_nonconst : Error<
"when type is in parentheses, array cannot have dynamic size">;
def err_placement_new_non_placement_delete : Error<
@@ -2116,8 +2202,8 @@ def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behaviour">;
def err_no_suitable_delete_member_function_found : Error<
"no suitable member %0 in %1">;
-def note_delete_member_function_declared_here : Note<
- "%0 declared here">;
+def note_member_declared_here : Note<
+ "member %0 declared here">;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated">, InGroup<Deprecated>;
@@ -2132,6 +2218,8 @@ def err_qualified_catch_declarator : Error<
def err_early_catch_all : Error<"catch-all handler must come last">;
def err_bad_memptr_rhs : Error<
"right hand operand to %0 has non pointer-to-member type %1">;
+def err_memptr_rhs_to_incomplete : Error<
+ "cannot dereference pointer into incomplete class type %0">;
def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;
@@ -2190,6 +2278,8 @@ def err_typecheck_deleted_function : Error<
"conversion function from %0 to %1 invokes a deleted function">;
def err_expected_class_or_namespace : Error<"expected a class or namespace">;
+def err_missing_qualified_for_redecl : Error<
+ "must qualify the name %0 to declare %q1 in this scope">;
def err_invalid_declarator_scope : Error<
"definition or redeclaration of %0 not in a namespace enclosing %1">;
def err_invalid_declarator_global_scope : Error<
@@ -2213,6 +2303,8 @@ def warn_condition_is_idiomatic_assignment : Warning<"using the result "
InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore;
def note_condition_assign_to_comparison : Note<
"use '==' to turn this assignment into an equality comparison">;
+def note_condition_assign_silence : Note<
+ "place parentheses around the assignment to silence this warning">;
def warn_value_always_zero : Warning<
"%0 is always %select{zero|false|NULL}1 in this context">;
@@ -2221,53 +2313,91 @@ def warn_value_always_zero : Warning<
// In most of these diagnostics the %2 is a value from the
// Sema::AssignmentAction enumeration
def err_typecheck_convert_incompatible : Error<
- "incompatible type %select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " %1, expected %0">;
-def err_typecheck_convert_ambiguous : Error<
- "ambiguity in initializing value of type %0 with initializer of type %1">;
-def err_cannot_initialize_decl_noname : Error<
- "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
- "of type %2">;
-def err_cannot_initialize_decl : Error<
- "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from incompatible type|to parameter of incompatible type|"
+ "from a function with incompatible result type|to incompatible type|"
+ "with an expression of incompatible type|to parameter of incompatible type|"
+ "to incompatible type}2 %1">;
def warn_incompatible_qualified_id : Warning<
- "incompatible type %select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " %1, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from incompatible type|to parameter of incompatible type|"
+ "from a function with incompatible result type|to incompatible type|"
+ "with an expression of incompatible type|to parameter of incompatible type|"
+ "to incompatible type}2 %1">;
def ext_typecheck_convert_pointer_int : ExtWarn<
"incompatible pointer to integer conversion "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">;
def ext_typecheck_convert_int_pointer : ExtWarn<
"incompatible integer to pointer conversion "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">;
def ext_typecheck_convert_pointer_void_func : Extension<
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " %1 converts between void* and function pointer, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1 "
+ "converts between void pointer and function pointer">;
def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn<
- "pointer types point to integer types with different sign "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">,
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1 "
+ "converts between pointers to integer types with different sign">,
InGroup<DiagGroup<"pointer-sign">>;
def ext_typecheck_convert_incompatible_pointer : ExtWarn<
"incompatible pointer types "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " %1 discards qualifiers, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1 discards "
+ "qualifiers">;
def ext_nested_pointer_qualifier_mismatch : ExtWarn<
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2,"
- " %0 and %1 have different qualifiers in nested pointer types">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1 discards "
+ "qualifiers in nested pointer types">;
def warn_incompatible_vectors : Warning<
- "incompatible vector types %select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " %1, expected %0">,
+ "incompatible vector types "
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">,
InGroup<VectorConversions>, DefaultIgnore;
def err_int_to_block_pointer : Error<
- "invalid conversion "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2"
- " integer %1, expected block pointer %0">;
-def err_typecheck_comparison_of_distinct_blocks : Error<
- "comparison of distinct block types (%0 and %1)">;
+ "invalid block pointer conversion "
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">;
def err_typecheck_convert_incompatible_block_pointer : Error<
"incompatible block pointer types "
- "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">;
+ "%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
+ " %0 "
+ "%select{from|to parameter of type|from a function with result type|to type|"
+ "with an expression of type|to parameter of type|to type}2 %1">;
+
+def err_typecheck_convert_ambiguous : Error<
+ "ambiguity in initializing value of type %0 with initializer of type %1">;
+def err_cannot_initialize_decl_noname : Error<
+ "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 "
+ "of type %2">;
+def err_cannot_initialize_decl : Error<
+ "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">;
+def err_typecheck_comparison_of_distinct_blocks : Error<
+ "comparison of distinct block types (%0 and %1)">;
def err_typecheck_array_not_modifiable_lvalue : Error<
"array type %0 is not assignable">;
@@ -2295,9 +2425,17 @@ def note_function_with_incomplete_return_type_declared_here : Note<
def err_call_incomplete_argument : Error<
"argument type %0 is incomplete">;
def err_typecheck_call_too_few_args : Error<
- "too few arguments to %select{function|block|method}0 call">;
+ "too few arguments to %select{function|block|method}0 call, "
+ "expected %1, have %2">;
+def err_typecheck_call_too_few_args_at_least : Error<
+ "too few arguments to %select{function|block|method}0 call, "
+ "expected at least %1, have %2">;
def err_typecheck_call_too_many_args : Error<
- "too many arguments to %select{function|block|method}0 call">;
+ "too many arguments to %select{function|block|method}0 call, "
+ "expected %1, have %2">;
+def err_typecheck_call_too_many_args_at_most : Error<
+ "too many arguments to %select{function|block|method}0 call, "
+ "expected at most %1, have %2">;
def warn_call_wrong_number_of_arguments : Warning<
"too %select{few|many}0 arguments in call to %1">;
def err_atomic_builtin_must_be_pointer : Error<
@@ -2359,8 +2497,11 @@ def ext_typecheck_expression_not_constant_but_accepted : Extension<
InGroup<GNU>;
def warn_unused_expr : Warning<"expression result unused">,
InGroup<UnusedValue>;
+def warn_unused_voidptr : Warning<
+ "expression result unused; should this cast be to 'void'?">,
+ InGroup<UnusedValue>;
def warn_unused_property_expr : Warning<
- "property access result unused - getters should not have side effects">,
+ "property access result unused - getters should not be used for side effects">,
InGroup<UnusedValue>;
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
@@ -2412,24 +2553,21 @@ def err_overload_incorrect_fntype : Error<
def err_only_constructors_take_base_inits : Error<
"only constructors take base initializers">;
-def error_multiple_mem_initialization : Error <
- "multiple initializations given for non-static member '%0'">;
-
-def error_multiple_base_initialization : Error <
+def err_multiple_mem_initialization : Error <
+ "multiple initializations given for non-static member %0">;
+def err_multiple_mem_union_initialization : Error <
+ "initializing multiple members of anonymous union">;
+def err_multiple_base_initialization : Error <
"multiple initializations given for base %0">;
def err_mem_init_not_member_or_class : Error<
"member initializer %0 does not name a non-static data member or base "
"class">;
-def warn_field_initialized : Warning<
- "member '%0' will be initialized after">,
- InGroup<Reorder>, DefaultIgnore;
-def warn_base_initialized : Warning<
- "base class %0 will be initialized after">,
+def warn_initializer_out_of_order : Warning<
+ "%select{field|base class}0 %1 will be initialized after "
+ "%select{field|base}2 %3">,
InGroup<Reorder>, DefaultIgnore;
-def note_fieldorbase_initialized_here : Note<
- "%select{field|base}0 %1">;
def err_base_init_does_not_name_class : Error<
"constructor initializer %0 does not name a class">;
@@ -2437,9 +2575,7 @@ def err_base_init_direct_and_virtual : Error<
"base class initializer %0 names both a direct base class and an "
"inherited virtual base class">;
def err_not_direct_base_or_virtual : Error<
- "type %0 is not a direct or virtual base of '%1'">;
-def err_not_direct_base_or_virtual_multi : Error<
- "type %0 is not a direct or virtual base of '%1'">;
+ "type %0 is not a direct or virtual base of %1">;
def err_in_class_initializer_non_integral_type : Error<
"in-class initializer has non-integral, non-enumeration type %0">;
@@ -2587,6 +2723,8 @@ def err_conv_function_to_array : Error<
"conversion function cannot convert to an array type">;
def err_conv_function_to_function : Error<
"conversion function cannot convert to a function type">;
+def err_conv_function_with_complex_decl : Error<
+ "must use a typedef to declare a conversion to %0">;
def err_conv_function_redeclared : Error<
"conversion function cannot be redeclared">;
def warn_conv_to_self_not_used : Warning<
@@ -2669,7 +2807,7 @@ def warn_selfcomparison : Warning<
"self-comparison always results in a constant value">;
def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
- "unspecified (use strcmp instead)">;
+ "unspecified (use strncmp instead)">;
@@ -2698,7 +2836,7 @@ def err_default_not_in_switch : Error<
"'default' statement not in switch statement">;
def err_case_not_in_switch : Error<"'case' statement not in switch statement">;
def warn_bool_switch_condition : Warning<
- "switch condition is a bool">;
+ "switch condition has boolean value">;
def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">,
InGroup<DiagGroup<"switch">>;
@@ -2770,22 +2908,15 @@ def err_vector_incorrect_num_initializers : Error<
"%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">;
def err_altivec_empty_initializer : Error<"expected initializer">;
-def err_stack_const_level : Error<
- "level argument for a stack address builtin must be constant">;
-
-def err_prefetch_invalid_arg_type : Error<
- "argument to __builtin_prefetch must be of integer type">;
-def err_prefetch_invalid_arg_ice : Error<
- "argument to __builtin_prefetch must be a constant integer">;
def err_argument_invalid_range : Error<
"argument should be a value from %0 to %1">;
-def err_object_size_invalid_argument : Error<
- "argument to __builtin_object_size must be a constant integer">;
-
def err_builtin_longjmp_invalid_val : Error<
"argument to __builtin_longjmp must be a constant 1">;
+def err_constant_integer_arg_type : Error<
+ "argument to %0 must be a constant integer">;
+
def ext_mixed_decls_code : Extension<
"ISO C90 forbids mixing declarations and code">;
def err_non_variable_decl_in_for : Error<
@@ -2834,9 +2965,9 @@ def warn_ivar_use_hidden : Warning<
def error_ivar_use_in_class_method : Error<
"instance variable %0 accessed in class method">;
def error_private_ivar_access : Error<"instance variable %0 is private">,
- NoSFINAE;
+ NoSFINAE;
def error_protected_ivar_access : Error<"instance variable %0 is protected">,
- NoSFINAE;
+ NoSFINAE;
def warn_maynot_respond : Warning<"%0 may not respond to %1">;
def warn_attribute_method_def : Warning<
"method attribute can only be specified on method declarations">;
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index fdf69d063f4d..1ed86f190af3 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -28,6 +28,7 @@ public:
unsigned DollarIdents : 1; // '$' allowed in identifiers.
unsigned AsmPreprocessor : 1; // Preprocessor in asm mode.
unsigned GNUMode : 1; // True in gnu99 mode false in c99 mode (etc)
+ unsigned GNUKeywords : 1; // True if GNU-only keywords are allowed
unsigned ImplicitInt : 1; // C89 implicit 'int'.
unsigned Digraphs : 1; // C94, C99 and C++
unsigned HexFloats : 1; // C99 Hexadecimal float constants.
@@ -98,8 +99,13 @@ public:
unsigned ElideConstructors : 1; // Whether C++ copy constructors should be
// elided if possible.
unsigned CatchUndefined : 1; // Generate code to check for undefined ops.
- unsigned DumpVtableLayouts : 1; // Dump the layouts of all the emitted
- // vtables.
+ unsigned DumpRecordLayouts : 1; /// Dump the layout of IRgen'd records.
+ unsigned DumpVTableLayouts : 1; /// Dump the layouts of emitted vtables.
+ unsigned NoConstantCFStrings : 1; // Do not do CF strings
+
+ // FIXME: This is just a temporary option, for testing purposes.
+ unsigned NoBitFieldTypeAlign : 1;
+
private:
unsigned GC : 2; // Objective-C Garbage Collection modes. We
// declare this enum as unsigned because MSVC
@@ -126,9 +132,10 @@ public:
LangOptions() {
Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
- GNUMode = ImplicitInt = Digraphs = 0;
+ GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0;
HexFloats = 0;
GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
+ NoConstantCFStrings = 0;
C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0;
CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;
Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0;
@@ -155,7 +162,7 @@ public:
OverflowChecking = 0;
ObjCGCBitmapPrint = 0;
- InstantiationDepth = 500;
+ InstantiationDepth = 1024;
Optimize = 0;
OptimizeSize = 0;
@@ -169,7 +176,9 @@ public:
CharIsSigned = 1;
ShortWChar = 0;
CatchUndefined = 0;
- DumpVtableLayouts = 0;
+ DumpRecordLayouts = 0;
+ DumpVTableLayouts = 0;
+ NoBitFieldTypeAlign = 0;
}
GCMode getGCMode() const { return (GCMode) GC; }
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 555e6f5a919a..0bbeffefc725 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -176,19 +176,14 @@ public:
/// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful
/// for argument passing to functions that expect both objects.
class FullSourceLoc : public SourceLocation {
- SourceManager* SrcMgr;
+ const SourceManager *SrcMgr;
public:
/// Creates a FullSourceLoc where isValid() returns false.
- explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {}
+ explicit FullSourceLoc() : SrcMgr(0) {}
- explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM)
+ explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM)
: SourceLocation(Loc), SrcMgr(&SM) {}
- SourceManager &getManager() {
- assert(SrcMgr && "SourceManager is NULL.");
- return *SrcMgr;
- }
-
const SourceManager &getManager() const {
assert(SrcMgr && "SourceManager is NULL.");
return *SrcMgr;
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index d1239694fc16..930fb52873eb 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -78,8 +78,13 @@ namespace SrcMgr {
/// \param Diag Object through which diagnostics will be emitted it the
/// buffer cannot be retrieved.
///
+ /// \param Loc If specified, is the location that invalid file diagnostics
+ /// will be emitted at.
+ ///
/// \param Invalid If non-NULL, will be set \c true if an error occurred.
- const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag,
+ const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag,
+ const SourceManager &SM,
+ SourceLocation Loc = SourceLocation(),
bool *Invalid = 0) const;
/// getSize - Returns the size of the content encapsulated by this
@@ -447,11 +452,17 @@ public:
/// getBuffer - Return the buffer for the specified FileID. If there is an
/// error opening this buffer the first time, this manufactures a temporary
/// buffer and returns a non-empty error string.
- const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
- return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag,
- Invalid);
+ const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc,
+ bool *Invalid = 0) const {
+ return getSLocEntry(FID).getFile().getContentCache()
+ ->getBuffer(Diag, *this, Loc, Invalid);
}
+ const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
+ return getSLocEntry(FID).getFile().getContentCache()
+ ->getBuffer(Diag, *this, SourceLocation(), Invalid);
+ }
+
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
const FileEntry *getFileEntryForID(FileID FID) const {
return getSLocEntry(FID).getFile().getContentCache()->Entry;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index bc2cf198c3f5..19987508baf3 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -45,6 +45,7 @@ protected:
// Target values set by the ctor of the actual target implementation. Default
// values are specified by the TargetInfo constructor.
bool TLSSupported;
+ bool NoAsmVariants; // True if {|} are normal characters.
unsigned char PointerWidth, PointerAlign;
unsigned char IntWidth, IntAlign;
unsigned char FloatWidth, FloatAlign;
@@ -85,6 +86,14 @@ public:
protected:
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType;
+
+ /// Control whether the alignment of bit-field types is respected when laying
+ /// out structures. If true, then the alignment of the bit-field type will be
+ /// used to (a) impact the alignment of the containing structure, and (b)
+ /// ensure that the individual bit-field will not straddle an alignment
+ /// boundary.
+ unsigned UseBitFieldTypeAlignment : 1;
+
public:
IntType getSizeType() const { return SizeType; }
IntType getIntMaxType() const { return IntMaxType; }
@@ -197,6 +206,10 @@ public:
return UserLabelPrefix;
}
+ bool useBitFieldTypeAlignment() const {
+ return UseBitFieldTypeAlignment;
+ }
+
/// getTypeName - Return the user string for the specified integer type enum.
/// For example, SignedShort -> "short".
static const char *getTypeName(IntType T);
@@ -326,6 +339,18 @@ public:
return "__DATA,__cfstring";
}
+ /// getNSStringSection - Return the section to use for NSString
+ /// literals, or 0 if no special section is used.
+ virtual const char *getNSStringSection() const {
+ return "__OBJC,__cstring_object,regular,no_dead_strip";
+ }
+
+ /// getNSStringNonFragileABISection - Return the section to use for
+ /// NSString literals, or 0 if no special section is used (NonFragile ABI).
+ virtual const char *getNSStringNonFragileABISection() const {
+ return "__DATA, __objc_stringobj, regular, no_dead_strip";
+ }
+
/// isValidSectionSpecifier - This is an optional hook that targets can
/// implement to perform semantic checking on attribute((section("foo")))
/// specifiers. In this case, "foo" is passed in to be checked. If the
@@ -402,6 +427,15 @@ public:
return TLSSupported;
}
+ /// hasNoAsmVariants - Return true if {|} are normal characters in the
+ /// asm string. If this returns false (the default), then {abc|xyz} is syntax
+ /// that says that when compiling for asm variant #0, "abc" should be
+ /// generated, but when compiling for asm variant #1, "xyz" should be
+ /// generated.
+ bool hasNoAsmVariants() const {
+ return NoAsmVariants;
+ }
+
/// getEHDataRegisterNumber - Return the register number that
/// __builtin_eh_return_regno would return with the specified argument.
virtual int getEHDataRegisterNumber(unsigned RegNo) const {
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index 2e0993ab52a1..b3b61841a8c3 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -18,11 +18,11 @@
#include "llvm/ADT/StringRef.h"
/// \brief Clang major version
-#define CLANG_VERSION_MAJOR 1
+#define CLANG_VERSION_MAJOR 2
// FIXME: Updates to this file must also update CMakeLists.txt and VER.
/// \brief Clang minor version
-#define CLANG_VERSION_MINOR 5
+#define CLANG_VERSION_MINOR 0
/// \brief Clang patchlevel version
// #define CLANG_VERSION_PATCHLEVEL 1
diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h
index 617034292638..5b65d52a9a96 100644
--- a/include/clang/Checker/BugReporter/BugReporter.h
+++ b/include/clang/Checker/BugReporter/BugReporter.h
@@ -458,7 +458,6 @@ public:
namespace bugreporter {
const Stmt *GetDerefExpr(const ExplodedNode *N);
-const Stmt *GetReceiverExpr(const ExplodedNode *N);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetCalleeExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h
index fdf52a7dc770..0c59d7b572a4 100644
--- a/include/clang/Checker/PathSensitive/AnalysisManager.h
+++ b/include/clang/Checker/PathSensitive/AnalysisManager.h
@@ -37,6 +37,8 @@ class AnalysisManager : public BugReporterData {
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+ unsigned MaxNodes;
+
bool VisualizeEGDot;
bool VisualizeEGUbi;
bool PurgeDead;
@@ -55,12 +57,12 @@ public:
AnalysisManager(ASTContext &ctx, Diagnostic &diags,
const LangOptions &lang, PathDiagnosticClient *pd,
StoreManagerCreator storemgr,
- ConstraintManagerCreator constraintmgr,
+ ConstraintManagerCreator constraintmgr, unsigned maxnodes,
bool vizdot, bool vizubi, bool purge, bool eager, bool trim)
: Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
- AScope(ScopeDecl),
+ AScope(ScopeDecl), MaxNodes(maxnodes),
VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
EagerlyAssume(eager), TrimGraph(trim) {}
@@ -104,6 +106,8 @@ public:
PD->FlushDiagnostics();
}
+ unsigned getMaxNodes() const { return MaxNodes; }
+
bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
index a3ff0dbedc7b..2d8afeeb0da6 100644
--- a/include/clang/Checker/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -239,31 +239,7 @@ public:
}
ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
- const GRState* St, ProgramPoint::Kind K) {
-
- const GRState* PredState = GetState(Pred);
-
- // If the state hasn't changed, don't generate a new node.
- if (!BuildSinks && St == PredState && Auditor == 0) {
- Dst.Add(Pred);
- return NULL;
- }
-
- ExplodedNode* N = generateNode(S, St, Pred, K);
-
- if (N) {
- if (BuildSinks)
- N->markAsSink();
- else {
- if (Auditor && Auditor->Audit(N, Mgr))
- N->markAsSink();
-
- Dst.Add(N);
- }
- }
-
- return N;
- }
+ const GRState* St, ProgramPoint::Kind K);
ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S,
ExplodedNode* Pred, const GRState* St) {
@@ -273,7 +249,6 @@ public:
BuildSinks = Tmp;
return N;
}
-
};
class GRBranchNodeBuilder {
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 161cb28df033..f04ca75084b7 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -87,6 +87,15 @@ class GRExprEngine : public GRSubEngine {
llvm::OwningPtr<GRTransferFuncs> TF;
+ class CallExprWLItem {
+ public:
+ CallExpr::arg_iterator I;
+ ExplodedNode *N;
+
+ CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
+ : I(i), N(n) {}
+ };
+
public:
GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf);
@@ -333,6 +342,10 @@ public:
/// VisitReturnStmt - Transfer function logic for return statements.
void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitOffsetOfExpr - Transfer function for offsetof.
+ void VisitOffsetOfExpr(OffsetOfExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
/// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
@@ -352,6 +365,12 @@ public:
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ void VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -363,6 +382,11 @@ public:
const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD,
const StackFrameContext *SFC);
+ /// Evaluate arguments with a work list algorithm.
+ void EvalArguments(ExprIterator AI, ExprIterator AE,
+ const FunctionProtoType *FnType,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
index 57ea8a3f6d9d..2ab3b420c313 100644
--- a/include/clang/Checker/PathSensitive/MemRegion.h
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -869,11 +869,11 @@ public:
/// getElementRegion - Retrieve the memory region associated with the
/// associated element type, index, and super region.
const ElementRegion *getElementRegion(QualType elementType, SVal Idx,
- const MemRegion *superRegion,
- ASTContext &Ctx);
+ const MemRegion *superRegion,
+ ASTContext &Ctx);
const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
- const MemRegion *superRegion) {
+ const MemRegion *superRegion) {
return getElementRegion(ER->getElementType(), ER->getIndex(),
superRegion, ER->getContext());
}
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index 72565f4d740d..41d7c2bd713e 100644
--- a/include/clang/Checker/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -129,11 +129,14 @@ public:
CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
};
+ const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
+
/// CastRegion - Used by GRExprEngine::VisitCast to handle casts from
/// a MemRegion* to a specific location type. 'R' is the region being
/// casted and 'CastToTy' the result type of the cast.
const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
+
/// EvalBinOp - Perform pointer arithmetic.
virtual SVal EvalBinOp(BinaryOperator::Opcode Op,
Loc lhs, NonLoc rhs, QualType resultTy) {
diff --git a/include/clang/Checker/PathSensitive/ValueManager.h b/include/clang/Checker/PathSensitive/ValueManager.h
index f80ad421742f..5a9d54d337b0 100644
--- a/include/clang/Checker/PathSensitive/ValueManager.h
+++ b/include/clang/Checker/PathSensitive/ValueManager.h
@@ -22,6 +22,7 @@
#include "clang/Checker/PathSensitive/BasicValueFactory.h"
#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/SValuator.h"
+#include "clang/AST/ExprCXX.h"
namespace llvm { class BumpPtrAllocator; }
@@ -133,6 +134,11 @@ public:
I->getType()->isUnsignedIntegerType()));
}
+ nonloc::ConcreteInt makeIntVal(const CXXBoolLiteralExpr *E) {
+ return E->getValue() ? nonloc::ConcreteInt(BasicVals.getValue(1, 1, true))
+ : nonloc::ConcreteInt(BasicVals.getValue(0, 1, true));
+ }
+
nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
return nonloc::ConcreteInt(BasicVals.getValue(V));
}
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 638ed516ed0b..54d3ba03f3f0 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -28,10 +28,17 @@ public:
OnlyAlwaysInlining // Only run the always inlining pass.
};
+ enum ObjCDispatchMethodKind {
+ Legacy = 0,
+ NonLegacy = 1,
+ Mixed = 2
+ };
+
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
+ unsigned DataSections : 1; /// Set when -fdata-sections is enabled
unsigned DebugInfo : 1; /// Should generate deubg info (-g).
unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled.
unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in
@@ -39,12 +46,12 @@ public:
/// internal state before optimizations are
/// done.
unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled.
+ unsigned FunctionSections : 1; /// Set when -ffunction-sections is enabled
unsigned MergeAllConstants : 1; /// Merge identical constants.
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 ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use.
unsigned OptimizationLevel : 3; /// The -O[0-4] option specified.
unsigned OptimizeSize : 1; /// If -Os is specified.
unsigned SoftFloat : 1; /// -soft-float.
@@ -88,15 +95,17 @@ public:
AsmVerbose = 0;
CXAAtExit = 1;
CXXCtorDtorAliases = 0;
+ DataSections = 0;
DebugInfo = 0;
DisableFPElim = 0;
DisableLLVMOpts = 0;
DisableRedZone = 0;
+ FunctionSections = 0;
MergeAllConstants = 1;
NoCommon = 0;
NoImplicitFloat = 0;
NoZeroInitializedInBSS = 0;
- ObjCLegacyDispatch = 0;
+ ObjCDispatchMethod = Legacy;
OptimizationLevel = 0;
OptimizeSize = 0;
SoftFloat = 0;
@@ -109,6 +118,10 @@ public:
Inlining = NoInlining;
RelocationModel = "pic";
}
+
+ ObjCDispatchMethodKind getObjCDispatchMethod() const {
+ return ObjCDispatchMethodKind(ObjCDispatchMethod);
+ }
};
} // end namespace clang
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 124288a76305..18b54ef5e072 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -97,6 +97,8 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">,
HelpText<"Display exploded graph using GraphViz">;
def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">,
HelpText<"Display exploded graph using Ubigraph">;
+def analyzer_max_nodes : Separate<"-analyzer-max-nodes">,
+ HelpText<"The maximum number of nodes the analyzer can generate">;
//===----------------------------------------------------------------------===//
// CodeGen Options
@@ -123,6 +125,10 @@ 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 ffunction_sections : Flag<"-ffunction-sections">,
+ HelpText<"Place each function in its own section (ELF Only)">;
+def fdata_sections : Flag<"-fdata-sections">,
+ HelpText<"Place each data in its own section (ELF Only)">;
def masm_verbose : Flag<"-masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<"-mcode-model">,
@@ -192,6 +198,10 @@ def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
HelpText<"Print diagnostic name with mappable diagnostics">;
def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
HelpText<"Set the tab stop distance.">;
+def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
+def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">,
+ HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
@@ -235,8 +245,6 @@ def x : Separate<"-x">, HelpText<"Input language type">;
def cxx_inheritance_view : Separate<"-cxx-inheritance-view">,
MetaVarName<"<class name>">,
HelpText<"View C++ inheritance for a specified class">;
-def fixit_at : Separate<"-fixit-at">, MetaVarName<"<source location>">,
- HelpText<"Perform Fix-It modifications at the given source location">;
def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">;
def load : Separate<"-load">, MetaVarName<"<dsopath>">,
HelpText<"Load the named plugin (dynamic shared object)">;
@@ -269,6 +277,8 @@ def fsyntax_only : Flag<"-fsyntax-only">,
HelpText<"Run parser and perform semantic analysis">;
def fixit : Flag<"-fixit">,
HelpText<"Apply fix-it advice to the input source">;
+def fixit_EQ : Joined<"-fixit=">,
+ HelpText<"Apply fix-it advice creating a file with the given suffix">;
def parse_print_callbacks : Flag<"-parse-print-callbacks">,
HelpText<"Run parser and print each callback invoked">;
def emit_html : Flag<"-emit-html">,
@@ -283,8 +293,6 @@ def ast_view : Flag<"-ast-view">,
HelpText<"Build ASTs and view them with GraphViz">;
def print_decl_contexts : Flag<"-print-decl-contexts">,
HelpText<"Print DeclContexts and their Decls">;
-def dump_record_layouts : Flag<"-dump-record-layouts">,
- HelpText<"Dump record layout information">;
def emit_pth : Flag<"-emit-pth">,
HelpText<"Generate pre-tokenized header file">;
def emit_pch : Flag<"-emit-pch">,
@@ -315,6 +323,14 @@ def print_stats : Flag<"-print-stats">,
def ftime_report : Flag<"-ftime-report">,
HelpText<"Print the amount of time each phase of compilation takes">;
+def fdump_record_layouts : Flag<"-fdump-record-layouts">,
+ HelpText<"Dump record layout information">;
+
+// Generic forwarding to LLVM options. This should only be used for debugging
+// and experimental features.
+def mllvm : Separate<"-mllvm">,
+ HelpText<"Additional arguments to forward to LLVM's option processing">;
+
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
@@ -323,10 +339,14 @@ def fno_builtin : Flag<"-fno-builtin">,
HelpText<"Disable implicit builtin knowledge of functions">;
def faltivec : Flag<"-faltivec">,
HelpText<"Enable AltiVec vector initializer syntax">;
-def faccess_control : Flag<"-faccess-control">,
- HelpText<"Enable C++ access control">;
+def fno_access_control : Flag<"-fno-access-control">,
+ HelpText<"Disable C++ access control">;
def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">,
HelpText<"Don't assume that C++'s global operator new can't alias any pointer">;
+def fgnu_keywords : Flag<"-fgnu-keywords">,
+ HelpText<"Allow GNU-extension keywords regardless of language standard">;
+def fno_gnu_keywords : Flag<"-fno-gnu-keywords">,
+ HelpText<"Disallow GNU-extension keywords regardless of language standard">;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">,
HelpText<"Allow '$' in identifiers">;
def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">,
@@ -365,12 +385,14 @@ def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">,
def fconstant_string_class : Separate<"-fconstant-string-class">,
MetaVarName<"<class name>">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
+def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">,
+ HelpText<"Enable creation of CodeFoundation-type constant strings">;
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 fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">,
+ HelpText<"Objective-C dispatch method to use">;
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">,
@@ -401,6 +423,8 @@ def trigraphs : Flag<"-trigraphs">,
HelpText<"Process trigraph sequences">;
def fwritable_strings : Flag<"-fwritable-strings">,
HelpText<"Store string literals as writable data">;
+def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">,
+ HelpText<"Ignore bit-field types when aligning structures">;
//===----------------------------------------------------------------------===//
// Header Search Options
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index ed68d68dd621..2127e5724f97 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -248,7 +248,7 @@ def fclasspath_EQ : Joined<"-fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, Group<f_Group>;
def fcommon : Flag<"-fcommon">, Group<f_Group>;
def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group<f_Group>;
-def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<clang_ignored_f_Group>;
+def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<f_Group>;
def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Group>;
def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>;
def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>;
@@ -265,6 +265,10 @@ def fexceptions : Flag<"-fexceptions">, Group<f_Group>;
def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>;
def fhosted : Flag<"-fhosted">, Group<f_Group>;
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
+
+def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>;
+def fasm : Flag<"-fasm">, Alias<fgnu_keywords>;
+
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
@@ -300,6 +304,10 @@ def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_
def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>;
def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>;
def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>;
+
+def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>;
+def fno_asm : Flag<"-fno-asm">, Alias<fno_gnu_keywords>;
+
def fno_inline_functions : Flag<"-fno-inline-functions">, Group<clang_ignored_f_Group>;
def fno_inline : Flag<"-fno-inline">, Group<clang_ignored_f_Group>;
def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
@@ -321,6 +329,7 @@ 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>;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
+def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
@@ -356,7 +365,10 @@ def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<clang_ignored_f_Group>;
def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
+def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
+def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">,
+ Group<f_Group>;
def 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>;
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index 851e4235b00e..ef77206c6593 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -48,6 +48,10 @@ public:
virtual bool hasIntegratedAssembler() const { return false; }
virtual bool hasIntegratedCPP() const = 0;
+ /// \brief Does this tool have "good" standardized diagnostics, or should the
+ /// driver add an additional "command failed" diagnostic on failures.
+ virtual bool hasGoodDiagnostics() const { return false; }
+
/// ConstructJob - Construct jobs to perform the action \arg JA,
/// writing to \arg Output and with \arg Inputs.
///
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 9a82973dca27..1a8ae7749143 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -103,6 +103,10 @@ public:
/// ABI).
virtual bool IsObjCLegacyDispatchDefault() const { return false; }
+ /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the
+ /// mixed dispatch method be used?
+ virtual bool UseObjCMixedDispatch() 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; }
@@ -120,6 +124,9 @@ public:
/// particular PIC mode.
virtual const char *GetForcedPicModel() const = 0;
+ /// Does this tool chain support Objective-C garbage collection.
+ virtual bool SupportsObjCGC() const { return false; }
+
/// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf
/// compile unit information.
virtual bool UseDwarfDebugFlags() const { return false; }
diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h
index b5b09f536d6e..9163a208de2e 100644
--- a/include/clang/Frontend/ASTConsumers.h
+++ b/include/clang/Frontend/ASTConsumers.h
@@ -57,10 +57,6 @@ ASTConsumer *CreateASTViewer();
// to stderr; this is intended for debugging.
ASTConsumer *CreateDeclContextPrinter();
-// RecordLayout dumper: prints out the record layout information for all records
-// in the translation unit; this is intended for debugging.
-ASTConsumer *CreateRecordLayoutDumper();
-
// ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code.
// This is considered experimental, and only works with Apple's ObjC runtime.
ASTConsumer *CreateObjCRewriter(const std::string &InFile,
diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def
index 287c67ebb7ef..aaa3920cee4f 100644
--- a/include/clang/Frontend/Analyses.def
+++ b/include/clang/Frontend/Analyses.def
@@ -15,22 +15,21 @@
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
#endif
-ANALYSIS(CFGDump, "cfg-dump",
+ANALYSIS(CFGDump, "cfg-dump",
"Display Control-Flow Graphs", Code)
-ANALYSIS(CFGView, "cfg-view",
+ANALYSIS(CFGView, "cfg-view",
"View Control-Flow Graphs using GraphViz", Code)
ANALYSIS(DisplayLiveVariables, "dump-live-variables",
"Print results of live variable analysis", Code)
ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic",
- "Perform quick security checks that require no data flow",
- Code)
+ "Perform quick security checks that require no data flow", Code)
ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions",
- "Check code for LLVM codebase conventions (domain-specific)",
- TranslationUnit)
+ "Check code for LLVM codebase conventions (domain-specific)",
+ TranslationUnit)
ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores",
"Warn about stores to dead variables", Code)
@@ -39,15 +38,15 @@ ANALYSIS(WarnUninitVals, "warn-uninit-values",
"Warn about uses of uninitialized variables", Code)
ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs",
- "Warn about Objective-C method signatures with type incompatibilities",
- ObjCImplementation)
+ "Warn about Objective-C method signatures with type incompatibilities",
+ ObjCImplementation)
ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc",
- "Warn about Objective-C classes that lack a correct implementation of -dealloc",
- ObjCImplementation)
+"Warn about Objective-C classes that lack a correct implementation of -dealloc",
+ ObjCImplementation)
ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars",
- "Warn about private ivars that are never used", ObjCImplementation)
+ "Warn about private ivars that are never used", ObjCImplementation)
ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
"Run the [Core] Foundation reference count checker", Code)
@@ -55,10 +54,6 @@ ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem",
ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer",
"Warn about unintended use of sizeof() on pointer expressions", Code)
-ANALYSIS(InlineCall, "inline-call",
- "Experimental transfer function inling callees when its definition"
- " is available.", TranslationUnit)
-
#ifndef ANALYSIS_STORE
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
#endif
diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h
index f55e5dc04055..3341bb01f0fa 100644
--- a/include/clang/Frontend/AnalysisConsumer.h
+++ b/include/clang/Frontend/AnalysisConsumer.h
@@ -60,6 +60,7 @@ public:
AnalysisConstraints AnalysisConstraintsOpt;
AnalysisDiagClients AnalysisDiagOpt;
std::string AnalyzeSpecificFunction;
+ unsigned MaxNodes;
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index b37c18057f0f..797cb34023db 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -38,6 +38,9 @@ public:
/// binary serialization mechanism, to be
/// deserialized by, e.g., the CIndex library.
+ unsigned ErrorLimit; /// Limit # errors emitted.
+ unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
+
/// The distance between tab stops.
unsigned TabStop;
enum { DefaultTabStop = 8, MaxTabStop = 100 };
@@ -70,6 +73,8 @@ public:
ShowSourceRanges = 0;
VerifyDiagnostics = 0;
BinaryOutput = 0;
+ ErrorLimit = 0;
+ TemplateBacktraceLimit = 0;
}
};
diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h
index fac87afadef2..b432d747de97 100644
--- a/include/clang/Frontend/FixItRewriter.h
+++ b/include/clang/Frontend/FixItRewriter.h
@@ -16,23 +16,24 @@
#define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Rewrite/Rewriter.h"
#include "llvm/ADT/SmallVector.h"
+namespace llvm { class raw_ostream; }
+
namespace clang {
class SourceManager;
class FileEntry;
-/// \brief Stores a source location in the form that it shows up on
-/// the Clang command line, e.g., file:line:column.
-///
-/// FIXME: Would prefer to use real SourceLocations, but I don't see a
-/// good way to resolve them during parsing.
-struct RequestedSourceLocation {
- const FileEntry *File;
- unsigned Line;
- unsigned Column;
+class FixItPathRewriter {
+public:
+ virtual ~FixItPathRewriter();
+
+ /// \brief This file is about to be rewritten. Return the name of the file
+ /// that is okay to write to.
+ virtual std::string RewriteFilename(const std::string &Filename) = 0;
};
class FixItRewriter : public DiagnosticClient {
@@ -47,38 +48,46 @@ class FixItRewriter : public DiagnosticClient {
/// of error messages.
DiagnosticClient *Client;
+ /// \brief Turn an input path into an output path. NULL implies overwriting
+ /// the original.
+ FixItPathRewriter *PathRewriter;
+
/// \brief The number of rewriter failures.
unsigned NumFailures;
- /// \brief Locations at which we should perform fix-its.
- ///
- /// When empty, perform fix-it modifications everywhere.
- llvm::SmallVector<RequestedSourceLocation, 4> FixItLocations;
-
public:
+ typedef Rewriter::buffer_iterator iterator;
+
/// \brief Initialize a new fix-it rewriter.
FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
- const LangOptions &LangOpts);
+ const LangOptions &LangOpts, FixItPathRewriter *PathRewriter);
/// \brief Destroy the fix-it rewriter.
~FixItRewriter();
- /// \brief Add a location where fix-it modifications should be
- /// performed.
- void addFixItLocation(RequestedSourceLocation Loc) {
- FixItLocations.push_back(Loc);
+ /// \brief Check whether there are modifications for a given file.
+ bool IsModified(FileID ID) const {
+ return Rewrite.getRewriteBufferFor(ID) != NULL;
}
- /// \brief Write the modified source file.
+ // Iteration over files with changes.
+ iterator buffer_begin() { return Rewrite.buffer_begin(); }
+ iterator buffer_end() { return Rewrite.buffer_end(); }
+
+ /// \brief Write a single modified source file.
+ ///
+ /// \returns true if there was an error, false otherwise.
+ bool WriteFixedFile(FileID ID, llvm::raw_ostream &OS);
+
+ /// \brief Write the modified source files.
///
/// \returns true if there was an error, false otherwise.
- bool WriteFixedFile(const std::string &InFileName,
- const std::string &OutFileName = std::string());
+ bool WriteFixedFiles();
/// IncludeInDiagnosticCounts - This method (whose default implementation
- /// returns true) indicates whether the diagnostics handled by this
- /// DiagnosticClient should be included in the number of diagnostics
- /// reported by Diagnostic.
+ /// returns true) indicates whether the diagnostics handled by this
+ /// DiagnosticClient should be included in the number of diagnostics
+ /// reported by Diagnostic.
virtual bool IncludeInDiagnosticCounts() const;
/// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index a7b6aa7e752f..3ddd77dc39e0 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -16,6 +16,7 @@
namespace clang {
class FixItRewriter;
+class FixItPathRewriter;
//===----------------------------------------------------------------------===//
// Custom Consumer Actions
@@ -73,15 +74,10 @@ protected:
llvm::StringRef InFile);
};
-class DumpRecordAction : public ASTFrontendAction {
-protected:
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile);
-};
-
class FixItAction : public ASTFrontendAction {
private:
llvm::OwningPtr<FixItRewriter> Rewriter;
+ llvm::OwningPtr<FixItPathRewriter> PathRewriter;
protected:
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index ee3811a30b94..60512edd6c1f 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -24,7 +24,6 @@ namespace frontend {
ASTPrintXML, ///< Parse ASTs and print them in XML.
ASTView, ///< Parse ASTs and view them in Graphviz.
DumpRawTokens, ///< Dump out raw tokens.
- DumpRecordLayouts, ///< Dump record layout information.
DumpTokens, ///< Dump out preprocessed tokens.
EmitAssembly, ///< Emit a .s file.
EmitBC, ///< Emit a .bc file.
@@ -93,8 +92,8 @@ public:
/// If given, the name for a C++ class to view the inheritance of.
std::string ViewClassInheritance;
- /// A list of locations to apply fix-its at.
- std::vector<ParsedSourceLocation> FixItLocations;
+ /// If given, the new suffix for fix-it rewritten files.
+ std::string FixItSuffix;
/// If given, enable code completion at the provided location.
ParsedSourceLocation CodeCompletionAt;
@@ -111,6 +110,10 @@ public:
/// \brief The list of AST files to merge.
std::vector<std::string> ASTMergeFiles;
+ /// \brief A list of arguments to forward to LLVM's option processing; this
+ /// should only be used for debugging and experimental features.
+ std::vector<std::string> LLVMArgs;
+
public:
FrontendOptions() {
DebugCodeCompletionPrinter = 1;
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index f975c497bee9..1640afb4122a 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -453,7 +453,9 @@ namespace clang {
/// \brief Block extedned descriptor type for Blocks CodeGen
SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13,
/// \brief Objective-C "SEL" redefinition type
- SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14
+ SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14,
+ /// \brief NSConstantString type
+ SPECIAL_TYPE_NS_CONSTANT_STRING = 15
};
/// \brief Record codes for each kind of declaration.
@@ -601,6 +603,8 @@ namespace clang {
EXPR_PAREN,
/// \brief A UnaryOperator record.
EXPR_UNARY_OPERATOR,
+ /// \brief An OffsetOfExpr record.
+ EXPR_OFFSETOF,
/// \brief A SizefAlignOfExpr record.
EXPR_SIZEOF_ALIGN_OF,
/// \brief An ArraySubscriptExpr record.
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 73c1bf4cce5c..c2352301caa0 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -436,7 +436,7 @@ private:
std::deque<PendingIdentifierInfo> PendingIdentifierInfos;
/// \brief FIXME: document!
- llvm::SmallVector<uint64_t, 4> SpecialTypes;
+ llvm::SmallVector<uint64_t, 16> SpecialTypes;
/// \brief Contains declarations and definitions that will be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
@@ -688,6 +688,9 @@ public:
Selector DecodeSelector(unsigned Idx);
+ virtual Selector GetSelector(uint32_t ID);
+ virtual uint32_t GetNumKnownSelectors();
+
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
return DecodeSelector(Record[Idx++]);
}
diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def
index 2f0da9e7b117..f63761a908af 100644
--- a/include/clang/Frontend/StmtXML.def
+++ b/include/clang/Frontend/StmtXML.def
@@ -254,7 +254,7 @@ NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op
ENUM_XML(UnaryOperator::Real, "__real")
ENUM_XML(UnaryOperator::Imag, "__imag")
ENUM_XML(UnaryOperator::Extension, "__extension__")
- ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof")
+ ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof")
END_ENUM_XML
SUB_NODE_XML(Expr) // expr
END_NODE_XML
@@ -311,6 +311,13 @@ NODE_XML(ConditionalOperator, "ConditionalOperator") // expr1 ? expr2 : expr3
SUB_NODE_XML(Expr) // expr3
END_NODE_XML
+NODE_XML(OffsetOfExpr, "OffsetOfExpr") // offsetof(basetype, components)
+ ATTRIBUTE_FILE_LOCATION_XML
+ TYPE_ATTRIBUTE_XML(getTypeSourceInfo()->getType())
+ ATTRIBUTE_XML(getNumComponents(), "num_components")
+ SUB_NODE_SEQUENCE_XML(OffsetOfExpr::OffsetOfNode)
+END_NODE_XML
+
NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr") // sizeof(expr) or alignof(expr)
ATTRIBUTE_FILE_LOCATION_XML
TYPE_ATTRIBUTE_XML(getType())
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 157876b59d34..336713661a28 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -68,7 +68,7 @@ public:
void EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges, unsigned NumRanges,
- SourceManager &SM,
+ const SourceManager &SM,
const FixItHint *Hints,
unsigned NumHints,
unsigned Columns);
diff --git a/include/clang/Frontend/VerifyDiagnosticsClient.h b/include/clang/Frontend/VerifyDiagnosticsClient.h
index 08adbb04d166..6f45e49ec0ef 100644
--- a/include/clang/Frontend/VerifyDiagnosticsClient.h
+++ b/include/clang/Frontend/VerifyDiagnosticsClient.h
@@ -25,7 +25,10 @@ class TextDiagnosticBuffer;
/// USING THE DIAGNOSTIC CHECKER:
///
/// Indicating that a line expects an error or a warning is simple. Put a
-/// comment on the line that has the diagnostic, use "expected-{error,warning}"
+/// comment on the line that has the diagnostic, use:
+///
+/// expected-{error,warning,note}
+///
/// to tag if it's an expected error or warning, and place the expected text
/// between {{ and }} markers. The full text doesn't have to be included, only
/// enough to ensure that the correct diagnostic was emitted.
@@ -45,6 +48,20 @@ class TextDiagnosticBuffer;
///
/// void f(); // expected-note 2 {{previous declaration is here}}
///
+/// Regex matching mode may be selected by appending '-re' to type. Example:
+///
+/// expected-error-re
+///
+/// Examples matching error: "variable has incomplete type 'struct s'"
+///
+/// // expected-error {{variable has incomplete type 'struct s'}}
+/// // expected-error {{variable has incomplete type}}
+///
+/// // expected-error-re {{variable has has type 'struct .'}}
+/// // expected-error-re {{variable has has type 'struct .*'}}
+/// // expected-error-re {{variable has has type 'struct (.*)'}}
+/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
+///
class VerifyDiagnosticsClient : public DiagnosticClient {
public:
Diagnostic &Diags;
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index e891e94d4cbc..d74124e9c79b 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -44,6 +44,14 @@ public:
SrcMgr::CharacteristicKind FileType) {
}
+ /// FileSkipped - This callback is invoked whenever a source file is
+ /// skipped as the result of header guard optimization. ParentFile
+ /// is the file that #includes the skipped file. FilenameTok is the
+ /// token in ParentFile that indicates the skipped file.
+ virtual void FileSkipped(const FileEntry &ParentFile,
+ const Token &FilenameTok,
+ SrcMgr::CharacteristicKind FileType) {
+ }
/// EndOfMainFile - This callback is invoked when the end of the main file is
/// reach, no subsequent callbacks will be made.
@@ -96,6 +104,13 @@ public:
Second->FileChanged(Loc, Reason, FileType);
}
+ virtual void FileSkipped(const FileEntry &ParentFile,
+ const Token &FilenameTok,
+ SrcMgr::CharacteristicKind FileType) {
+ First->FileSkipped(ParentFile, FilenameTok, FileType);
+ Second->FileSkipped(ParentFile, FilenameTok, FileType);
+ }
+
virtual void EndOfMainFile() {
First->EndOfMainFile();
Second->EndOfMainFile();
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 312a760e01d3..20d9fc50e49f 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -366,17 +366,17 @@ public:
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
- bool EnterMainSourceFile();
+ void EnterMainSourceFile();
/// EndSourceFile - Inform the preprocessor callbacks that processing is
/// complete.
void EndSourceFile();
/// EnterSourceFile - Add a source file to the top of the include stack and
- /// start lexing tokens from it instead of the current buffer. Return true
- /// and fill in ErrorStr with the error information on failure.
- bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir,
- std::string &ErrorStr);
+ /// start lexing tokens from it instead of the current buffer. Emit an error
+ /// and don't enter the file on error.
+ void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir,
+ SourceLocation Loc);
/// EnterMacro - Add a Macro to the top of the include stack and start lexing
/// tokens from it instead of the current buffer. Args specifies the
diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h
index d759e47e57fc..094990a6e317 100644
--- a/include/clang/Lex/TokenConcatenation.h
+++ b/include/clang/Lex/TokenConcatenation.h
@@ -58,7 +58,9 @@ namespace clang {
public:
TokenConcatenation(Preprocessor &PP);
- bool AvoidConcat(const Token &PrevTok, const Token &Tok) const;
+ bool AvoidConcat(const Token &PrevPrevTok,
+ const Token &PrevTok,
+ const Token &Tok) const;
private:
/// StartsWithL - Return true if the spelling of this token starts with 'L'.
diff --git a/include/clang/Makefile b/include/clang/Makefile
index 624292a128ee..d76e0a9c63ba 100644
--- a/include/clang/Makefile
+++ b/include/clang/Makefile
@@ -2,3 +2,30 @@ LEVEL = ../../../..
DIRS := Basic Driver
include $(LEVEL)/Makefile.common
+
+install-local::
+ $(Echo) Installing Clang include files
+ $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir)
+ $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang" ; then \
+ cd $(PROJ_SRC_ROOT)/tools/clang/include && \
+ for hdr in `find clang -type f '!' '(' -name '*~' \
+ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \
+ -o -name 'Makefile' -o -name '*.td' ')' -print \
+ | grep -v CVS | grep -v .svn | grep -v .dir` ; do \
+ instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \
+ if test \! -d "$$instdir" ; then \
+ $(EchoCmd) Making install directory $$instdir ; \
+ $(MKDIR) $$instdir ;\
+ fi ; \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
+ $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang" ; then \
+ cd $(PROJ_OBJ_ROOT)/tools/clang/include && \
+ for hdr in `find clang -type f '!' '(' -name 'Makefile' ')' -print \
+ | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \
+ $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \
+ done ; \
+ fi
+endif
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 59cc0d218cec..3d68d80ef9f0 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -205,7 +205,7 @@ public:
/// \returns the type referred to by this identifier, or NULL if the type
/// does not name an identifier.
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS = 0,
+ Scope *S, CXXScopeSpec *SS = 0,
bool isClassName = false,
TypeTy *ObjectType = 0) = 0;
@@ -243,7 +243,7 @@ public:
virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
- const CXXScopeSpec *SS,
+ CXXScopeSpec *SS,
TypeTy *&SuggestedType) {
return false;
}
@@ -281,7 +281,7 @@ public:
///
/// \returns the kind of template that this name refers to.
virtual TemplateNameKind isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
@@ -329,7 +329,7 @@ public:
/// This actual is used in the parsing of pseudo-destructor names to
/// distinguish a nested-name-specifier and a "type-name ::" when we
/// see the token sequence "X :: ~".
- virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+ virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectType) {
@@ -371,7 +371,7 @@ public:
///
/// \returns a CXXScopeTy* object representing the C++ scope.
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -387,7 +387,7 @@ public:
///
/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier.
virtual bool IsInvalidUnlessNestedName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo &II,
TypeTy *ObjectType,
bool EnteringContext) {
@@ -428,7 +428,7 @@ public:
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
/// \returns true if an error occurred, false otherwise.
- virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) {
return false;
}
@@ -468,7 +468,11 @@ public:
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy();
}
- virtual void ActOnObjCCatchParam(DeclPtrTy D) {
+
+ /// \brief Parsed an exception object declaration within an Objective-C
+ /// @catch statement.
+ virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
+ return DeclPtrTy();
}
/// AddInitializerToDecl - This action is called immediately after
@@ -576,8 +580,7 @@ public:
virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc) {
return DeclPtrTy();
}
@@ -655,7 +658,7 @@ public:
///
/// \returns the declaration to which this tag refers.
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -938,20 +941,46 @@ public:
}
// Objective-c statements
+
+ /// \brief Parsed an Objective-C @catch statement.
+ ///
+ /// \param AtLoc The location of the '@' starting the '@catch'.
+ ///
+ /// \param RParen The location of the right parentheses ')' after the
+ /// exception variable.
+ ///
+ /// \param Parm The variable that will catch the exception. Will be NULL if
+ /// this is a @catch(...) block.
+ ///
+ /// \param Body The body of the @catch block.
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
- DeclPtrTy Parm, StmtArg Body,
- StmtArg CatchList) {
+ DeclPtrTy Parm, StmtArg Body) {
return StmtEmpty();
}
+ /// \brief Parsed an Objective-C @finally statement.
+ ///
+ /// \param AtLoc The location of the '@' starting the '@finally'.
+ ///
+ /// \param Body The body of the @finally block.
virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
StmtArg Body) {
return StmtEmpty();
}
+ /// \brief Parsed an Objective-C @try-@catch-@finally statement.
+ ///
+ /// \param AtLoc The location of the '@' starting '@try'.
+ ///
+ /// \param Try The body of the '@try' statement.
+ ///
+ /// \param CatchStmts The @catch statements.
+ ///
+ /// \param Finally The @finally statement.
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
- StmtArg Try, StmtArg Catch,
+ StmtArg Try,
+ MultiStmtArg CatchStmts,
StmtArg Finally) {
return StmtEmpty();
}
@@ -1049,7 +1078,7 @@ public:
/// id-expression or identifier was an ampersand ('&'), indicating that
/// we will be taking the address of this expression.
virtual OwningExprResult ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
bool HasTrailingLParen,
bool IsAddressOfOperand) {
@@ -1127,7 +1156,7 @@ public:
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
@@ -1315,7 +1344,7 @@ public:
virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList);
@@ -1326,7 +1355,7 @@ public:
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
return DeclPtrTy();
@@ -1372,7 +1401,7 @@ public:
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -1501,7 +1530,7 @@ public:
/// \returns the type being destructed.
virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
TypeTy *ObjectType,
bool EnteringContext) {
return getTypeName(II, NameLoc, S, &SS, false, ObjectType);
@@ -1683,7 +1712,7 @@ public:
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
@@ -1729,7 +1758,7 @@ public:
virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorDecl,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -1939,7 +1968,7 @@ public:
/// \param EnteringContext whether we are entering the context of this
/// template.
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext) {
@@ -1995,7 +2024,7 @@ public:
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -2133,7 +2162,7 @@ public:
SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr) {
@@ -2306,7 +2335,7 @@ public:
TypeTy *ReturnType, // the method return type.
Selector Sel, // a unique name for the method.
ObjCArgInfo *ArgInfo, // ArgInfo: Has 'Sel.getNumArgs()' entries.
- llvm::SmallVectorImpl<Declarator> &Cdecls, // c-style args
+ DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *MethodAttrList, // optional
// tok::objc_not_keyword, tok::objc_optional, tok::objc_required
tok::ObjCKeywordKind impKind,
@@ -2336,36 +2365,118 @@ public:
return DeclPtrTy();
}
- virtual OwningExprResult ActOnClassPropertyRefExpr(
- IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation &receiverNameLoc,
- SourceLocation &propertyNameLoc) {
+ virtual OwningExprResult
+ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation receiverNameLoc,
+ SourceLocation propertyNameLoc) {
return ExprEmpty();
}
- // ActOnClassMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnClassMessage(
- Scope *S,
- IdentifierInfo *receivingClassName,
- Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc,
- SourceLocation selectorLoc,
- SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs) {
- return ExprResult();
- }
- // ActOnInstanceMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnInstanceMessage(
- ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs) {
- return ExprResult();
+ /// \brief Describes the kind of message expression indicated by a message
+ /// send that starts with an identifier.
+ enum ObjCMessageKind {
+ /// \brief The message is sent to 'super'.
+ ObjCSuperMessage,
+ /// \brief The message is an instance message.
+ ObjCInstanceMessage,
+ /// \brief The message is a class message, and the identifier is a type
+ /// name.
+ ObjCClassMessage
+ };
+
+ /// \brief Determine the kind of Objective-C message send that we will be
+ /// performing based on the identifier given.
+ ///
+ /// This action determines how a message send that starts with [
+ /// identifier (followed by another identifier) will be parsed,
+ /// e.g., as a class message, instance message, super message. The
+ /// result depends on the meaning of the given identifier. If the
+ /// identifier is unknown, the action should indicate that the
+ /// message is an instance message.
+ ///
+ /// By default, this routine applies syntactic disambiguation and uses
+ /// \c getTypeName() to determine whether the identifier refers to a type.
+ /// However, \c Action subclasses may override this routine to improve
+ /// error recovery.
+ ///
+ /// \param S The scope in which the message send occurs.
+ ///
+ /// \param Name The identifier following the '['.
+ ///
+ /// \param NameLoc The location of the identifier.
+ ///
+ /// \param IsSuper Whether the name is the pseudo-keyword "super".
+ ///
+ /// \param HasTrailingDot Whether the name is followed by a period.
+ ///
+ /// \param ReceiverType If this routine returns \c ObjCClassMessage,
+ /// this argument will be set to the receiver type.
+ ///
+ /// \returns The kind of message send.
+ virtual ObjCMessageKind getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType);
+
+ /// \brief Parsed a message send to 'super'.
+ ///
+ /// \param S The scope in which the message send occurs.
+ /// \param SuperLoc The location of the 'super' keyword.
+ /// \param Sel The selector to which the message is being sent.
+ /// \param LBracLoc The location of the opening square bracket ']'.
+ /// \param SelectorLoc The location of the first identifier in the selector.
+ /// \param RBrac The location of the closing square bracket ']'.
+ /// \param Args The message arguments.
+ virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ return OwningExprResult(*this);
+ }
+
+ /// \brief Parsed a message send to a class.
+ ///
+ /// \param S The scope in which the message send occurs.
+ /// \param Receiver The type of the class receiving the message.
+ /// \param Sel The selector to which the message is being sent.
+ /// \param LBracLoc The location of the opening square bracket ']'.
+ /// \param SelectorLoc The location of the first identifier in the selector.
+ /// \param RBrac The location of the closing square bracket ']'.
+ /// \param Args The message arguments.
+ virtual OwningExprResult ActOnClassMessage(Scope *S,
+ TypeTy *Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ return OwningExprResult(*this);
+ }
+
+ /// \brief Parsed a message send to an object instance.
+ ///
+ /// \param S The scope in which the message send occurs.
+ /// \param Receiver The expression that computes the receiver object.
+ /// \param Sel The selector to which the message is being sent.
+ /// \param LBracLoc The location of the opening square bracket ']'.
+ /// \param SelectorLoc The location of the first identifier in the selector.
+ /// \param RBrac The location of the closing square bracket ']'.
+ /// \param Args The message arguments.
+ virtual OwningExprResult ActOnInstanceMessage(Scope *S,
+ ExprArg Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ return OwningExprResult(*this);
}
+
virtual DeclPtrTy ActOnForwardClassDeclaration(
SourceLocation AtClassLoc,
IdentifierInfo **IdentList,
@@ -2581,7 +2692,7 @@ public:
///
/// \parame EnteringContext whether we're entering the context of this
/// scope specifier.
- virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) { }
/// \brief Code completion for a C++ "using" declaration or directive.
@@ -2692,21 +2803,33 @@ public:
unsigned NumMethods) {
}
+ /// \brief Code completion for an ObjC message expression that sends
+ /// a message to the superclass.
+ ///
+ /// This code completion action is invoked when the code-completion token is
+ /// found after the class name and after each argument.
+ ///
+ /// \param S The scope in which the message expression occurs.
+ /// \param SuperLoc The location of the 'super' keyword.
+ /// \param SelIdents The identifiers that describe the selector (thus far).
+ /// \param NumSelIdents The number of identifiers in \p SelIdents.
+ virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents) { }
+
/// \brief Code completion for an ObjC message expression that refers to
/// a class method.
///
/// This code completion action is invoked when the code-completion token is
/// found after the class name and after each argument.
///
- /// \param S the scope in which the message expression occurs.
- /// \param FName the factory name.
- /// \param FNameLoc the source location of the factory name.
- /// \param SelIdents the identifiers that describe the selector (thus far).
- /// \param NumSelIdents the number of identifiers in \p SelIdents.
- virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
- SourceLocation FNameLoc,
+ /// \param S The scope in which the message expression occurs.
+ /// \param Receiver The type of the class that is receiving a message.
+ /// \param SelIdents The identifiers that describe the selector (thus far).
+ /// \param NumSelIdents The number of identifiers in \p SelIdents.
+ virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
IdentifierInfo **SelIdents,
- unsigned NumSelIdents){ }
+ unsigned NumSelIdents) { }
/// \brief Code completion for an ObjC message expression that refers to
/// an instance method.
@@ -2752,7 +2875,8 @@ public:
///
/// \param ClassName the name of the class being defined.
virtual void CodeCompleteObjCSuperclass(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
}
/// \brief Code completion for an Objective-C implementation, after the
@@ -2765,7 +2889,8 @@ public:
/// This code completion action is invoked after the '(' that indicates
/// a category name within an Objective-C interface declaration.
virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
}
/// \brief Code completion for the category name in an Objective-C category
@@ -2774,7 +2899,8 @@ public:
/// This code completion action is invoked after the '(' that indicates
/// the category name within an Objective-C category implementation.
virtual void CodeCompleteObjCImplementationCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
}
/// \brief Code completion for the property names when defining an
@@ -2795,6 +2921,32 @@ public:
IdentifierInfo *PropertyName,
DeclPtrTy ObjCImpDecl) {
}
+
+ /// \brief Code completion for an Objective-C method declaration or
+ /// definition, which may occur within an interface, category,
+ /// extension, protocol, or implementation thereof (where applicable).
+ ///
+ /// This code completion action is invoked after the "-" or "+" that
+ /// starts a method declaration or definition, and after the return
+ /// type such a declaration (e.g., "- (id)").
+ ///
+ /// \param S The scope in which the completion occurs.
+ ///
+ /// \param IsInstanceMethod Whether this is an instance method
+ /// (introduced with '-'); otherwise, it's a class method
+ /// (introduced with '+').
+ ///
+ /// \param ReturnType If non-NULL, the specified return type of the method
+ /// being declared or defined.
+ ///
+ /// \param IDecl The interface, category, protocol, or
+ /// implementation, or category implementation in which this method
+ /// declaration or definition occurs.
+ virtual void CodeCompleteObjCMethodDecl(Scope *S,
+ bool IsInstanceMethod,
+ TypeTy *ReturnType,
+ DeclPtrTy IDecl) {
+ }
//@}
};
@@ -2837,7 +2989,7 @@ public:
/// \returns the type referred to by this identifier, or NULL if the type
/// does not name an identifier.
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName = false,
TypeTy *ObjectType = 0);
@@ -2847,7 +2999,7 @@ public:
const CXXScopeSpec *SS);
virtual TemplateNameKind isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h
index 37acab9b019b..12512f33c761 100644
--- a/include/clang/Parse/AttributeList.h
+++ b/include/clang/Parse/AttributeList.h
@@ -41,6 +41,7 @@ class AttributeList {
unsigned NumArgs;
AttributeList *Next;
bool DeclspecAttribute, CXX0XAttribute;
+ mutable bool Invalid; /// True if already diagnosed as invalid.
AttributeList(const AttributeList &); // DO NOT IMPLEMENT
void operator=(const AttributeList &); // DO NOT IMPLEMENT
public:
@@ -128,6 +129,9 @@ public:
bool isDeclspecAttribute() const { return DeclspecAttribute; }
bool isCXX0XAttribute() const { return CXX0XAttribute; }
+ bool isInvalid() const { return Invalid; }
+ void setInvalid(bool b = true) const { Invalid = b; }
+
Kind getKind() const { return getKind(getName()); }
static Kind getKind(const IdentifierInfo *Name);
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index f6f1eb936b7a..9c19a674732a 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -27,9 +27,18 @@ namespace clang {
class Preprocessor;
class Declarator;
struct TemplateIdAnnotation;
-
+
/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope
-/// specifier.
+/// specifier. These can be in 3 states:
+/// 1) Not present, identified by isEmpty()
+/// 2) Present, identified by isNotEmpty()
+/// 2.a) Valid, idenified by isValid()
+/// 2.b) Invalid, identified by isInvalid().
+///
+/// isSet() is deprecated because it mostly corresponded to "valid" but was
+/// often used as if it meant "present".
+///
+/// The actual scope is described by getScopeRep().
class CXXScopeSpec {
SourceRange Range;
void *ScopeRep;
@@ -47,13 +56,18 @@ public:
ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; }
void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; }
+ /// No scope specifier.
bool isEmpty() const { return !Range.isValid(); }
+ /// A scope specifier is present, but may be valid or invalid.
bool isNotEmpty() const { return !isEmpty(); }
- /// isInvalid - An error occured during parsing of the scope specifier.
+ /// An error occured during parsing of the scope specifier.
bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; }
+ /// A scope specifier is present, and it refers to a real scope.
+ bool isValid() const { return isNotEmpty() && ScopeRep != 0; }
- /// isSet - A scope specifier was resolved to a valid C++ scope.
+ /// Deprecated. Some call sites intend isNotEmpty() while others intend
+ /// isValid().
bool isSet() const { return ScopeRep != 0; }
void clear() {
@@ -68,8 +82,9 @@ public:
class DeclSpec {
public:
// storage-class-specifier
+ // Note: The order of these enumerators is important for diagnostics.
enum SCS {
- SCS_unspecified,
+ SCS_unspecified = 0,
SCS_typedef,
SCS_extern,
SCS_static,
@@ -171,6 +186,8 @@ private:
// constexpr-specifier
bool Constexpr_specified : 1;
+ /*SCS*/unsigned StorageClassSpecAsWritten : 3;
+
/// TypeRep - This contains action-specific information about a specific TST.
/// For example, for a typedef or struct, it might contain the declaration for
/// these.
@@ -203,6 +220,9 @@ private:
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
+ void SaveStorageSpecifierAsWritten() {
+ StorageClassSpecAsWritten = StorageClassSpec;
+ }
DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
void operator=(const DeclSpec&); // DO NOT IMPLEMENT
@@ -224,6 +244,7 @@ public:
FS_explicit_specified(false),
Friend_specified(false),
Constexpr_specified(false),
+ StorageClassSpecAsWritten(SCS_unspecified),
TypeRep(0),
AttrList(0),
ProtocolQualifiers(0),
@@ -321,6 +342,10 @@ public:
///
unsigned getParsedSpecifiers() const;
+ SCS getStorageClassSpecAsWritten() const {
+ return (SCS)StorageClassSpecAsWritten;
+ }
+
/// isEmpty - Return true if this declaration specifier is completely empty:
/// no tokens were parsed in the production of it.
bool isEmpty() const {
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 9a4634a42085..42a41d6d3028 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -41,6 +41,29 @@ public:
virtual void print(llvm::raw_ostream &OS) const;
};
+/// PrecedenceLevels - These are precedences for the binary/ternary
+/// operators in the C99 grammar. These have been named to relate
+/// with the C99 grammar productions. Low precedences numbers bind
+/// more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13, // *, /, %
+ PointerToMember = 14 // .*, ->*
+ };
+}
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
@@ -460,9 +483,11 @@ private:
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
+public:
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
+private:
void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
@@ -771,9 +796,15 @@ private:
const ParsedTemplateInfo &TemplateInfo);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDefs(ParsingClass &Class);
+ bool ConsumeAndStoreUntil(tok::TokenKind T1,
+ CachedTokens &Toks,
+ bool StopAtSemi = true,
+ bool ConsumeFinalToken = true) {
+ return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken);
+ }
bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
CachedTokens &Toks,
- tok::TokenKind EarlyAbortIf = tok::unknown,
+ bool StopAtSemi = true,
bool ConsumeFinalToken = true);
//===--------------------------------------------------------------------===//
@@ -846,7 +877,7 @@ private:
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.
-
+
OwningExprResult ParseExpression();
OwningExprResult ParseConstantExpression();
// Expr that doesn't include commas.
@@ -857,7 +888,7 @@ private:
OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
- unsigned MinPrec);
+ prec::Level MinPrec);
OwningExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
@@ -954,6 +985,8 @@ private:
// C++ 5.2.3: Explicit type conversion (functional notation)
OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS);
+ bool isCXXSimpleTypeSpecifier() const;
+
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
/// This should only be called when the current token is known to be part of
/// simple-type-specifier.
@@ -998,18 +1031,6 @@ private:
//===--------------------------------------------------------------------===//
// Objective-C Expressions
-
- bool isTokObjCMessageIdentifierReceiver() const {
- if (!Tok.is(tok::identifier))
- return false;
-
- IdentifierInfo *II = Tok.getIdentifierInfo();
- if (Actions.getTypeName(*II, Tok.getLocation(), CurScope))
- return true;
-
- return II == Ident_super;
- }
-
OwningExprResult ParseObjCAtExpression(SourceLocation AtLocation);
OwningExprResult ParseObjCStringLiteral(SourceLocation AtLoc);
OwningExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
@@ -1017,12 +1038,13 @@ private:
OwningExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);
OwningExprResult ParseObjCMessageExpression();
OwningExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc,
- SourceLocation NameLoc,
- IdentifierInfo *ReceiverName,
+ SourceLocation SuperLoc,
+ TypeTy *ReceiverType,
ExprArg ReceiverExpr);
OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
- SourceLocation LBracloc, SourceLocation NameLoc,
- IdentifierInfo *ReceiverName, ExprArg ReceiverExpr);
+ SourceLocation LBracloc, SourceLocation SuperLoc,
+ TypeTy *ReceiverType, ExprArg ReceiverExpr);
+ bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
//===--------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
@@ -1354,7 +1376,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 9: classes [class] and C structs/unions.
TypeResult ParseClassName(SourceLocation &EndLocation,
- const CXXScopeSpec *SS = 0);
+ CXXScopeSpec *SS = 0);
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index c9825f60c25c..d7a0e3583ca5 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -52,8 +52,8 @@ public:
/// BlockScope - This is a scope that corresponds to a block object.
/// Blocks serve as top-level scopes for some objects like labels, they
- /// also prevent things like break and continue. BlockScopes have the
- /// other flags set as well.
+ /// also prevent things like break and continue. BlockScopes always have
+ /// the FnScope, BreakScope, ContinueScope, and DeclScope flags set as well.
BlockScope = 0x40,
/// TemplateParamScope - This is a scope that corresponds to the
@@ -68,7 +68,15 @@ public:
/// AtCatchScope - This is a scope that corresponds to the Objective-C
/// @catch statement.
- AtCatchScope = 0x200
+ AtCatchScope = 0x200,
+
+ /// ObjCMethodScope - This scope corresponds to an Objective-C method body.
+ /// It always has FnScope and DeclScope set as well.
+ ObjCMethodScope = 0x400,
+
+ /// ElseScope - This scoep corresponds to an 'else' scope of an if/then/else
+ /// statement.
+ ElseScope = 0x800
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -77,15 +85,11 @@ private:
/// Depth - This is the depth of this scope. The translation-unit scope has
/// depth 0.
- unsigned Depth : 16;
+ unsigned short Depth;
/// Flags - This contains a set of ScopeFlags, which indicates how the scope
/// interrelates with other control flow statements.
- unsigned Flags : 10;
-
- /// WithinElse - Whether this scope is part of the "else" branch in
- /// its parent ControlScope.
- bool WithinElse : 1;
+ unsigned short Flags;
/// FnParent - If this scope has a parent scope that is a function body, this
/// pointer is non-null and points to it. This is used for label processing.
@@ -140,6 +144,7 @@ public:
/// getFlags - Return the flags for this scope.
///
unsigned getFlags() const { return Flags; }
+ void setFlags(unsigned F) { Flags = F; }
/// isBlockScope - Return true if this scope does not correspond to a
/// closure.
@@ -233,6 +238,17 @@ public:
}
return false;
}
+
+ /// isInObjcMethodScope - Return true if this scope is, or is contained in, an
+ /// Objective-C method body. Note that this method is not constant time.
+ bool isInObjcMethodScope() const {
+ for (const Scope *S = this; S; S = S->getParent()) {
+ // If this scope is an objc method scope, then we succeed.
+ if (S->getFlags() & ObjCMethodScope)
+ return true;
+ }
+ return false;
+ }
/// isTemplateParamScope - Return true if this scope is a C++
/// template parameter scope.
@@ -251,12 +267,6 @@ public:
return getFlags() & Scope::AtCatchScope;
}
- /// isWithinElse - Whether we are within the "else" of the
- /// ControlParent (if any).
- bool isWithinElse() const { return WithinElse; }
-
- void setWithinElse(bool WE) { WithinElse = WE; }
-
typedef UsingDirectivesTy::iterator udir_iterator;
typedef UsingDirectivesTy::const_iterator const_udir_iterator;
@@ -286,7 +296,6 @@ public:
AnyParent = Parent;
Depth = AnyParent ? AnyParent->Depth+1 : 0;
Flags = ScopeFlags;
- WithinElse = false;
if (AnyParent) {
FnParent = AnyParent->FnParent;
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
index 1692180a6da9..adda86699965 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -16,18 +16,20 @@
#define LLVM_CLANG_REWRITER_H
#include "clang/Basic/SourceLocation.h"
+#include "clang/Rewrite/DeltaTree.h"
#include "clang/Rewrite/RewriteRope.h"
-#include <map>
-#include <vector>
+#include "llvm/ADT/StringRef.h"
#include <cstring>
+#include <map>
#include <string>
-#include "clang/Rewrite/DeltaTree.h"
-#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace llvm { class raw_ostream; }
namespace clang {
- class SourceManager;
class LangOptions;
class Rewriter;
+ class SourceManager;
class Stmt;
/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original
@@ -53,6 +55,8 @@ public:
iterator end() const { return Buffer.end(); }
unsigned size() const { return Buffer.size(); }
+ llvm::raw_ostream &write(llvm::raw_ostream &) const;
+
/// RemoveText - Remove the specified text.
void RemoveText(unsigned OrigOffset, unsigned Size);
@@ -125,6 +129,8 @@ class Rewriter {
const LangOptions *LangOpts;
std::map<FileID, RewriteBuffer> RewriteBuffers;
public:
+ typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator;
+
explicit Rewriter(SourceManager &SM, const LangOptions &LO)
: SourceMgr(&SM), LangOpts(&LO) {}
explicit Rewriter() : SourceMgr(0), LangOpts(0) {}
@@ -192,6 +198,12 @@ public:
/// could not be rewritten, or false if successful.
bool ReplaceStmt(Stmt *From, Stmt *To);
+ /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
+ /// buffer, and allows you to write on it directly. This is useful if you
+ /// want efficient low-level access to apis for scribbling on one specific
+ /// FileID's buffer.
+ RewriteBuffer &getEditBuffer(FileID FID);
+
/// getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
/// If no modification has been made to it, return null.
const RewriteBuffer *getRewriteBufferFor(FileID FID) const {
@@ -200,11 +212,9 @@ public:
return I == RewriteBuffers.end() ? 0 : &I->second;
}
- /// getEditBuffer - This is like getRewriteBufferFor, but always returns a
- /// buffer, and allows you to write on it directly. This is useful if you
- /// want efficient low-level access to apis for scribbling on one specific
- /// FileID's buffer.
- RewriteBuffer &getEditBuffer(FileID FID);
+ // Iterators over rewrite buffers.
+ buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
+ buffer_iterator buffer_end() { return RewriteBuffers.end(); }
private:
unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const;
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 50a6e0a50d8b..731d5e046681 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -48,7 +48,8 @@ const APValue &APValue::operator=(const APValue &RHS) {
else if (isFloat())
setFloat(RHS.getFloat());
else if (isVector())
- setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength());
+ setVector(((const Vec *)(const char *)RHS.Data)->Elts,
+ RHS.getVectorLength());
else if (isComplexInt())
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
else if (isComplexFloat())
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c77acce1bd06..eea727deb44d 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -41,6 +41,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
Builtin::Context &builtins,
bool FreeMem, unsigned size_reserve) :
GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
+ NSConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
@@ -325,55 +326,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
-CXXMethodVector::iterator CXXMethodVector::begin() const {
- if ((Storage & 0x01) == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front();
-}
-
-CXXMethodVector::iterator CXXMethodVector::end() const {
- if ((Storage & 0x01) == 0) {
- if (Storage == 0)
- return reinterpret_cast<iterator>(&Storage);
-
- return reinterpret_cast<iterator>(&Storage) + 1;
- }
-
- vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
- return &Vec->front() + Vec->size();
-}
-
-void CXXMethodVector::push_back(const CXXMethodDecl *Method) {
- if (Storage == 0) {
- // 0 -> 1 element.
- Storage = reinterpret_cast<uintptr_t>(Method);
- return;
- }
-
- vector_type *Vec;
- if ((Storage & 0x01) == 0) {
- // 1 -> 2 elements. Allocate a new vector and push the element into that
- // vector.
- Vec = new vector_type;
- Vec->push_back(reinterpret_cast<const CXXMethodDecl *>(Storage));
- Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01;
- } else
- Vec = reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- // Add the new method to the vector.
- Vec->push_back(Method);
-}
-
-void CXXMethodVector::Destroy() {
- if (Storage & 0x01)
- delete reinterpret_cast<vector_type *>(Storage & ~0x01);
-
- Storage = 0;
-}
-
-
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -515,7 +467,7 @@ ASTContext::getTypeInfo(const Type *T) {
Align = Width;
// If the alignment is not a power of 2, round up to the next power of 2.
// This happens for non-power-of-2 length vectors.
- if (VT->getNumElements() & (VT->getNumElements()-1)) {
+ if (Align & (Align-1)) {
Align = llvm::NextPowerOf2(Align);
Width = llvm::RoundUpToAlignment(Width, Align);
}
@@ -701,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::QualifiedName:
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
- case Type::InjectedClassName:
- return getTypeInfo(cast<InjectedClassNameType>(T)
- ->getUnderlyingType().getTypePtr());
-
case Type::TemplateSpecialization:
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
@@ -833,9 +781,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
CollectInheritedProtocols(SD, Protocols);
SD = SD->getSuperClass();
}
- return;
- }
- if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
@@ -844,9 +790,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
- return;
- }
- if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
PE = OP->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
@@ -855,26 +799,20 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
PE = Proto->protocol_end(); P != PE; ++P)
CollectInheritedProtocols(*P, Protocols);
}
- return;
}
}
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) {
unsigned count = 0;
// Count ivars declared in class extension.
- if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
- for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
- E = CDecl->ivar_end(); I != E; ++I) {
- ++count;
- }
- }
-
+ if (const ObjCCategoryDecl *CDecl = OI->getClassExtension())
+ count += CDecl->ivar_size();
+
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
- for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end(); I != E; ++I)
- ++count;
+ count += ImplDecl->ivar_size();
+
return count;
}
@@ -998,6 +936,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
ASTRecordLayoutBuilder::ComputeLayout(*this, D);
ASTRecordLayouts[D] = NewEntry;
+ if (getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::errs());
+ }
+
return *NewEntry;
}
@@ -1735,8 +1678,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
Decl->TypeForDecl = PrevDecl->TypeForDecl;
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
} else {
- Decl->TypeForDecl = new (*this, TypeAlignment)
- InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal());
+ Decl->TypeForDecl =
+ new (*this, TypeAlignment) InjectedClassNameType(Decl, TST);
Types.push_back(Decl->TypeForDecl);
}
return QualType(Decl->TypeForDecl, 0);
@@ -1867,7 +1810,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
- QualType Canon) {
+ QualType Canon,
+ bool IsCurrentInstantiation) {
unsigned NumArgs = Args.size();
llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -1875,17 +1819,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
for (unsigned i = 0; i != NumArgs; ++i)
ArgVec.push_back(Args[i].getArgument());
- return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon);
+ return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
+ Canon, IsCurrentInstantiation);
}
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon) {
+ QualType Canon,
+ bool IsCurrentInstantiation) {
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else {
+ assert(!IsCurrentInstantiation &&
+ "current-instantiation specializations should always "
+ "have a canonical type");
+
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -1896,7 +1846,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
// Determine whether this canonical template specialization type already
// exists.
llvm::FoldingSetNodeID ID;
- TemplateSpecializationType::Profile(ID, CanonTemplate,
+ TemplateSpecializationType::Profile(ID, CanonTemplate, false,
CanonArgs.data(), NumArgs, *this);
void *InsertPos = 0;
@@ -1908,7 +1858,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
- Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
+ Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false,
CanonArgs.data(), NumArgs,
Canon);
Types.push_back(Spec);
@@ -1928,7 +1878,9 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
sizeof(TemplateArgument) * NumArgs),
TypeAlignment);
TemplateSpecializationType *Spec
- = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs,
+ = new (Mem) TemplateSpecializationType(*this, Template,
+ IsCurrentInstantiation,
+ Args, NumArgs,
Canon);
Types.push_back(Spec);
@@ -2108,10 +2060,10 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
if (!InterfaceT.isCanonical() ||
!areSortedAndUniqued(Protocols, NumProtocols)) {
if (!areSortedAndUniqued(Protocols, NumProtocols)) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols);
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
+ Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
- std::copy(Protocols, Protocols + NumProtocols, Sorted.begin());
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT),
@@ -2154,8 +2106,8 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
// Sort the protocol list alphabetically to canonicalize it.
QualType Canonical;
if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) {
- llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols);
- std::copy(Protocols, Protocols + NumProtocols, Sorted.begin());
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols,
+ Protocols + NumProtocols);
unsigned UniqueCount = NumProtocols;
SortAndUniqueProtocols(&Sorted[0], UniqueCount);
@@ -2634,14 +2586,9 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) {
QualType ASTContext::getBaseElementType(QualType QT) {
QualifierCollector Qs;
- while (true) {
- const Type *UT = Qs.strip(QT);
- if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
- QT = AT->getElementType();
- } else {
- return Qs.apply(QT);
- }
- }
+ while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0)))
+ QT = AT->getElementType();
+ return Qs.apply(QT);
}
QualType ASTContext::getBaseElementType(const ArrayType *AT) {
@@ -2886,6 +2833,7 @@ QualType ASTContext::getCFConstantStringType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
CFConstantStringTypeDecl->addDecl(Field);
}
@@ -2901,6 +2849,46 @@ void ASTContext::setCFConstantStringType(QualType T) {
CFConstantStringTypeDecl = Rec->getDecl();
}
+// getNSConstantStringType - Return the type used for constant NSStrings.
+QualType ASTContext::getNSConstantStringType() {
+ if (!NSConstantStringTypeDecl) {
+ NSConstantStringTypeDecl =
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__builtin_NSString"));
+ NSConstantStringTypeDecl->startDefinition();
+
+ QualType FieldTypes[3];
+
+ // const int *isa;
+ FieldTypes[0] = getPointerType(IntTy.withConst());
+ // const char *str;
+ FieldTypes[1] = getPointerType(CharTy.withConst());
+ // unsigned int length;
+ FieldTypes[2] = UnsignedIntTy;
+
+ // Create fields
+ for (unsigned i = 0; i < 3; ++i) {
+ FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false);
+ Field->setAccess(AS_public);
+ NSConstantStringTypeDecl->addDecl(Field);
+ }
+
+ NSConstantStringTypeDecl->completeDefinition();
+ }
+
+ return getTagDeclType(NSConstantStringTypeDecl);
+}
+
+void ASTContext::setNSConstantStringType(QualType T) {
+ const RecordType *Rec = T->getAs<RecordType>();
+ assert(Rec && "Invalid NSConstantStringType");
+ NSConstantStringTypeDecl = Rec->getDecl();
+}
+
QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
@@ -2923,6 +2911,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
@@ -2960,6 +2949,7 @@ QualType ASTContext::getBlockDescriptorType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3008,6 +2998,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
/*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3085,6 +3076,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3129,6 +3121,7 @@ QualType ASTContext::getBlockParmType(
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3149,6 +3142,7 @@ QualType ASTContext::getBlockParmType(
FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
Name, FieldType, /*TInfo=*/0,
/*BitWidth=*/0, /*Mutable=*/false);
+ Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3192,7 +3186,7 @@ std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
}
-/// getObjCEncodingForBlockDecl - Return the encoded type for this method
+/// getObjCEncodingForBlockDecl - Return the encoded type for this block
/// declaration.
void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
std::string& S) {
@@ -3207,7 +3201,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
SourceLocation Loc;
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
- for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ for (BlockDecl::param_const_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
@@ -3258,7 +3252,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// their size.
CharUnits ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
+ E = Decl->sel_param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
assert (sz.isPositive() &&
@@ -3272,7 +3266,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Argument types.
ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
+ E = Decl->sel_param_end(); PI != E; ++PI) {
ParmVarDecl *PVDecl = *PI;
QualType PType = PVDecl->getOriginalType();
if (const ArrayType *AT =
@@ -3494,13 +3488,18 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
+ // encoding for pointer or r3eference types.
+ QualType PointeeTy;
if (const PointerType *PT = T->getAs<PointerType>()) {
if (PT->isObjCSelType()) {
S += ':';
return;
}
- QualType PointeeTy = PT->getPointeeType();
-
+ PointeeTy = PT->getPointeeType();
+ }
+ else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ PointeeTy = RT->getPointeeType();
+ if (!PointeeTy.isNull()) {
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -3524,12 +3523,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Another legacy compatibility encoding. Some ObjC qualifier and type
// combinations need to be rearranged.
// Rewrite "in const" from "nr" to "rn"
- const char * s = S.c_str();
- int len = S.length();
- if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') {
- std::string replace = "rn";
- S.replace(S.end()-2, S.end(), replace);
- }
+ if (llvm::StringRef(S).endswith("nr"))
+ S.replace(S.end()-2, S.end(), "rn");
}
if (PointeeTy->isCharType()) {
@@ -3559,7 +3554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
NULL);
return;
}
-
+
if (const ArrayType *AT =
// Ignore type qualifiers etc.
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
@@ -4136,15 +4131,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
- if (RHSOPT->isObjCBuiltinType() ||
- LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType())
+ if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
}
- if (RHSOPT->isObjCQualifiedIdType())
+ if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
@@ -4190,7 +4184,8 @@ void getIntersectionOfProtocols(ASTContext &Context,
unsigned RHSNumProtocols = RHS->getNumProtocols();
if (RHSNumProtocols > 0) {
- ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin();
+ ObjCProtocolDecl **RHSProtocols =
+ const_cast<ObjCProtocolDecl **>(RHS->qual_begin());
for (unsigned i = 0; i < RHSNumProtocols; ++i)
if (InheritedProtocolSet.count(RHSProtocols[i]))
IntersectionOfProtocols.push_back(RHSProtocols[i]);
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 866b7f799f05..e4cd2a9c1053 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT,
continue;
}
- // ...or an injected class name...
- if (isa<InjectedClassNameType>(Ty)) {
- QT = cast<InjectedClassNameType>(Ty)->desugar();
- continue;
- }
-
// ...or a substituted template type parameter.
if (isa<SubstTemplateTypeParmType>(Ty)) {
QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 5dfb99ff0889..ae09d7978ea5 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
if (!IsStructurallyEquivalent(Context,
- Inj1->getUnderlyingType(),
- Inj2->getUnderlyingType()))
+ Inj1->getInjectedSpecializationType(),
+ Inj2->getInjectedSpecializationType()))
return false;
break;
}
@@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
for (DeclContext::lookup_result Lookup = DC->lookup(Name);
Lookup.first != Lookup.second;
++Lookup.first) {
- if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace))
continue;
if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) {
@@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace,
ConflictingDecls.data(),
ConflictingDecls.size());
}
@@ -1905,6 +1905,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc,
Name, T, TInfo, D->getStorageClass(),
+ D->getStorageClassAsWritten(),
D->isInlineSpecified(),
D->hasWrittenPrototype());
}
@@ -2125,7 +2126,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(), T, TInfo,
- D->getStorageClass());
+ D->getStorageClass(),
+ D->getStorageClassAsWritten());
// Import the qualifier, if any.
if (D->getQualifier()) {
NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
@@ -2197,6 +2199,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
+ D->getStorageClassAsWritten(),
/*FIXME: Default argument*/ 0);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
@@ -2312,7 +2315,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
ToMethod->addDecl(ToParams[I]);
}
ToMethod->setMethodParams(Importer.getToContext(),
- ToParams.data(), ToParams.size());
+ ToParams.data(), ToParams.size(),
+ ToParams.size());
ToMethod->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToMethod);
@@ -2881,8 +2885,11 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
if (!SubExpr)
return 0;
+ // FIXME: Initialize the base path.
+ assert(E->getBasePath().empty() && "FIXME: Must copy base path!");
+ CXXBaseSpecifierArray BasePath;
return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(),
- SubExpr,
+ SubExpr, BasePath,
E->isLvalueCast());
}
@@ -2899,8 +2906,11 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) {
if (!TInfo && E->getTypeInfoAsWritten())
return 0;
+ // FIXME: Initialize the base path.
+ assert(E->getBasePath().empty() && "FIXME: Must copy base path!");
+ CXXBaseSpecifierArray BasePath;
return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(),
- SubExpr, TInfo,
+ SubExpr, BasePath, TInfo,
Importer.Import(E->getLParenLoc()),
Importer.Import(E->getRParenLoc()));
}
@@ -3086,7 +3096,7 @@ FileID ASTImporter::Import(FileID FromID) {
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags());
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM);
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index dc9fb59e3090..ffe49671d8a3 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -25,7 +25,6 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/ErrorHandling.h"
-#include <vector>
using namespace clang;
@@ -286,6 +285,28 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
}
Linkage NamedDecl::getLinkage() const {
+
+ // Objective-C: treat all Objective-C declarations as having external
+ // linkage.
+ switch (getKind()) {
+ default:
+ break;
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCForwardProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCIvar:
+ case Decl::ObjCMethod:
+ case Decl::ObjCProperty:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCProtocol:
+ return ExternalLinkage;
+ }
+
// Handle linkage for namespace-scope names.
if (getDeclContext()->getLookupContext()->isFileContext())
if (Linkage L = getLinkageForNamespaceScopeDecl(this))
@@ -354,88 +375,79 @@ std::string NamedDecl::getQualifiedNameAsString() const {
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
- // FIXME: Collect contexts, then accumulate names to avoid unnecessary
- // std::string thrashing.
- std::vector<std::string> Names;
- std::string QualName;
const DeclContext *Ctx = getDeclContext();
if (Ctx->isFunctionOrMethod())
return getNameAsString();
- while (Ctx) {
+ typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy;
+ ContextsTy Contexts;
+
+ // Collect contexts.
+ while (Ctx && isa<NamedDecl>(Ctx)) {
+ Contexts.push_back(Ctx);
+ Ctx = Ctx->getParent();
+ };
+
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+
+ for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend();
+ I != E; ++I) {
if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
+ = dyn_cast<ClassTemplateSpecializationDecl>(*I)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
P);
- Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr);
- } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Ctx)) {
+ OS << Spec->getName() << TemplateArgsStr;
+ } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
if (ND->isAnonymousNamespace())
- Names.push_back("<anonymous namespace>");
+ OS << "<anonymous namespace>";
else
- Names.push_back(ND->getNameAsString());
- } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(Ctx)) {
- if (!RD->getIdentifier()) {
- std::string RecordString = "<anonymous ";
- RecordString += RD->getKindName();
- RecordString += ">";
- Names.push_back(RecordString);
- } else {
- Names.push_back(RD->getNameAsString());
- }
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Ctx)) {
- std::string Proto = FD->getNameAsString();
-
+ OS << ND;
+ } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) {
+ if (!RD->getIdentifier())
+ OS << "<anonymous " << RD->getKindName() << '>';
+ else
+ OS << RD;
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionProtoType *FT = 0;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
- Proto += "(";
+ OS << FD << '(';
if (FT) {
- llvm::raw_string_ostream POut(Proto);
unsigned NumParams = FD->getNumParams();
for (unsigned i = 0; i < NumParams; ++i) {
if (i)
- POut << ", ";
+ OS << ", ";
std::string Param;
FD->getParamDecl(i)->getType().getAsStringInternal(Param, P);
- POut << Param;
+ OS << Param;
}
if (FT->isVariadic()) {
if (NumParams > 0)
- POut << ", ";
- POut << "...";
+ OS << ", ";
+ OS << "...";
}
}
- Proto += ")";
-
- Names.push_back(Proto);
- } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
- Names.push_back(ND->getNameAsString());
- else
- break;
-
- Ctx = Ctx->getParent();
+ OS << ')';
+ } else {
+ OS << cast<NamedDecl>(*I);
+ }
+ OS << "::";
}
- std::vector<std::string>::reverse_iterator
- I = Names.rbegin(),
- End = Names.rend();
-
- for (; I!=End; ++I)
- QualName += *I + "::";
-
if (getDeclName())
- QualName += getNameAsString();
+ OS << this;
else
- QualName += "<anonymous>";
+ OS << "<anonymous>";
- return QualName;
+ return OS.str();
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
@@ -494,6 +506,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
}
}
+bool NamedDecl::isCXXInstanceMember() const {
+ assert(isCXXClassMember() &&
+ "checking whether non-member is instance member");
+
+ const NamedDecl *D = this;
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ if (isa<FieldDecl>(D))
+ return true;
+ if (isa<CXXMethodDecl>(D))
+ return cast<CXXMethodDecl>(D)->isInstance();
+ if (isa<FunctionTemplateDecl>(D))
+ return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
+ ->getTemplatedDecl())->isInstance();
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// DeclaratorDecl Implementation
//===----------------------------------------------------------------------===//
@@ -568,8 +598,8 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S) {
- return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S);
+ StorageClass S, StorageClass SCAsWritten) {
+ return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
}
void VarDecl::Destroy(ASTContext& C) {
@@ -793,8 +823,10 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
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);
+ StorageClass S, StorageClass SCAsWritten,
+ Expr *DefArg) {
+ return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo,
+ S, SCAsWritten, DefArg);
}
Expr *ParmVarDecl::getDefaultArg() {
@@ -874,6 +906,12 @@ void FunctionDecl::getNameForDiagnostic(std::string &S,
}
+bool FunctionDecl::isVariadic() const {
+ if (const FunctionProtoType *FT = getType()->getAs<FunctionProtoType>())
+ return FT->isVariadic();
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->Body) {
@@ -1291,6 +1329,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
}
}
+void
+FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context,
+ const UnresolvedSetImpl &Templates,
+ const TemplateArgumentListInfo &TemplateArgs) {
+ assert(TemplateOrSpecialization.isNull());
+ size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo);
+ Size += Templates.size() * sizeof(FunctionTemplateDecl*);
+ Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc);
+ void *Buffer = Context.Allocate(Size);
+ DependentFunctionTemplateSpecializationInfo *Info =
+ new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates,
+ TemplateArgs);
+ TemplateOrSpecialization = Info;
+}
+
+DependentFunctionTemplateSpecializationInfo::
+DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
+ const TemplateArgumentListInfo &TArgs)
+ : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) {
+
+ d.NumTemplates = Ts.size();
+ d.NumArgs = TArgs.size();
+
+ FunctionTemplateDecl **TsArray =
+ const_cast<FunctionTemplateDecl**>(getTemplates());
+ for (unsigned I = 0, E = Ts.size(); I != E; ++I)
+ TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl());
+
+ TemplateArgumentLoc *ArgsArray =
+ const_cast<TemplateArgumentLoc*>(getTemplateArgs());
+ for (unsigned I = 0, E = TArgs.size(); I != E; ++I)
+ new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]);
+}
+
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
// For a function template specialization, query the specialization
// information object.
@@ -1407,6 +1479,10 @@ void TagDecl::startDefinition() {
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
TagT->decl.setPointer(this);
TagT->decl.setInt(1);
+ } else if (InjectedClassNameType *Injected
+ = const_cast<InjectedClassNameType *>(
+ TypeForDecl->getAs<InjectedClassNameType>())) {
+ Injected->Decl = cast<CXXRecordDecl>(this);
}
if (isa<CXXRecordDecl>(this)) {
@@ -1428,6 +1504,11 @@ void TagDecl::completeDefinition() {
assert(TagT->decl.getPointer() == this &&
"Attempt to redefine a tag definition?");
TagT->decl.setInt(0);
+ } else if (InjectedClassNameType *Injected
+ = const_cast<InjectedClassNameType *>(
+ TypeForDecl->getAs<InjectedClassNameType>())) {
+ assert(Injected->Decl == this &&
+ "Attempt to redefine a class template definition?");
}
}
@@ -1606,10 +1687,10 @@ 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);
+ StorageClass S, StorageClass SCAsWritten,
+ bool isInline, bool hasWrittenPrototype) {
+ FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo,
+ S, SCAsWritten, isInline);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index c693e153dda5..b5aec0c5125c 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -231,24 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case CXXConstructor:
case CXXDestructor:
case CXXConversion:
- case Typedef:
case EnumConstant:
case Var:
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
case ObjCMethod:
- case ObjCContainer:
- case ObjCInterface:
case ObjCProperty:
- case ObjCCompatibleAlias:
return IDNS_Ordinary;
+ case ObjCCompatibleAlias:
+ case ObjCInterface:
+ return IDNS_Ordinary | IDNS_Type;
+
+ case Typedef:
+ case UnresolvedUsingTypename:
+ case TemplateTypeParm:
+ return IDNS_Ordinary | IDNS_Type;
+
case UsingShadow:
return 0; // we'll actually overwrite this later
case UnresolvedUsingValue:
- case UnresolvedUsingTypename:
return IDNS_Ordinary | IDNS_Using;
case Using:
@@ -257,13 +261,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCProtocol:
return IDNS_ObjCProtocol;
- case ObjCImplementation:
- return IDNS_ObjCImplementation;
-
- case ObjCCategory:
- case ObjCCategoryImpl:
- return IDNS_ObjCCategoryName;
-
case Field:
case ObjCAtDefsField:
case ObjCIvar:
@@ -272,16 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Record:
case CXXRecord:
case Enum:
- case TemplateTypeParm:
- return IDNS_Tag;
+ return IDNS_Tag | IDNS_Type;
case Namespace:
- case Template:
+ case NamespaceAlias:
+ return IDNS_Namespace;
+
case FunctionTemplate:
+ return IDNS_Ordinary;
+
case ClassTemplate:
case TemplateTemplateParm:
- case NamespaceAlias:
- return IDNS_Tag | IDNS_Ordinary;
+ return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
// Never have names.
case Friend:
@@ -295,10 +294,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Block:
case TranslationUnit:
- // Aren't looked up?
case UsingDirective:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
+ case ObjCImplementation:
+ case ObjCCategory:
+ case ObjCCategoryImpl:
+ // Never looked up by name.
return 0;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 94ed85c7cd2d..68f4a821e689 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -587,9 +587,9 @@ CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, bool isInline) {
+ bool isStatic, StorageClass SCAsWritten, bool isInline) {
return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo,
- isStatic, isInline);
+ isStatic, SCAsWritten, isInline);
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -633,6 +633,27 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
return true;
}
+bool CXXMethodDecl::isCopyAssignmentOperator() const {
+ // C++0x [class.copy]p19:
+ // A user-declared copy assignment operator X::operator= is a non-static
+ // non-template member function of class X with exactly one parameter of
+ // type X, X&, const X&, volatile X& or const volatile X&.
+ if (/*operator=*/getOverloadedOperator() != OO_Equal ||
+ /*non-static*/ isStatic() ||
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ /*exactly one parameter*/getNumParams() != 1)
+ return false;
+
+ QualType ParamType = getParamDecl(0)->getType();
+ if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>())
+ ParamType = Ref->getPointeeType();
+
+ ASTContext &Context = getASTContext();
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ return Context.hasSameUnqualifiedType(ClassType, ParamType);
+}
+
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
@@ -659,15 +680,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
assert(isInstance() && "No 'this' for static methods!");
QualType ClassTy = C.getTypeDeclType(getParent());
-
- // Aesthetically we prefer not to synthesize a type as the
- // InjectedClassNameType of a template pattern: injected class names
- // are printed without template arguments, which might
- // surprise/confuse/distract our poor users if they didn't
- // explicitly write one.
- if (isa<InjectedClassNameType>(ClassTy))
- ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType();
-
ClassTy = C.getQualifiedType(ClassTy,
Qualifiers::fromCVRMask(getTypeQualifiers()));
return C.getPointerType(ClassTy);
@@ -686,9 +698,9 @@ bool CXXMethodDecl::hasInlineBody() const {
CXXBaseOrMemberInitializer::
CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo,
+ TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init, SourceLocation R)
- : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
+ : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual),
LParenLoc(L), RParenLoc(R)
{
}
@@ -745,11 +757,12 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit,
- bool isInline, bool isImplicitlyDeclared) {
+ bool isInline,
+ bool isImplicitlyDeclared) {
assert(N.getNameKind() == DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline,
- isImplicitlyDeclared);
+ return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit,
+ isInline, isImplicitlyDeclared);
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -848,8 +861,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
bool isImplicitlyDeclared) {
assert(N.getNameKind() == DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, L, N, T, isInline,
- isImplicitlyDeclared);
+ return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared);
}
void
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 821e38bdacfd..dc4aacdb515c 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -330,11 +330,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isInstance,
bool isVariadic,
bool isSynthesized,
- ImplementationControl impControl) {
+ ImplementationControl impControl,
+ unsigned numSelectorArgs) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
- isVariadic, isSynthesized, impControl);
+ isVariadic, isSynthesized, impControl,
+ numSelectorArgs);
}
void ObjCMethodDecl::Destroy(ASTContext &C) {
@@ -841,6 +843,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const {
return 0;
}
+llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+ const ObjCCategoryImplDecl *CID) {
+ OS << CID->getName();
+ return OS;
+}
+
//===----------------------------------------------------------------------===//
// ObjCImplementationDecl
//===----------------------------------------------------------------------===//
@@ -853,6 +861,12 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl);
}
+llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
+ const ObjCImplementationDecl *ID) {
+ OS << ID->getName();
+ return OS;
+}
+
//===----------------------------------------------------------------------===//
// ObjCCompatibleAliasDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index a625865ecdb3..539492479707 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -301,17 +301,15 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
- Out << "enum " << D->getNameAsString() << " {\n";
+ Out << "enum " << D << " {\n";
VisitDeclContext(D);
Indent() << "}";
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
Out << D->getKindName();
- if (D->getIdentifier()) {
- Out << " ";
- Out << D->getNameAsString();
- }
+ if (D->getIdentifier())
+ Out << ' ' << D;
if (D->isDefinition()) {
Out << " {\n";
@@ -321,7 +319,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
}
void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
- Out << D->getNameAsString();
+ Out << D;
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
Init->printPretty(Out, Context, 0, Policy, Indentation);
@@ -406,7 +404,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << ", ";
if (BMInitializer->isMemberInitializer()) {
FieldDecl *FD = BMInitializer->getMember();
- Out << FD->getNameAsString();
+ Out << FD;
} else {
Out << QualType(BMInitializer->getBaseClass(), 0).getAsString();
}
@@ -537,7 +535,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
// C++ declarations
//----------------------------------------------------------------------------
void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
- Out << "namespace " << D->getNameAsString() << " {\n";
+ Out << "namespace " << D << " {\n";
VisitDeclContext(D);
Indent() << "}";
}
@@ -546,22 +544,20 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getNominatedNamespaceAsWritten()->getNameAsString();
+ Out << D->getNominatedNamespaceAsWritten();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
- Out << "namespace " << D->getNameAsString() << " = ";
+ Out << "namespace " << D << " = ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getAliasedNamespace()->getNameAsString();
+ Out << D->getAliasedNamespace();
}
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << D->getKindName();
- if (D->getIdentifier()) {
- Out << " ";
- Out << D->getNameAsString();
- }
+ if (D->getIdentifier())
+ Out << ' ' << D;
if (D->isDefinition()) {
// Print the base classes
@@ -669,7 +665,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
for (ObjCClassDecl::iterator I = D->begin(), E = D->end();
I != E; ++I) {
if (I != D->begin()) Out << ", ";
- Out << I->getInterface()->getNameAsString();
+ Out << I->getInterface();
}
}
@@ -688,8 +684,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
// FIXME: selector is missing here!
pos = name.find_first_of(":", lastPos);
Out << " " << name.substr(lastPos, pos - lastPos);
- Out << ":(" << (*PI)->getType().getAsString(Policy) << ")"
- << (*PI)->getNameAsString();
+ Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI;
lastPos = pos + 1;
}
@@ -711,7 +706,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@implementation " << I << " : " << SID->getNameAsString();
+ Out << "@implementation " << I << " : " << SID;
else
Out << "@implementation " << I;
Out << "\n";
@@ -724,7 +719,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
ObjCInterfaceDecl *SID = OID->getSuperClass();
if (SID)
- Out << "@interface " << I << " : " << SID->getNameAsString();
+ Out << "@interface " << I << " : " << SID;
else
Out << "@interface " << I;
@@ -733,7 +728,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
if (!Protocols.empty()) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
- Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString();
+ Out << (I == Protocols.begin() ? '<' : ',') << *I;
}
if (!Protocols.empty())
@@ -744,8 +739,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
- Indent() << (*I)->getType().getAsString(Policy)
- << ' ' << (*I)->getNameAsString() << ";\n";
+ Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
@@ -762,20 +756,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
E = D->protocol_end();
I != E; ++I) {
if (I != D->protocol_begin()) Out << ", ";
- Out << (*I)->getNameAsString();
+ Out << *I;
}
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
- Out << "@protocol " << PID->getNameAsString() << '\n';
+ Out << "@protocol " << PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
- Out << "@implementation "
- << PID->getClassInterface()->getNameAsString()
- << '(' << PID->getNameAsString() << ")\n";
+ Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -783,9 +775,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
}
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
- Out << "@interface "
- << PID->getClassInterface()->getNameAsString()
- << '(' << PID->getNameAsString() << ")\n";
+ Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n";
VisitDeclContext(PID, false);
Out << "@end";
@@ -793,8 +783,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
}
void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
- Out << "@compatibility_alias " << AID->getNameAsString()
- << ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
+ Out << "@compatibility_alias " << AID
+ << ' ' << AID->getClassInterface() << ";\n";
}
/// PrintObjCPropertyDecl - print a property declaration.
@@ -854,8 +844,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
}
Out << " )";
}
- Out << ' ' << PDecl->getType().getAsString(Policy)
- << ' ' << PDecl->getNameAsString();
+ Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl;
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -863,28 +852,28 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
Out << "@synthesize ";
else
Out << "@dynamic ";
- Out << PID->getPropertyDecl()->getNameAsString();
+ Out << PID->getPropertyDecl();
if (PID->getPropertyIvarDecl())
- Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
+ Out << '=' << PID->getPropertyIvarDecl();
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getTargetNestedNameDecl()->print(Out, Policy);
- Out << D->getNameAsString();
+ Out << D;
}
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getDeclName().getAsString();
+ Out << D->getDeclName();
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getDeclName().getAsString();
+ Out << D->getDeclName();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index b44939862445..c498dea17703 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -178,6 +178,20 @@ void ClassTemplateDecl::Destroy(ASTContext& C) {
C.Deallocate((void*)this);
}
+void ClassTemplateDecl::getPartialSpecializations(
+ llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
+ = CommonPtr->PartialSpecializations;
+ PS.clear();
+ PS.resize(PartialSpecs.size());
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
+ P != PEnd; ++P) {
+ assert(!PS[P->getSequenceNumber()]);
+ PS[P->getSequenceNumber()] = &*P;
+ }
+}
+
ClassTemplatePartialSpecializationDecl *
ClassTemplateDecl::findPartialSpecialization(QualType T) {
ASTContext &Context = getASTContext();
@@ -186,7 +200,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
for (partial_spec_iterator P = getPartialSpecializations().begin(),
PEnd = getPartialSpecializations().end();
P != PEnd; ++P) {
- if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+ if (Context.hasSameType(P->getInjectedSpecializationType(), T))
return &*P;
}
@@ -456,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
TemplateArgumentListBuilder &Builder,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ ClassTemplatePartialSpecializationDecl *PrevDecl,
+ unsigned SequenceNumber) {
unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
@@ -468,7 +483,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
SpecializedTemplate,
Builder,
ClonedArgs, N,
- PrevDecl);
+ PrevDecl,
+ SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Context.getInjectedClassNameType(Result, CanonInjectedType);
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 19b58bcbaf03..4f85fca53868 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -18,7 +18,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include <cstdio>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace clang {
@@ -202,32 +202,42 @@ bool DeclarationName::isDependentName() const {
}
std::string DeclarationName::getAsString() const {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ printName(OS);
+ return OS.str();
+}
+
+void DeclarationName::printName(llvm::raw_ostream &OS) const {
switch (getNameKind()) {
case Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
- return II->getName();
- return "";
+ OS << II->getName();
+ return;
case ObjCZeroArgSelector:
case ObjCOneArgSelector:
case ObjCMultiArgSelector:
- return getObjCSelector().getAsString();
+ OS << getObjCSelector().getAsString();
+ return;
case CXXConstructorName: {
QualType ClassType = getCXXNameType();
if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- return ClassRec->getDecl()->getNameAsString();
- return ClassType.getAsString();
+ OS << ClassRec->getDecl();
+ else
+ OS << ClassType.getAsString();
+ return;
}
case CXXDestructorName: {
- std::string Result = "~";
+ OS << '~';
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- Result += Rec->getDecl()->getNameAsString();
+ OS << Rec->getDecl();
else
- Result += Type.getAsString();
- return Result;
+ OS << Type.getAsString();
+ return;
}
case CXXOperatorName: {
@@ -240,32 +250,32 @@ std::string DeclarationName::getAsString() const {
const char *OpName = OperatorNames[getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
- std::string Result = "operator";
+ OS << "operator";
if (OpName[0] >= 'a' && OpName[0] <= 'z')
- Result += ' ';
- Result += OpName;
- return Result;
+ OS << ' ';
+ OS << OpName;
+ return;
}
- case CXXLiteralOperatorName: {
- return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName());
- }
+ case CXXLiteralOperatorName:
+ OS << "operator \"\" " << getCXXLiteralIdentifier()->getName();
+ return;
case CXXConversionFunctionName: {
- std::string Result = "operator ";
+ OS << "operator ";
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
- Result += Rec->getDecl()->getNameAsString();
+ OS << Rec->getDecl();
else
- Result += Type.getAsString();
- return Result;
+ OS << Type.getAsString();
+ return;
}
case CXXUsingDirective:
- return "<using-directive>";
+ OS << "<using-directive>";
+ return;
}
assert(false && "Unexpected declaration name kind");
- return "";
}
QualType DeclarationName::getCXXNameType() const {
@@ -369,7 +379,8 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
}
void DeclarationName::dump() const {
- fprintf(stderr, "%s\n", getAsString().c_str());
+ printName(llvm::errs());
+ llvm::errs() << '\n';
}
DeclarationNameTable::DeclarationNameTable() {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ae4bc8c80128..00662a53afed 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -27,6 +27,65 @@
#include <algorithm>
using namespace clang;
+/// isKnownToHaveBooleanValue - Return true if this is an integer expression
+/// that is known to return 0 or 1. This happens for _Bool/bool expressions
+/// but also int expressions which are produced by things like comparisons in
+/// C.
+bool Expr::isKnownToHaveBooleanValue() const {
+ // If this value has _Bool type, it is obvious 0/1.
+ if (getType()->isBooleanType()) return true;
+ // If this is a non-scalar-integer type, we don't care enough to try.
+ if (!getType()->isIntegralType()) return false;
+
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
+ return PE->getSubExpr()->isKnownToHaveBooleanValue();
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
+ switch (UO->getOpcode()) {
+ case UnaryOperator::Plus:
+ case UnaryOperator::Extension:
+ return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ default:
+ return false;
+ }
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(this))
+ return CE->getSubExpr()->isKnownToHaveBooleanValue();
+
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
+ switch (BO->getOpcode()) {
+ default: return false;
+ case BinaryOperator::LT: // Relational operators.
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ: // Equality operators.
+ case BinaryOperator::NE:
+ case BinaryOperator::LAnd: // AND operator.
+ case BinaryOperator::LOr: // Logical OR operator.
+ return true;
+
+ case BinaryOperator::And: // Bitwise AND operator.
+ case BinaryOperator::Xor: // Bitwise XOR operator.
+ case BinaryOperator::Or: // Bitwise OR operator.
+ // Handle things like (x==2)|(y==12).
+ return BO->getLHS()->isKnownToHaveBooleanValue() &&
+ BO->getRHS()->isKnownToHaveBooleanValue();
+
+ case BinaryOperator::Comma:
+ case BinaryOperator::Assign:
+ return BO->getRHS()->isKnownToHaveBooleanValue();
+ }
+ }
+
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
+ return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
+ CO->getFalseExpr()->isKnownToHaveBooleanValue();
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
@@ -231,14 +290,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// For incorrect code, there might not be an ObjCInterfaceDecl. Do
// a null check to avoid a crash.
if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
- Out << ID->getNameAsString();
+ Out << ID;
if (const ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) {
- Out << '(';
- Out << CID->getNameAsString();
- Out << ')';
- }
+ dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext()))
+ Out << '(' << CID << ')';
+
Out << ' ';
Out << MD->getSelector().getAsString();
Out << ']';
@@ -492,17 +549,70 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
+OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc,
+ TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc) {
+ void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+ sizeof(OffsetOfNode) * numComps +
+ sizeof(Expr*) * numExprs);
+
+ return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps,
+ exprsPtr, numExprs, RParenLoc);
+}
+
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+ unsigned numComps, unsigned numExprs) {
+ void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+ sizeof(OffsetOfNode) * numComps +
+ sizeof(Expr*) * numExprs);
+ return new (Mem) OffsetOfExpr(numComps, numExprs);
+}
+
+OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
+ SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+ OffsetOfNode* compsPtr, unsigned numComps,
+ Expr** exprsPtr, unsigned numExprs,
+ SourceLocation RParenLoc)
+ : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false,
+ /*ValueDependent=*/tsi->getType()->isDependentType() ||
+ hasAnyTypeDependentArguments(exprsPtr, numExprs) ||
+ hasAnyValueDependentArguments(exprsPtr, numExprs)),
+ OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
+ NumComps(numComps), NumExprs(numExprs)
+{
+ for(unsigned i = 0; i < numComps; ++i) {
+ setComponent(i, compsPtr[i]);
+ }
+
+ for(unsigned i = 0; i < numExprs; ++i) {
+ setIndexExpr(i, exprsPtr[i]);
+ }
+}
+
+IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
+ assert(getKind() == Field || getKind() == Identifier);
+ if (getKind() == Field)
+ return getField()->getIdentifier();
+
+ return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
+}
+
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
ValueDecl *memberdecl,
- NamedDecl *founddecl,
+ DeclAccessPair founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
- bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
+ bool hasQualOrFound = (qual != 0 ||
+ founddecl.getDecl() != memberdecl ||
+ founddecl.getAccess() != memberdecl->getAccess());
if (hasQualOrFound)
Size += sizeof(MemberNameQualifier);
@@ -593,6 +703,12 @@ const char *CastExpr::getCastKindName() const {
return 0;
}
+void CastExpr::DoDestroy(ASTContext &C)
+{
+ BasePath.Destroy();
+ Expr::DoDestroy(C);
+}
+
Expr *CastExpr::getSubExprAsWritten() {
Expr *SubExpr = 0;
CastExpr *E = this;
@@ -720,10 +836,11 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(SourceLocation lbraceloc,
+InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), false, false),
+ InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
UnionFieldInit(0), HadArrayRangeDesignator(false)
{
@@ -734,24 +851,24 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc,
ValueDependent = true;
}
- InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
+ InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits);
}
-void InitListExpr::reserveInits(unsigned NumInits) {
+void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
if (NumInits > InitExprs.size())
- InitExprs.reserve(NumInits);
+ InitExprs.reserve(C, NumInits);
}
-void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) {
for (unsigned Idx = NumInits, LastIdx = InitExprs.size();
Idx < LastIdx; ++Idx)
- InitExprs[Idx]->Destroy(Context);
- InitExprs.resize(NumInits, 0);
+ InitExprs[Idx]->Destroy(C);
+ InitExprs.resize(C, NumInits, 0);
}
-Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
- InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+ InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
return 0;
}
@@ -835,19 +952,22 @@ 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) {
- // ((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->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
- BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
+ switch (BO->getOpcode()) {
+ default:
+ break;
+ // Consider ',', '||', '&&' to have side effects if the LHS or RHS does.
+ case 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;
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) ||
+ BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
}
-
if (BO->isAssignmentOp())
return false;
Loc = BO->getOperatorLoc();
@@ -1219,11 +1339,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
- case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property.
+ case ObjCImplicitSetterGetterRefExprClass:
+ // FIXME: check if read-only property.
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
case UnresolvedLookupExprClass:
+ case UnresolvedMemberExprClass:
return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
@@ -1821,7 +1943,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UnaryOperator::AddrOf:
case UnaryOperator::Deref:
return ICEDiag(2, E->getLocStart());
-
case UnaryOperator::Extension:
case UnaryOperator::LNot:
case UnaryOperator::Plus:
@@ -1831,6 +1952,12 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UnaryOperator::Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
case UnaryOperator::OffsetOf:
+ break;
+ }
+
+ // OffsetOf falls through here.
+ }
+ case Expr::OffsetOfExprClass: {
// Note that per C99, offsetof must be an ICE. And AFAIK, using
// Evaluate matches the proposed gcc behavior for cases like
// "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect
@@ -1838,7 +1965,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// array subscripts that aren't ICEs, and if the array subscripts
// are ICEs, the value of the offsetof must be an integer constant.
return CheckEvalInICE(E, Ctx);
- }
}
case Expr::SizeOfAlignOfExprClass: {
const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
@@ -1936,7 +2062,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
- case Expr::CXXNamedCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass: {
@@ -1953,7 +2078,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (const CallExpr *CallCE
+ = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
Expr::EvalResult EVResult;
if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
@@ -2176,101 +2302,156 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
}
-// constructor for instance messages.
-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 (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = receiver;
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
-
-// constructor for class messages.
-// FIXME: clsName should be typed to ObjCInterfaceType
-ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType, ObjCMethodDecl *mproto,
- SourceLocation LBrac, SourceLocation RBrac,
- Expr **ArgExprs, unsigned nargs)
- : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
- SelName(selInfo), MethodProto(mproto) {
- NumArgs = nargs;
- SubExprs = new (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown);
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
-
-// constructor for class messages.
-ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls,
- SourceLocation clsNameLoc, Selector selInfo,
- QualType retType,
- ObjCMethodDecl *mproto, SourceLocation LBrac,
- SourceLocation RBrac, Expr **ArgExprs,
- unsigned nargs)
- : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc),
- SelName(selInfo), MethodProto(mproto)
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false,
+ /*ValueDependent=*/false),
+ NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
+ HasMethod(Method != 0), SuperLoc(SuperLoc),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
- NumArgs = nargs;
- SubExprs = new (C) Stmt*[NumArgs+1];
- SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown);
- if (NumArgs) {
- for (unsigned i = 0; i != NumArgs; ++i)
- SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
- }
- LBracloc = LBrac;
- RBracloc = RBrac;
-}
+ setReceiverPointer(SuperType.getAsOpaquePtr());
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, T->isDependentType(),
+ (T->isDependentType() ||
+ hasAnyValueDependentArguments(Args, NumArgs))),
+ NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+{
+ setReceiverPointer(Receiver);
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc)
+ : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(),
+ (Receiver->isTypeDependent() ||
+ hasAnyValueDependentArguments(Args, NumArgs))),
+ NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
+ SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
+ : Sel.getAsOpaquePtr())),
+ LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+{
+ setReceiverPointer(Receiver);
+ if (NumArgs)
+ memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ SourceLocation SuperLoc,
+ bool IsInstanceSuper,
+ QualType SuperType,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper,
+ SuperType, Sel, Method, Args, NumArgs,
+ RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ TypeSourceInfo *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
+ NumArgs, RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ SourceLocation LBracLoc,
+ Expr *Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RBracLoc) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
+ NumArgs, RBracLoc);
+}
+
+ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
+ unsigned NumArgs) {
+ unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
+ NumArgs * sizeof(Expr *);
+ void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
+ return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
+}
+
+Selector ObjCMessageExpr::getSelector() const {
+ if (HasMethod)
+ return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod)
+ ->getSelector();
+ return Selector(SelectorOrMethod);
+}
+
+ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
+ switch (getReceiverKind()) {
+ case Instance:
+ if (const ObjCObjectPointerType *Ptr
+ = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+ break;
-ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const {
- uintptr_t x = (uintptr_t) SubExprs[RECEIVER];
- switch (x & Flags) {
- default:
- assert(false && "Invalid ObjCMessageExpr.");
- case IsInstMeth:
- return ClassInfo(0, 0, SourceLocation());
- case IsClsMethDeclUnknown:
- return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc);
- case IsClsMethDeclKnown: {
- ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags);
- return ClassInfo(D, D->getIdentifier(), ClassNameLoc);
- }
- }
-}
+ case Class:
+ if (const ObjCInterfaceType *Iface
+ = getClassReceiver()->getAs<ObjCInterfaceType>())
+ return Iface->getDecl();
+ break;
-void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) {
- if (CI.Decl == 0 && CI.Name == 0) {
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth);
- return;
- }
+ case SuperInstance:
+ if (const ObjCObjectPointerType *Ptr
+ = getSuperType()->getAs<ObjCObjectPointerType>())
+ return Ptr->getInterfaceDecl();
+ break;
- if (CI.Decl == 0)
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown);
- else
- SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown);
- ClassNameLoc = CI.Loc;
-}
+ case SuperClass:
+ if (const ObjCObjectPointerType *Iface
+ = getSuperType()->getAs<ObjCObjectPointerType>())
+ return Iface->getInterfaceDecl();
+ break;
+ }
-void ObjCMessageExpr::DoDestroy(ASTContext &C) {
- DestroyChildren(C);
- if (SubExprs)
- C.Deallocate(SubExprs);
- this->~ObjCMessageExpr();
- C.Deallocate((void*) this);
+ return 0;
}
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
@@ -2577,6 +2758,15 @@ Stmt::child_iterator ParenExpr::child_end() { return &Val+1; }
Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
+// OffsetOfExpr
+Stmt::child_iterator OffsetOfExpr::child_begin() {
+ return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1)
+ + NumComps);
+}
+Stmt::child_iterator OffsetOfExpr::child_end() {
+ return child_iterator(&*child_begin() + NumExprs);
+}
+
// SizeOfAlignOfExpr
Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
// If this is of a type and the type is a VLA type (and not a typedef), the
@@ -2746,10 +2936,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() {
// ObjCMessageExpr
Stmt::child_iterator ObjCMessageExpr::child_begin() {
- return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START;
+ if (getReceiverKind() == Instance)
+ return reinterpret_cast<Stmt **>(this + 1);
+ return getArgs();
}
Stmt::child_iterator ObjCMessageExpr::child_end() {
- return &SubExprs[0]+ARGS_START+getNumArgs();
+ return getArgs() + getNumArgs();
}
// Blocks
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b9a4ee6e4d2c..2e03beb0f050 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -18,16 +18,25 @@
#include "clang/AST/TypeLoc.h"
using namespace clang;
+
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
+QualType CXXTypeidExpr::getTypeOperand() const {
+ assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
+ return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
+ .getUnqualifiedType();
+}
+
// CXXTypeidExpr - has child iterators if the operand is an expression
Stmt::child_iterator CXXTypeidExpr::child_begin() {
- return isTypeOperand() ? child_iterator() : &Operand.Ex;
+ return isTypeOperand() ? child_iterator()
+ : reinterpret_cast<Stmt **>(&Operand);
}
Stmt::child_iterator CXXTypeidExpr::child_end() {
- return isTypeOperand() ? child_iterator() : &Operand.Ex+1;
+ return isTypeOperand() ? child_iterator()
+ : reinterpret_cast<Stmt **>(&Operand) + 1;
}
// CXXBoolLiteralExpr
@@ -180,6 +189,13 @@ bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
return false;
}
+CXXRecordDecl *OverloadExpr::getNamingClass() const {
+ if (isa<UnresolvedLookupExpr>(this))
+ return cast<UnresolvedLookupExpr>(this)->getNamingClass();
+ else
+ return cast<UnresolvedMemberExpr>(this)->getNamingClass();
+}
+
Stmt::child_iterator UnresolvedLookupExpr::child_begin() {
return child_iterator();
}
@@ -443,9 +459,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
SourceLocation tyBeginLoc,
Expr **Args,
unsigned NumArgs,
- SourceLocation rParenLoc)
+ SourceLocation rParenLoc,
+ bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc,
- Cons, false, Args, NumArgs),
+ Cons, false, Args, NumArgs, ZeroInitialization),
TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
}
@@ -454,25 +471,25 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool ZeroInitialization,
- bool BaseInitialization) {
+ ConstructionKind ConstructKind) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args, NumArgs, ZeroInitialization,
- BaseInitialization);
+ ConstructKind);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
- bool ZeroInitialization,
- bool BaseInitialization)
+ bool ZeroInitialization,
+ ConstructionKind ConstructKind)
: Expr(SC, T,
T->isDependentType(),
(T->isDependentType() ||
CallExpr::hasAnyValueDependentArguments(args, numargs))),
Constructor(D), Loc(Loc), Elidable(elidable),
- ZeroInitialization(ZeroInitialization),
- BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs)
+ ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind),
+ Args(0), NumArgs(numargs)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
@@ -712,15 +729,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
// If there was a nested name specifier, it names the naming class.
// It can't be dependent: after all, we were actually able to do the
// lookup.
- const RecordType *RT;
+ CXXRecordDecl *Record = 0;
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");
-
+ Record = T->getAsCXXRecordDecl();
+ assert(Record && "qualifier in member expression does not name record");
+ }
// Otherwise the naming class must have been the base class.
- } else {
+ else {
QualType BaseType = getBaseType().getNonReferenceType();
if (isArrow()) {
const PointerType *PT = BaseType->getAs<PointerType>();
@@ -728,11 +745,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
BaseType = PT->getPointeeType();
}
- RT = BaseType->getAs<RecordType>();
- assert(RT && "base of member expression does not name record");
+ Record = BaseType->getAsCXXRecordDecl();
+ assert(Record && "base of member expression does not name record");
}
- return cast<CXXRecordDecl>(RT->getDecl());
+ return Record;
}
Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index eeeeb5c836b8..c1a42d88fffa 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -16,7 +16,9 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
@@ -203,6 +205,13 @@ public:
return Visit(E->getSubExpr());
}
bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
+
+ // Has side effects if any element does.
+ bool VisitInitListExpr(InitListExpr *E) {
+ for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
+ if (Visit(E->getInit(i))) return true;
+ return false;
+ }
};
} // end anonymous namespace
@@ -221,7 +230,7 @@ public:
APValue VisitStmt(Stmt *S) {
return APValue();
}
-
+
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitDeclRefExpr(DeclRefExpr *E);
APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
@@ -821,6 +830,7 @@ public:
bool VisitCallExpr(CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConditionalOperator(const ConditionalOperator *E);
@@ -961,7 +971,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
return complex_type_class;
else if (ArgTy->isFunctionType())
return function_type_class;
- else if (ArgTy->isStructureType())
+ else if (ArgTy->isStructureOrClassType())
return record_type_class;
else if (ArgTy->isUnionType())
return union_type_class;
@@ -1109,9 +1119,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(E->getOpcode() == BinaryOperator::NE &&
"Invalid complex comparison.");
return Success(((CR_r == APFloat::cmpGreaterThan ||
- CR_r == APFloat::cmpLessThan) &&
+ CR_r == APFloat::cmpLessThan ||
+ CR_r == APFloat::cmpUnordered) ||
(CR_i == APFloat::cmpGreaterThan ||
- CR_i == APFloat::cmpLessThan)), E);
+ CR_i == APFloat::cmpLessThan ||
+ CR_i == APFloat::cmpUnordered)), E);
}
} else {
if (E->getOpcode() == BinaryOperator::EQ)
@@ -1154,7 +1166,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Success(CR == APFloat::cmpEqual, E);
case BinaryOperator::NE:
return Success(CR == APFloat::cmpGreaterThan
- || CR == APFloat::cmpLessThan, E);
+ || CR == APFloat::cmpLessThan
+ || CR == APFloat::cmpUnordered, E);
}
}
@@ -1191,8 +1204,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
if (E->getOpcode() == BinaryOperator::Sub) {
- const QualType Type = E->getLHS()->getType();
- const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
+ QualType Type = E->getLHS()->getType();
+ QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
CharUnits ElementSize = CharUnits::One();
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
@@ -1365,6 +1378,85 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
}
+bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+ CharUnits Result;
+ unsigned n = E->getNumComponents();
+ OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E);
+ if (n == 0)
+ return false;
+ QualType CurrentType = E->getTypeSourceInfo()->getType();
+ for (unsigned i = 0; i != n; ++i) {
+ OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array: {
+ Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
+ APSInt IdxResult;
+ if (!EvaluateInteger(Idx, IdxResult, Info))
+ return false;
+ const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType);
+ if (!AT)
+ return false;
+ CurrentType = AT->getElementType();
+ CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
+ Result += IdxResult.getSExtValue() * ElementSize;
+ break;
+ }
+
+ case OffsetOfExpr::OffsetOfNode::Field: {
+ FieldDecl *MemberDecl = ON.getField();
+ const RecordType *RT = CurrentType->getAs<RecordType>();
+ if (!RT)
+ return false;
+ RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+ unsigned i = 0;
+ // FIXME: It would be nice if we didn't have to loop here!
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ Field != FieldEnd; (void)++Field, ++i) {
+ if (*Field == MemberDecl)
+ break;
+ }
+ assert(i < RL.getFieldCount() && "offsetof field in wrong type");
+ Result += CharUnits::fromQuantity(
+ RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
+ CurrentType = MemberDecl->getType().getNonReferenceType();
+ break;
+ }
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ llvm_unreachable("dependent __builtin_offsetof");
+ return false;
+
+ case OffsetOfExpr::OffsetOfNode::Base: {
+ CXXBaseSpecifier *BaseSpec = ON.getBase();
+ if (BaseSpec->isVirtual())
+ return false;
+
+ // Find the layout of the class whose base we are looking into.
+ const RecordType *RT = CurrentType->getAs<RecordType>();
+ if (!RT)
+ return false;
+ RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+
+ // Find the base class itself.
+ CurrentType = BaseSpec->getType();
+ const RecordType *BaseRT = CurrentType->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ // Add the offset to the base.
+ Result += CharUnits::fromQuantity(
+ RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()))
+ / Info.Ctx.getCharWidth());
+ break;
+ }
+ }
+ }
+ return Success(Result.getQuantity(), E);
+}
+
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
// Special case unary operators that do not need their subexpression
// evaluated. offsetof/sizeof/alignof are all special.
@@ -1373,12 +1465,12 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
// directly Evaluate it as an l-value.
APValue LV;
if (!EvaluateLValue(E->getSubExpr(), LV, Info))
- return false;
+ return false;
if (LV.getLValueBase())
- return false;
+ return false;
return Success(LV.getLValueOffset().getQuantity(), E);
}
-
+
if (E->getOpcode() == UnaryOperator::LNot) {
// LNot's operand isn't necessarily an integer, so we handle it specially.
bool bres;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 93edb42bf4c0..3782985e5302 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -15,15 +15,16 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
-#include <llvm/ADT/SmallSet.h>
-#include <llvm/Support/MathExtras.h>
+#include "llvm/Support/Format.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
-ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
- MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
- NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
+ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context)
+ : Context(Context), Size(0), Alignment(8), Packed(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false),
+ NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { }
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
/// no other data.
@@ -31,29 +32,29 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
// FIXME: Audit the corners
if (!RD->isDynamicClass())
return false;
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
- if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0))
+ const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
+ if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0))
return true;
return false;
}
void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
- Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo();
-
+ const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
+ Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
+
// If the record has a primary base class that is virtual, add it to the set
// of primary bases.
if (BaseInfo.isVirtual())
IndirectPrimaryBases.insert(BaseInfo.getBase());
-
+
// Now traverse all bases and find primary bases for them.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
assert(!i->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
+
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
if (Base->getNumVBases())
@@ -64,10 +65,10 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
void
ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
@@ -80,12 +81,12 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
/*IsVirtual=*/true);
return;
}
-
+
// Is this the first nearly empty virtual base?
if (!FirstNearlyEmptyVBase)
FirstNearlyEmptyVBase = Base;
}
-
+
SelectPrimaryVBase(Base);
if (PrimaryBase.getBase())
return;
@@ -97,11 +98,11 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the class isn't dynamic, it won't have a primary base.
if (!RD->isDynamicClass())
return;
-
+
// Compute all the primary virtual bases for all of our direct and
// indirect bases, and record all their primary virtual base classes.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
assert(!i->getType()->isDependentType() &&
"Cannot lay out class with dependent bases.");
const CXXRecordDecl *Base =
@@ -109,15 +110,15 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
IdentifyPrimaryBases(Base);
}
- // If the record has a dynamic base class, attempt to choose a primary base
- // class. It is the first (in direct base class order) non-virtual dynamic
+ // If the record has a dynamic base class, attempt to choose a primary base
+ // class. It is the first (in direct base class order) non-virtual dynamic
// base class, if one exists.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ e = RD->bases_end(); i != e; ++i) {
// Ignore virtual bases.
if (i->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
@@ -139,44 +140,47 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// Otherwise, it is the first nearly empty virtual base that is not an
// indirect primary virtual base class, if one exists.
if (FirstNearlyEmptyVBase) {
- PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase,
/*IsVirtual=*/true);
return;
}
-
+
// Otherwise there is no primary base class.
assert(!PrimaryBase.getBase() && "Should not get here with a primary base!");
// Allocate the virtual table pointer at offset zero.
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
-
+
// Update the size.
- Size += Ctx.Target.getPointerWidth(0);
+ Size += Context.Target.getPointerWidth(0);
DataSize = Size;
// Update the alignment.
- UpdateAlignment(Ctx.Target.getPointerAlign(0));
+ UpdateAlignment(Context.Target.getPointerAlign(0));
}
void
ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// First, determine the primary base class.
DeterminePrimaryBase(RD);
-
+
// If we have a primary base class, lay it out.
if (const CXXRecordDecl *Base = PrimaryBase.getBase()) {
if (PrimaryBase.isVirtual()) {
// We have a virtual primary base, insert it as an indirect primary base.
IndirectPrimaryBases.insert(Base);
+ assert(!VisitedVirtualBases.count(Base) && "vbase already visited!");
+ VisitedVirtualBases.insert(Base);
+
LayoutVirtualBase(Base);
} else
LayoutNonVirtualBase(Base);
}
-
+
// Now lay out the non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
// Ignore virtual bases.
if (I->isVirtual())
@@ -197,83 +201,113 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
// Layout the base.
uint64_t Offset = LayoutBase(RD);
-
+
// Add its base class offset.
if (!Bases.insert(std::make_pair(RD, Offset)).second)
assert(false && "Added same base offset more than once!");
}
-void
-ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+void
+ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD,
uint64_t Offset,
const CXXRecordDecl *MostDerivedClass) {
+ // We already have the offset for the primary base of the most derived class.
+ if (RD != MostDerivedClass) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // If this is a primary virtual base and we haven't seen it before, add it.
+ if (PrimaryBase && Layout.getPrimaryBaseWasVirtual() &&
+ !VBases.count(PrimaryBase))
+ VBases.insert(std::make_pair(PrimaryBase, Offset));
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot layout class with dependent bases.");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ if (!BaseDecl->getNumVBases()) {
+ // This base isn't interesting since it doesn't have any virtual bases.
+ continue;
+ }
+
+ // Compute the offset of this base.
+ uint64_t BaseOffset;
+
+ if (I->isVirtual()) {
+ // If we don't know this vbase yet, don't visit it. It will be visited
+ // later.
+ if (!VBases.count(BaseDecl)) {
+ continue;
+ }
+
+ // Check if we've already visited this base.
+ if (!VisitedVirtualBases.insert(BaseDecl))
+ continue;
+
+ // We want the vbase offset from the class we're currently laying out.
+ BaseOffset = VBases[BaseDecl];
+ } else if (RD == MostDerivedClass) {
+ // We want the base offset from the class we're currently laying out.
+ assert(Bases.count(BaseDecl) && "Did not find base!");
+ BaseOffset = Bases[BaseDecl];
+ } else {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ }
+
+ AddPrimaryVirtualBaseOffsets(BaseDecl, BaseOffset, MostDerivedClass);
+ }
+}
+
+void
+ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
+ const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase;
+ bool PrimaryBaseIsVirtual;
- if (MostDerivedClass == RD)
+ if (MostDerivedClass == RD) {
PrimaryBase = this->PrimaryBase.getBase();
- else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual();
+ } else {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
+ PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
if (I->isVirtual()) {
- bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
-
- // We only want to visit this virtual base if it's either a primary base,
- // or not an indirect primary base.
- if (Base == PrimaryBase || !IndirectPrimaryBase) {
- // Only lay things out once.
- if (!VisitedVirtualBases.insert(Base))
- continue;
-
- if (Base == PrimaryBase) {
- assert(IndirectPrimaryBase &&
- "Base is supposed to be an indirect primary base!");
-
- // We only want to add a vbase offset if this primary base is not the
- // primary base of the most derived class.
- if (PrimaryBase != this->PrimaryBase.getBase() ||
- !this->PrimaryBase.isVirtual()) {
- if (!VBases.insert(std::make_pair(Base, Offset)).second)
- assert(false && "Added same vbase offset more than once!");
- }
- } else {
- // We actually do want to lay out this base.
+ if (PrimaryBase != Base || !PrimaryBaseIsVirtual) {
+ bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
+
+ // Only lay out the virtual base if it's not an indirect primary base.
+ if (!IndirectPrimaryBase) {
+ // Only visit virtual bases once.
+ if (!VisitedVirtualBases.insert(Base))
+ continue;
+
LayoutVirtualBase(Base);
}
}
}
-
+
if (!Base->getNumVBases()) {
// This base isn't interesting since it doesn't have any virtual bases.
continue;
}
- // Compute the offset of this base.
- uint64_t BaseOffset;
-
- if (I->isVirtual()) {
- // We want the vbase offset from the class we're currently laying out.
- assert(VBases.count(Base) && "Did not find virtual base!");
- BaseOffset = VBases[Base];
- } else if (RD == MostDerivedClass) {
- // We want the base offset from the class we're currently laying out.
- assert(Bases.count(Base) && "Did not find base!");
- BaseOffset = Bases[Base];
- } else {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- }
-
- LayoutVirtualBases(Base, BaseOffset, MostDerivedClass);
+ LayoutVirtualBases(Base, MostDerivedClass);
}
}
@@ -287,7 +321,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
}
uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
// If we have an empty base class, try to place it at offset 0.
if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) {
@@ -298,17 +332,17 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
return 0;
}
-
+
unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
-
+
// Round up the current record size to the base's alignment boundary.
uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
-
+
// Try to place the base.
while (true) {
if (canPlaceRecordAtOffset(RD, Offset))
break;
-
+
Offset += BaseAlign;
}
@@ -327,44 +361,44 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
return Offset;
}
-bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
+bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
uint64_t Offset) const {
// Look for an empty class with the same type at the same offset.
- for (EmptyClassOffsetsTy::const_iterator I =
- EmptyClassOffsets.lower_bound(Offset),
- E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) {
-
+ for (EmptyClassOffsetsTy::const_iterator I =
+ EmptyClassOffsets.lower_bound(Offset),
+ E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) {
+
if (I->second == RD)
return false;
}
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
// Check bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (I->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
-
+
if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset))
return false;
}
-
+
// Check fields.
unsigned FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
+
uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
-
+
if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset))
return false;
}
@@ -373,35 +407,35 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
return true;
}
-bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
+bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD,
uint64_t Offset) const {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
return canPlaceRecordAtOffset(RD, Offset);
}
-
- if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
- QualType ElemTy = Ctx.getBaseElementType(AT);
+
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return true;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return true;
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
- uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
if (!canPlaceRecordAtOffset(RD, ElementOffset))
return false;
-
+
ElementOffset += Info.getSize();
}
}
-
+
return true;
}
@@ -409,39 +443,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
uint64_t Offset) {
if (RD->isEmpty())
EmptyClassOffsets.insert(std::make_pair(Offset, RD));
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
+
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
// Update bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ E = RD->bases_end(); I != E; ++I) {
assert(!I->getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
if (I->isVirtual())
continue;
-
+
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
+
uint64_t BaseClassOffset = Info.getBaseClassOffset(Base);
UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset);
}
-
+
// Update fields.
unsigned FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
+
uint64_t FieldOffset = Info.getFieldOffset(FieldNo);
UpdateEmptyClassOffsets(FD, Offset + FieldOffset);
}
-
+
// FIXME: Update virtual bases.
}
void
-ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
+ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
uint64_t Offset) {
QualType T = FD->getType();
@@ -451,19 +485,19 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD,
return;
}
}
-
- if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) {
- QualType ElemTy = Ctx.getBaseElementType(AT);
+
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
+ QualType ElemTy = Context.getBaseElementType(AT);
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
if (!RD)
return;
-
- const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD);
- uint64_t NumElements = Ctx.getConstantArrayElementCount(AT);
+ const ASTRecordLayout &Info = Context.getASTRecordLayout(RD);
+
+ uint64_t NumElements = Context.getConstantArrayElementCount(AT);
uint64_t ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
@@ -495,20 +529,50 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
- // If this is a C++ class, lay out its virtual bases.
- if (RD)
- LayoutVirtualBases(RD, 0, RD);
+ // If this is a C++ class, lay out its virtual bases and add its primary
+ // virtual base offsets.
+ if (RD) {
+ LayoutVirtualBases(RD, RD);
+
+ VisitedVirtualBases.clear();
+ AddPrimaryVirtualBaseOffsets(RD, 0, RD);
+ }
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
FinishLayout();
+
+#ifndef NDEBUG
+ if (RD) {
+ // Check that we have base offsets for all bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(Bases.count(BaseDecl) && "Did not find base offset!");
+ }
+
+ // And all virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ assert(VBases.count(BaseDecl) && "Did not find base offset!");
+ }
+ }
+#endif
}
// FIXME. Impl is no longer needed.
void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) {
if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
- const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
+ const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD);
UpdateAlignment(SL.getAlignment());
@@ -528,7 +592,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
- Ctx.ShallowCollectObjCIvars(D, Ivars);
+ Context.ShallowCollectObjCIvars(D, Ivars);
for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
LayoutField(Ivars[i]);
@@ -541,20 +605,82 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
+ uint64_t TypeSize) {
+ assert(Context.getLangOptions().CPlusPlus &&
+ "Can only have wide bit-fields in C++!");
+
+ // Itanium C++ ABI 2.4:
+ // If sizeof(T)*8 < n, let T' be the largest integral POD type with
+ // sizeof(T')*8 <= n.
+
+ QualType IntegralPODTypes[] = {
+ Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy,
+ Context.UnsignedLongTy, Context.UnsignedLongLongTy
+ };
+
+ QualType Type;
+ for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes);
+ I != E; ++I) {
+ uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]);
+
+ if (Size > FieldSize)
+ break;
+
+ Type = IntegralPODTypes[I];
+ }
+ assert(!Type.isNull() && "Did not find a type!");
+
+ unsigned TypeAlign = Context.getTypeAlign(Type);
+
+ // We're not going to use any of the unfilled bits in the last byte.
+ UnfilledBitsInLastByte = 0;
+
+ uint64_t FieldOffset;
+
+ if (IsUnion) {
+ DataSize = std::max(DataSize, FieldSize);
+ FieldOffset = 0;
+ } else {
+ // The bitfield is allocated starting at the next offset aligned appropriately
+ // for T', with length n bits.
+ FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign);
+
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+
+ DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+ UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ }
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Update the size.
+ Size = std::max(Size, DataSize);
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(TypeAlign);
+}
+
void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
- uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
-
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
-
- if (FieldPacked)
+
+ if (FieldSize > TypeSize) {
+ LayoutWideBitField(FieldSize, TypeSize);
+ return;
+ }
+
+ if (FieldPacked || !Context.Target.useBitFieldTypeAlignment())
FieldAlign = 1;
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
@@ -562,33 +688,32 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// The maximum field alignment overrides the aligned attribute.
if (MaxFieldAlignment)
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
-
- // Check if we need to add padding to give the field the correct
- // alignment.
+
+ // Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
-
- // Padding members don't affect overall alignment
+
+ // Padding members don't affect overall alignment.
if (!D->getIdentifier())
FieldAlign = 1;
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
-
+
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
DataSize = std::max(DataSize, FieldSize);
} else {
uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
+
DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
UnfilledBitsInLastByte = DataSize - NewSizeInBits;
}
-
+
// Update the size.
Size = std::max(Size, DataSize);
-
+
// Remember max struct/class alignment.
UpdateAlignment(FieldAlign);
}
@@ -606,21 +731,21 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
+
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
FieldSize = 0;
- const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
- FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ const ArrayType* ATy = Context.getAsArrayType(D->getType());
+ FieldAlign = Context.getTypeAlign(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
+ FieldSize = Context.Target.getPointerWidth(AS);
+ FieldAlign = Context.Target.getPointerAlign(AS);
} else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
}
@@ -636,20 +761,20 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
// Round up the current record size to the field's alignment boundary.
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
-
+
if (!IsUnion) {
while (true) {
// Check if we can place the field at this offset.
if (canPlaceFieldAtOffset(D, FieldOffset))
break;
-
+
// We couldn't place the field at the offset. Try again at a new offset.
FieldOffset += FieldAlign;
}
-
+
UpdateEmptyClassOffsets(D, FieldOffset);
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -668,7 +793,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
void ASTRecordLayoutBuilder::FinishLayout() {
// In C++, records cannot be of size 0.
- if (Ctx.getLangOptions().CPlusPlus && Size == 0)
+ if (Context.getLangOptions().CPlusPlus && Size == 0)
Size = 8;
// Finally, round the size of the record up to the alignment of the
// record itself.
@@ -735,7 +860,7 @@ const CXXMethodDecl *
ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
assert(RD->isDynamicClass() && "Class does not have any virtual methods!");
- // If a class isnt' polymorphic it doesn't have a key function.
+ // If a class isn't polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
@@ -745,13 +870,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace())
return 0;
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
-
+
if (!MD->isVirtual())
continue;
-
+
if (MD->isPure())
continue;
@@ -759,17 +884,134 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
// they don't have a body until they're defined.
if (MD->isImplicit())
continue;
-
+
if (MD->isInlineSpecified())
continue;
if (MD->hasInlineBody())
continue;
-
+
// We found it.
return MD;
}
-
+
return 0;
}
+static void PrintOffset(llvm::raw_ostream &OS,
+ uint64_t Offset, unsigned IndentLevel) {
+ OS << llvm::format("%4d | ", Offset);
+ OS.indent(IndentLevel * 2);
+}
+
+static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
+ const CXXRecordDecl *RD, ASTContext &C,
+ uint64_t Offset,
+ unsigned IndentLevel,
+ const char* Description,
+ bool IncludeVirtualBases) {
+ const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+
+ PrintOffset(OS, Offset, IndentLevel);
+ OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString();
+ if (Description)
+ OS << ' ' << Description;
+ if (RD->isEmpty())
+ OS << " (empty)";
+ OS << '\n';
+
+ IndentLevel++;
+
+ const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
+
+ // Vtable pointer.
+ if (RD->isDynamicClass() && !PrimaryBase) {
+ PrintOffset(OS, Offset, IndentLevel);
+ OS << '(' << RD << " vtable pointer)\n";
+ }
+ // Dump (non-virtual) bases
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot layout class with dependent bases.");
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
+
+ DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
+ Base == PrimaryBase ? "(primary base)" : "(base)",
+ /*IncludeVirtualBases=*/false);
+ }
+
+ // Dump fields.
+ uint64_t FieldNo = 0;
+ for (CXXRecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end(); I != E; ++I, ++FieldNo) {
+ const FieldDecl *Field = *I;
+ uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
+
+ if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
+ if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
+ Field->getNameAsCString(),
+ /*IncludeVirtualBases=*/true);
+ continue;
+ }
+ }
+
+ PrintOffset(OS, FieldOffset, IndentLevel);
+ OS << Field->getType().getAsString() << ' ' << Field << '\n';
+ }
+
+ if (!IncludeVirtualBases)
+ return;
+
+ // Dump virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ assert(I->isVirtual() && "Found non-virtual class!");
+ const CXXRecordDecl *VBase =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
+ DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel,
+ VBase == PrimaryBase ?
+ "(primary virtual base)" : "(virtual base)",
+ /*IncludeVirtualBases=*/false);
+ }
+
+ OS << " sizeof=" << Info.getSize() / 8;
+ OS << ", dsize=" << Info.getDataSize() / 8;
+ OS << ", align=" << Info.getAlignment() / 8 << '\n';
+ OS << " nvsize=" << Info.getNonVirtualSize() / 8;
+ OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
+ OS << '\n';
+}
+
+void ASTContext::DumpRecordLayout(const RecordDecl *RD,
+ llvm::raw_ostream &OS) {
+ const ASTRecordLayout &Info = getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0,
+ /*IncludeVirtualBases=*/true);
+
+ OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
+ OS << "Record: ";
+ RD->dump();
+ OS << "\nLayout: ";
+ OS << "<ASTRecordLayout\n";
+ OS << " Size:" << Info.getSize() << "\n";
+ OS << " DataSize:" << Info.getDataSize() << "\n";
+ OS << " Alignment:" << Info.getAlignment() << "\n";
+ OS << " FieldOffsets: [";
+ for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
+ if (i) OS << ", ";
+ OS << Info.getFieldOffset(i);
+ }
+ OS << "]>\n";
+}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index a4bce753126a..f277c29398b3 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -26,7 +26,7 @@ namespace clang {
class RecordDecl;
class ASTRecordLayoutBuilder {
- ASTContext &Ctx;
+ ASTContext &Context;
/// Size - The current size of the record layout.
uint64_t Size;
@@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder {
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
+ void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
void LayoutBitField(const FieldDecl *D);
/// DeterminePrimaryBase - Determine the primary base of the given class.
@@ -112,8 +113,11 @@ class ASTRecordLayoutBuilder {
/// LayoutNonVirtualBase - Lays out a single non-virtual base.
void LayoutNonVirtualBase(const CXXRecordDecl *RD);
+ void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
+ const CXXRecordDecl *MostDerivedClass);
+
/// LayoutVirtualBases - Lays out all the virtual bases.
- void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset,
+ void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 97023820e247..67fd74c288c7 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include <cstdio>
using namespace clang;
@@ -240,6 +241,8 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
// asm string.
std::string CurStringPiece;
+ bool HasVariants = !C.Target.hasNoAsmVariants();
+
while (1) {
// Done with the string?
if (CurPtr == StrEnd) {
@@ -251,9 +254,9 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
char CurChar = *CurPtr++;
switch (CurChar) {
case '$': CurStringPiece += "$$"; continue;
- case '{': CurStringPiece += "$("; continue;
- case '|': CurStringPiece += "$|"; continue;
- case '}': CurStringPiece += "$)"; continue;
+ case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
+ case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
+ case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
case '%':
break;
default:
@@ -389,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
RParenLoc = RPL;
}
-
-ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
- SourceLocation rparenloc,
- ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
- Stmt *atCatchList)
-: Stmt(ObjCAtCatchStmtClass) {
- ExceptionDecl = catchVarDecl;
- SubExprs[BODY] = atCatchStmt;
- SubExprs[NEXT_CATCH] = NULL;
- // FIXME: O(N^2) in number of catch blocks.
- if (atCatchList) {
- ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
-
- while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
- AtCatchList = NextCatch;
-
- AtCatchList->SubExprs[NEXT_CATCH] = this;
- }
- AtCatchLoc = atCatchLoc;
- RParenLoc = rparenloc;
+ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+ Stmt **CatchStmts, unsigned NumCatchStmts,
+ Stmt *atFinallyStmt)
+ : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
+ NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
+{
+ Stmt **Stmts = getStmts();
+ Stmts[0] = atTryStmt;
+ for (unsigned I = 0; I != NumCatchStmts; ++I)
+ Stmts[I + 1] = CatchStmts[I];
+
+ if (HasFinally)
+ Stmts[NumCatchStmts + 1] = atFinallyStmt;
+}
+
+ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
+ SourceLocation atTryLoc,
+ Stmt *atTryStmt,
+ Stmt **CatchStmts,
+ unsigned NumCatchStmts,
+ Stmt *atFinallyStmt) {
+ unsigned Size = sizeof(ObjCAtTryStmt) +
+ (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
+ void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
+ atFinallyStmt);
+}
+
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
+ unsigned NumCatchStmts,
+ bool HasFinally) {
+ unsigned Size = sizeof(ObjCAtTryStmt) +
+ (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
+ void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
+}
+
+SourceRange ObjCAtTryStmt::getSourceRange() const {
+ SourceLocation EndLoc;
+ if (HasFinally)
+ EndLoc = getFinallyStmt()->getLocEnd();
+ else if (NumCatchStmts)
+ EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+ else
+ EndLoc = getTryBody()->getLocEnd();
+
+ return SourceRange(AtTryLoc, EndLoc);
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
@@ -627,19 +657,18 @@ Stmt::child_iterator AsmStmt::child_end() {
}
// ObjCAtCatchStmt
-Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ObjCAtCatchStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
+Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
+Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
// ObjCAtFinallyStmt
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
// ObjCAtTryStmt
-Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
-Stmt::child_iterator ObjCAtTryStmt::child_end() {
- return &SubStmts[0]+END_EXPR;
+Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
+
+Stmt::child_iterator ObjCAtTryStmt::child_end() {
+ return getStmts() + 1 + NumCatchStmts + HasFinally;
}
// ObjCAtThrowStmt
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ba6218be1426..ca62ed12d058 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -143,6 +143,7 @@ namespace {
void DumpCXXTemporary(CXXTemporary *Temporary);
// ObjC
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
void VisitObjCMessageExpr(ObjCMessageExpr* Node);
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
@@ -219,7 +220,7 @@ void StmtDumper::DumpDeclarator(Decl *D) {
// nodes are where they need to be.
if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << " " << localType->getNameAsString() << "\"";
+ << ' ' << localType << '"';
} else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
OS << "\"";
// Emit storage class for vardecls.
@@ -299,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) {
DumpExpr(Node);
}
+static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) {
+ if (Node->getBasePath().empty())
+ return;
+
+ OS << " (";
+ bool First = true;
+ for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(),
+ E = Node->getBasePath().end(); I != E; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ if (!First)
+ OS << " -> ";
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual())
+ OS << "virtual ";
+ OS << RD->getName();
+ First = false;
+ }
+
+ OS << ')';
+}
+
void StmtDumper::VisitCastExpr(CastExpr *Node) {
DumpExpr(Node);
- OS << " <" << Node->getCastKindName() << ">";
+ OS << " <" << Node->getCastKindName();
+ DumpBasePath(OS, Node);
+ OS << ">";
}
void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
@@ -328,15 +355,14 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
case Decl::ObjCClass: OS << "ObjCClass"; break;
}
- OS << "='" << Node->getDecl()->getNameAsString()
- << "' " << (void*)Node->getDecl();
+ OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl();
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
DumpExpr(Node);
OS << " (";
if (!Node->requiresADL()) OS << "no ";
- OS << "ADL) = '" << Node->getName().getAsString() << "'";
+ OS << "ADL) = '" << Node->getName() << '\'';
UnresolvedLookupExpr::decls_iterator
I = Node->decls_begin(), E = Node->decls_end();
@@ -349,7 +375,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << Node->getDecl()->getNameAsString()
+ << "Decl='" << Node->getDecl()
<< "' " << (void*)Node->getDecl();
if (Node->isFreeIvar())
OS << " isFreeIvar";
@@ -408,7 +434,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
DumpExpr(Node);
OS << " " << (Node->isArrow() ? "->" : ".")
- << Node->getMemberDecl()->getNameAsString() << " "
+ << Node->getMemberDecl() << ' '
<< (void*)Node->getMemberDecl();
}
void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
@@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
DumpExpr(Node);
OS << " " << Node->getCastName()
<< "<" << Node->getTypeAsWritten().getAsString() << ">"
- << " <" << Node->getCastKindName() << ">";
+ << " <" << Node->getCastKindName();
+ DumpBasePath(OS, Node);
+ OS << ">";
}
void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
@@ -506,8 +534,33 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
DumpExpr(Node);
OS << " selector=" << Node->getSelector().getAsString();
- if (IdentifierInfo *clsName = Node->getClassName())
- OS << " class=" << clsName->getNameStart();
+ switch (Node->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << " class=";
+ DumpType(Node->getClassReceiver());
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ OS << " super (instance)";
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OS << " super (class)";
+ break;
+ }
+}
+
+void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
+ DumpStmt(Node);
+ if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
+ OS << " catch parm = ";
+ DumpDeclarator(CatchParam);
+ } else {
+ OS << " catch all";
+ }
}
void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
@@ -525,14 +578,13 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
DumpExpr(Node);
- OS << " " << Node->getProtocol()->getNameAsString();
+ OS << ' ' << Node->getProtocol();
}
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
- OS << " Kind=PropertyRef Property=\""
- << Node->getProperty()->getNameAsString() << "\"";
+ OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"';
}
void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index da43878628fb..52f627d449e2 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/Format.h"
+#include "clang/AST/Expr.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -388,11 +389,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
OS << "\n";
}
- for (ObjCAtCatchStmt *catchStmt =
- static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
- catchStmt;
- catchStmt =
- static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
+ for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I);
Indent() << "@catch(";
if (catchStmt->getCatchParamDecl()) {
if (Decl *DS = catchStmt->getCatchParamDecl())
@@ -474,7 +472,7 @@ void StmtPrinter::VisitExpr(Expr *Node) {
void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
if (Node->hasExplicitTemplateArgumentList())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
@@ -509,7 +507,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
}
void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
@@ -527,7 +525,7 @@ void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr(
OS << ".";
}
if (Node->getGetterMethod())
- OS << Node->getGetterMethod()->getNameAsString();
+ OS << Node->getGetterMethod();
}
@@ -695,7 +693,7 @@ bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
} else {
MemberExpr *ME = cast<MemberExpr>(E);
bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
- OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString();
+ OS << (IsFirst ? "" : ".") << ME->getMemberDecl();
return false;
}
}
@@ -706,6 +704,39 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
OS << ")";
}
+void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
+ OS << "__builtin_offsetof(";
+ OS << Node->getTypeSourceInfo()->getType().getAsString() << ", ";
+ bool PrintedSomething = false;
+ for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
+ OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) {
+ // Array node
+ OS << "[";
+ PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
+ OS << "]";
+ PrintedSomething = true;
+ continue;
+ }
+
+ // Skip implicit base indirections.
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+ continue;
+
+ // Field or identifier node.
+ IdentifierInfo *Id = ON.getFieldName();
+ if (!Id)
+ continue;
+
+ if (PrintedSomething)
+ OS << ".";
+ else
+ PrintedSomething = true;
+ OS << Id->getName();
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
if (Node->isArgumentType())
@@ -746,7 +777,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- OS << Node->getMemberDecl()->getNameAsString();
+ OS << Node->getMemberDecl();
if (Node->hasExplicitTemplateArgumentList())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -1242,14 +1273,26 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
}
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')';
+ OS << "@protocol(" << Node->getProtocol() << ')';
}
void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "[";
- Expr *receiver = Mess->getReceiver();
- if (receiver) PrintExpr(receiver);
- else OS << Mess->getClassName()->getName();
+ switch (Mess->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ PrintExpr(Mess->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << Mess->getClassReceiver().getAsString(Policy);
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ case ObjCMessageExpr::SuperClass:
+ OS << "Super";
+ break;
+ }
+
OS << ' ';
Selector selector = Mess->getSelector();
if (selector.isUnarySelector()) {
@@ -1304,7 +1347,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
- OS << Node->getDecl()->getNameAsString();
+ OS << Node->getDecl();
}
//===----------------------------------------------------------------------===//
// Stmt method implementations
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 3a19ec212c14..d45bb2f010c0 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -261,6 +261,34 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) {
ID.AddInteger(S->getOpcode());
}
+void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
+ VisitType(S->getTypeSourceInfo()->getType());
+ unsigned n = S->getNumComponents();
+ for (unsigned i = 0; i < n; ++i) {
+ const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i);
+ ID.AddInteger(ON.getKind());
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ // Expressions handled below.
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ VisitDecl(ON.getField());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ ID.AddPointer(ON.getFieldName());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // These nodes are implicit, and therefore don't need profiling.
+ break;
+ }
+ }
+
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isSizeOf());
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index b56c0cebfa58..14722f70398c 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -15,9 +15,11 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using namespace llvm;
TemplateDecl *TemplateName::getAsTemplateDecl() const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
@@ -45,13 +47,13 @@ void
TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
- OS << Template->getNameAsString();
+ OS << Template;
else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (!SuppressNNS)
QTN->getQualifier()->print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
- OS << QTN->getDecl()->getNameAsString();
+ OS << QTN->getDecl();
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
if (!SuppressNNS && DTN->getQualifier())
DTN->getQualifier()->print(OS, Policy);
@@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
}
}
+const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
+ TemplateName N) {
+ std::string NameStr;
+ raw_string_ostream OS(NameStr);
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ LO.Bool = true;
+ N.print(OS, PrintingPolicy(LO));
+ OS.flush();
+ return DB << NameStr;
+}
+
void TemplateName::dump() const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 27a277ddbcb0..05e7fdc49e35 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -225,6 +225,11 @@ bool Type::isStructureType() const {
return RT->getDecl()->isStruct();
return false;
}
+bool Type::isStructureOrClassType() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return RT->getDecl()->isStruct() || RT->getDecl()->isClass();
+ return false;
+}
bool Type::isVoidPointerType() const {
if (const PointerType *PT = getAs<PointerType>())
return PT->getPointeeType()->isVoidType();
@@ -410,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
return 0;
}
+CXXRecordDecl *Type::getAsCXXRecordDecl() const {
+ if (const RecordType *RT = getAs<RecordType>())
+ return dyn_cast<CXXRecordDecl>(RT->getDecl());
+ else if (const InjectedClassNameType *Injected
+ = getAs<InjectedClassNameType>())
+ return Injected->getDecl();
+
+ return 0;
+}
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
@@ -999,12 +1014,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
TemplateSpecializationType::
TemplateSpecializationType(ASTContext &Context, TemplateName T,
+ bool IsCurrentInstantiation,
const TemplateArgument *Args,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
- Context(Context),
+ ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation),
Template(T), NumArgs(NumArgs) {
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
@@ -1039,9 +1055,11 @@ TemplateSpecializationType::getArg(unsigned Idx) const {
void
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateName T,
+ bool IsCurrentInstantiation,
const TemplateArgument *Args,
unsigned NumArgs,
ASTContext &Context) {
+ ID.AddBoolean(IsCurrentInstantiation);
T.Profile(ID);
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
Args[Idx].Profile(ID, Context);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 340e373af123..915d7af9a8c3 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -29,7 +29,7 @@ namespace {
public:
explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
-
+
void Print(QualType T, std::string &S);
void AppendScope(DeclContext *DC, std::string &S);
void PrintTag(TagDecl *T, std::string &S);
@@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization(
void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
std::string &S) {
- PrintTemplateSpecialization(T->getUnderlyingTST(), S);
+ PrintTemplateSpecialization(T->getInjectedTST(), S);
}
void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index f94f6b3f127f..7f71e0acf7a3 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -46,7 +46,7 @@ public:
AddStmtChoice(Kind kind) : k(kind) {}
bool alwaysAdd() const { return (unsigned)k & 0x1; }
- bool asLValue() const { return k >= AlwaysAddAsLValue; }
+ bool asLValue() const { return k >= AsLValueNotAlwaysAdd; }
private:
Kind k;
@@ -108,16 +108,16 @@ private:
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
+ CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
+ CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
+ CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
+ CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
- CFGBlock *VisitConditionalOperator(ConditionalOperator *C,
- AddStmtChoice asc);
+ CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
- CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
- CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
- CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -127,6 +127,7 @@ private:
CFGBlock *VisitIfStmt(IfStmt *I);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
CFGBlock *VisitLabelStmt(LabelStmt *L);
+ CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
@@ -337,6 +338,10 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) {
/// DeclStmts (which may contain nested control-flow).
CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
tryAgain:
+ if (!S) {
+ badCFG = true;
+ return 0;
+ }
switch (S->getStmtClass()) {
default:
return VisitStmt(S, asc);
@@ -374,6 +379,9 @@ tryAgain:
case Stmt::CXXCatchStmtClass:
return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
+ case Stmt::CXXMemberCallExprClass:
+ return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc);
+
case Stmt::CXXThrowExprClass:
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
@@ -404,6 +412,9 @@ tryAgain:
case Stmt::LabelStmtClass:
return VisitLabelStmt(cast<LabelStmt>(S));
+ case Stmt::MemberExprClass:
+ return VisitMemberExpr(cast<MemberExpr>(S), asc);
+
case Stmt::ObjCAtCatchStmtClass:
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
@@ -491,8 +502,16 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
Succ = ConfluenceBlock;
Block = NULL;
CFGBlock* RHSBlock = addStmt(B->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
+
+ if (RHSBlock) {
+ if (!FinishBlock(RHSBlock))
+ return 0;
+ }
+ else {
+ // Create an empty block for cases where the RHS doesn't require
+ // any explicit statements in the CFG.
+ RHSBlock = createBlock();
+ }
// See if this is a known constant.
TryResult KnownVal = TryEvaluateBool(B->getLHS());
@@ -627,15 +646,18 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
if (!FinishBlock(ConfluenceBlock))
return 0;
+ asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* LHSBlock = addStmt(C->getLHS());
+ CFGBlock* LHSBlock = addStmt(C->getLHS(), asc);
if (!FinishBlock(LHSBlock))
return 0;
Succ = ConfluenceBlock;
Block = NULL;
- CFGBlock* RHSBlock = addStmt(C->getRHS());
+ CFGBlock* RHSBlock = addStmt(C->getRHS(), asc);
if (!FinishBlock(RHSBlock))
return 0;
@@ -676,6 +698,9 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
if (!FinishBlock(ConfluenceBlock))
return 0;
+ asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+
// Create a block for the LHS expression if there is an LHS expression. A
// GCC extension allows LHS to be NULL, causing the condition to be the
// value that is returned instead.
@@ -684,7 +709,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
Block = NULL;
CFGBlock* LHSBlock = NULL;
if (C->getLHS()) {
- LHSBlock = addStmt(C->getLHS());
+ LHSBlock = addStmt(C->getLHS(), asc);
if (!FinishBlock(LHSBlock))
return 0;
Block = NULL;
@@ -692,7 +717,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
// Create the block for the RHS expression.
Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = addStmt(C->getRHS());
+ CFGBlock* RHSBlock = addStmt(C->getRHS(), asc);
if (!FinishBlock(RHSBlock))
return 0;
@@ -1074,6 +1099,16 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
}
}
+CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
+ if (asc.alwaysAdd()) {
+ autoCreateBlock();
+ AppendStmt(Block, M, asc);
+ }
+ return Visit(M->getBase(),
+ M->isArrow() ? AddStmtChoice::NotAlwaysAdd
+ : AddStmtChoice::AsLValueNotAlwaysAdd);
+}
+
CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// Objective-C fast enumeration 'for' statements:
// http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
@@ -1694,6 +1729,15 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
return CatchBlock;
}
+CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
+ AddStmtChoice asc) {
+ AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue
+ : AddStmtChoice::AlwaysAdd;
+ autoCreateBlock();
+ AppendStmt(Block, C, AddStmtChoice(K));
+ return VisitChildren(C);
+}
+
CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
// Lazily create the indirect-goto dispatch block if there isn't one already.
CFGBlock* IBlock = cfg->getIndirectGotoBlock();
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 2b7fcd07f9d0..1870195ded03 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -11,24 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/PartialDiagnostic.h"
-
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/AST/ASTDiagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Analysis/AnalysisDiagnostic.h"
-#include "clang/Driver/DriverDiagnostic.h"
-
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+
#include <vector>
#include <map>
#include <cstring>
@@ -223,9 +223,12 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
- NumDiagnostics = 0;
-
+ ErrorLimit = 0;
+ TemplateBacktraceLimit = 0;
+
+ NumWarnings = 0;
NumErrors = 0;
+ NumErrorsSuppressed = 0;
CustomDiagInfo = 0;
CurDiagID = ~0U;
LastDiagLevel = Ignored;
@@ -286,11 +289,18 @@ bool Diagnostic::isBuiltinNote(unsigned DiagID) {
}
/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic
-/// ID is for an extension of some sort.
+/// ID is for an extension of some sort. This also returns EnabledByDefault,
+/// which is set to indicate whether the diagnostic is ignored by default (in
+/// which case -pedantic enables it) or treated as a warning/error by default.
///
-bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) {
- return DiagID < diag::DIAG_UPPER_LIMIT &&
- getBuiltinDiagClass(DiagID) == CLASS_EXTENSION;
+bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID,
+ bool &EnabledByDefault) {
+ if (DiagID >= diag::DIAG_UPPER_LIMIT ||
+ getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
+ return false;
+
+ EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE;
+ return true;
}
@@ -529,8 +539,14 @@ bool Diagnostic::ProcessDiag() {
// If a fatal error has already been emitted, silence all subsequent
// diagnostics.
- if (FatalErrorOccurred)
+ if (FatalErrorOccurred) {
+ if (DiagLevel >= Diagnostic::Error) {
+ ++NumErrors;
+ ++NumErrorsSuppressed;
+ }
+
return false;
+ }
// If the client doesn't care about this message, don't issue it. If this is
// a note and the last real diagnostic was ignored, ignore it too.
@@ -551,11 +567,20 @@ bool Diagnostic::ProcessDiag() {
if (DiagLevel >= Diagnostic::Error) {
ErrorOccurred = true;
++NumErrors;
+
+ // If we've emitted a lot of errors, emit a fatal error after it to stop a
+ // flood of bogus errors.
+ if (ErrorLimit && NumErrors >= ErrorLimit &&
+ DiagLevel == Diagnostic::Error)
+ SetDelayedDiagnostic(diag::fatal_too_many_errors);
}
// Finally, report it.
Client->HandleDiagnostic(DiagLevel, Info);
- if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
+ if (Client->IncludeInDiagnosticCounts()) {
+ if (DiagLevel == Diagnostic::Warning)
+ ++NumWarnings;
+ }
CurDiagID = ~0U;
@@ -1026,8 +1051,15 @@ static void WriteSourceLocation(llvm::raw_ostream &OS,
Location = SM->getInstantiationLoc(Location);
std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
-
- WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
+
+ const FileEntry *FE = SM->getFileEntryForID(Decomposed.first);
+ if (FE)
+ WriteString(OS, FE->getName());
+ else {
+ // Fallback to using the buffer name when there is no entry.
+ WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier());
+ }
+
WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 3da19ca16d5d..ed0de8c4af09 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -78,9 +78,9 @@ namespace {
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
///
-/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be
+/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be
/// enabled in the specified langauge, set to 1 if it is an extension
-/// in the specified language, and set to 2 if disabled in the
+/// in the specified language, and set to 0 if disabled in the
/// specified language.
static void AddKeyword(llvm::StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
@@ -90,7 +90,7 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
- else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
+ else if (LangOpts.GNUKeywords && (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;
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 27cb9bebde42..3ecab1d8c16f 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -60,6 +60,8 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) {
}
const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
+ const SourceManager &SM,
+ SourceLocation Loc,
bool *Invalid) const {
if (Invalid)
*Invalid = false;
@@ -94,22 +96,67 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
Entry->getName(), ErrorStr);
else
- Diag.Report(diag::err_cannot_open_file)
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file)
<< Entry->getName() << ErrorStr;
Buffer.setInt(true);
+
+ // FIXME: This conditionalization is horrible, but we see spurious failures
+ // in the test suite due to this warning and no one has had time to hunt it
+ // down. So for now, we just don't emit this diagnostic on Win32, and hope
+ // nothing bad happens.
+ //
+ // PR6812.
+#if !defined(LLVM_ON_WIN32)
} else if (FileInfo.st_size != Entry->getSize() ||
FileInfo.st_mtime != Entry->getModificationTime()) {
- // Check that the file's size, modification time, and inode are
- // the same as in the file entry (which may have come from a
- // stat cache).
+ // Check that the file's size and modification time are the same
+ // as in the file entry (which may have come from a stat cache).
if (Diag.isDiagnosticInFlight())
- Diag.SetDelayedDiagnostic(diag::err_file_modified,
+ Diag.SetDelayedDiagnostic(diag::err_file_modified,
Entry->getName());
- else
- Diag.Report(diag::err_file_modified) << Entry->getName();
+ else
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified)
+ << Entry->getName();
Buffer.setInt(true);
+#endif
+ }
+
+ // If the buffer is valid, check to see if it has a UTF Byte Order Mark
+ // (BOM). We only support UTF-8 without a BOM right now. See
+ // http://en.wikipedia.org/wiki/Byte_order_mark for more information.
+ if (!Buffer.getInt()) {
+ llvm::StringRef BufStr = Buffer.getPointer()->getBuffer();
+ const char *BOM = 0;
+ if (BufStr.startswith("\xFE\xBB\xBF"))
+ BOM = "UTF-8";
+ else if (BufStr.startswith("\xFE\xFF"))
+ BOM = "UTF-16 (BE)";
+ else if (BufStr.startswith("\xFF\xFE"))
+ BOM = "UTF-16 (LE)";
+ else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4)))
+ BOM = "UTF-32 (BE)";
+ else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4)))
+ BOM = "UTF-32 (LE)";
+ else if (BufStr.startswith("\x2B\x2F\x76"))
+ BOM = "UTF-7";
+ else if (BufStr.startswith("\xF7\x64\x4C"))
+ BOM = "UTF-1";
+ else if (BufStr.startswith("\xDD\x73\x66\x73"))
+ BOM = "UTF-EBCDIC";
+ else if (BufStr.startswith("\x0E\xFE\xFF"))
+ BOM = "SDSU";
+ else if (BufStr.startswith("\xFB\xEE\x28"))
+ BOM = "BOCU-1";
+ else if (BufStr.startswith("\x84\x31\x95\x33"))
+ BOM = "BOCU-1";
+
+ if (BOM) {
+ Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom)
+ << BOM << Entry->getName();
+ Buffer.setInt(1);
+ }
}
}
@@ -470,7 +517,7 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File,
bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return IR->getBuffer(Diag, Invalid);
+ return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
}
bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -717,8 +764,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
// Note that calling 'getBuffer()' may lazily page in a source file.
bool CharDataInvalid = false;
const llvm::MemoryBuffer *Buffer
- = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag,
- &CharDataInvalid);
+ = getSLocEntry(LocInfo.first).getFile().getContentCache()
+ ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -757,14 +804,16 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag,
- ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc,
- bool &Invalid);
-static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc, bool &Invalid) {
+static DISABLE_INLINE void
+ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+ llvm::BumpPtrAllocator &Alloc,
+ const SourceManager &SM, bool &Invalid);
+static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
+ llvm::BumpPtrAllocator &Alloc,
+ const SourceManager &SM, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
- const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid);
+ const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(),
+ &Invalid);
if (Invalid)
return;
@@ -825,7 +874,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
if (MyInvalid)
@@ -991,8 +1040,11 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// To get the source name, first consult the FileEntry (if one exists)
// before the MemBuffer as this will avoid unnecessarily paging in the
// MemBuffer.
- const char *Filename =
- C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier();
+ const char *Filename;
+ if (C->Entry)
+ Filename = C->Entry->getName();
+ else
+ Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second);
unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second);
SourceLocation IncludeLoc = FI.getIncludeLoc();
@@ -1050,7 +1102,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
/// SourceLineCache for it on demand.
if (Content->SourceLineCache == 0) {
bool MyInvalid = false;
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (MyInvalid)
return SourceLocation();
}
@@ -1082,15 +1134,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
return SourceLocation();
if (Line > Content->NumLines) {
- unsigned Size = Content->getBuffer(Diag)->getBufferSize();
+ unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
if (Size > 0)
--Size;
return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size);
}
unsigned FilePos = Content->SourceLineCache[Line - 1];
- const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos;
- unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf;
+ const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos;
+ unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf;
unsigned i = 0;
// Check that the given column is valid.
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 136089fe90c2..4c0c59a109e7 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -20,10 +20,10 @@ using namespace clang;
// TargetInfo Constructor.
TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
- // Set defaults. Defaults are set for a 32-bit RISC platform,
- // like PPC or SPARC.
- // These should be overridden by concrete targets as needed.
+ // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or
+ // SPARC. These should be overridden by concrete targets as needed.
TLSSupported = true;
+ NoAsmVariants = false;
PointerWidth = PointerAlign = 32;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
@@ -45,6 +45,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
SigAtomicType = SignedInt;
+ UseBitFieldTypeAlignment = true;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -142,9 +143,10 @@ bool TargetInfo::isTypeSigned(IntType T) const {
/// Apply changes to the target information with respect to certain
/// language options which change the target configuration.
void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
- if (Opts.ShortWChar) {
+ if (Opts.NoBitFieldTypeAlign)
+ UseBitFieldTypeAlignment = false;
+ if (Opts.ShortWChar)
WCharType = UnsignedShort;
- }
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 1797804a7aab..3d5048ccb9bf 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -219,6 +219,8 @@ protected:
Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
}
public:
LinuxTargetInfo(const std::string& triple)
@@ -1221,6 +1223,27 @@ public:
Builder.defineMacro("__CYGWIN__");
Builder.defineMacro("__CYGWIN32__");
DefineStd(Builder, "unix", Opts);
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
+};
+} // end anonymous namespace
+
+namespace {
+// x86-32 Haiku target
+class HaikuX86_32TargetInfo : public X86_32TargetInfo {
+public:
+ HaikuX86_32TargetInfo(const std::string& triple)
+ : X86_32TargetInfo(triple) {
+ SizeType = UnsignedLong;
+ IntPtrType = SignedLong;
+ PtrDiffType = SignedLong;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__INTEL__");
+ Builder.defineMacro("__HAIKU__");
}
};
} // end anonymous namespace
@@ -1373,6 +1396,10 @@ public:
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
+ // {} in inline assembly are neon specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
if (IsThumb) {
@@ -1397,6 +1424,10 @@ public:
DoubleAlign = LongLongAlign = LongDoubleAlign = 32;
SizeType = UnsignedLong;
+ // Do not respect the alignment of bit-field types when laying out
+ // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
+ UseBitFieldTypeAlignment = false;
+
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
@@ -2351,6 +2382,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MinGWX86_32TargetInfo(T);
case llvm::Triple::Win32:
return new VisualStudioWindowsX86_32TargetInfo(T);
+ case llvm::Triple::Haiku:
+ return new HaikuX86_32TargetInfo(T);
default:
return new X86_32TargetInfo(T);
}
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 810d0fbb997a..e7275ca551c2 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -31,13 +31,22 @@
using namespace clang;
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- const Expr* Receiver = ME->getReceiver();
-
- if (!Receiver)
- return NULL;
+ QualType T;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ T = ME->getInstanceReceiver()->getType();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ T = ME->getSuperType();
+ break;
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ return 0;
+ }
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
return PT->getInterfaceType();
return NULL;
@@ -509,11 +518,21 @@ public:
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
-
- const IdentifierInfo *ClsName = ME->getClassName();
- if (!ClsName)
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
return;
-
+ }
+
Selector S = ME->getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
- "of class '" << ClsName->getName()
+ "of class '" << Class->getName()
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 7c5399113df7..34470af29f4a 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
const VarDecl *VD = VR->getDecl();
// BasicStore does not model arrays and structs.
- if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
+ if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType())
return store;
if (VD->hasGlobalStorage()) {
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 4475872ee2dc..3bcc03f4f29c 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (D) {
GetRawInt = false;
- os << D->getNameAsString();
+ os << D;
}
}
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 06cee5bcd1bc..776e12bd2ae4 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
}
const Stmt*
-clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
- return ME->getReceiver();
- return NULL;
-}
-
-const Stmt*
clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
@@ -144,7 +136,7 @@ public:
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
+ os << "Variable '" << VR->getDecl() << "' ";
}
else
return NULL;
@@ -206,7 +198,7 @@ public:
return NULL;
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << VR->getDecl()->getNameAsString() << '\'';
+ os << '\'' << VR->getDecl() << '\'';
}
else
return NULL;
@@ -402,7 +394,7 @@ public:
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 3c4a27cc07f4..d26ee1db5653 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -603,12 +603,33 @@ public:
Selector S = ME->getSelector();
- if (Expr* Receiver = ME->getReceiver()) {
- const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
- return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+ const ObjCInterfaceDecl* OD = 0;
+ bool IsInstanceMessage = false;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ OD = getReceiverDecl(ME->getInstanceReceiver());
+ IsInstanceMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ IsInstanceMessage = true;
+ OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+
+ case ObjCMessageExpr::Class:
+ OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
}
- return M[ObjCSummaryKey(ME->getClassName(), S)];
+ if (IsInstanceMessage)
+ return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+
+ return M[ObjCSummaryKey(OD->getIdentifier(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
@@ -836,7 +857,7 @@ public:
RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+ return getInstanceMethodSummary(ME->getSelector(), 0,
ID, ME->getMethodDecl(), ME->getType());
}
@@ -851,8 +872,21 @@ public:
QualType RetTy);
RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
- ME->getClassInfo().Decl,
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getReceiverInterface();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
+ break;
+ }
+
+ return getClassMethodSummary(ME->getSelector(),
+ Class? Class->getIdentifier() : 0,
+ Class,
ME->getMethodDecl(), ME->getType());
}
@@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
- SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+ SVal receiverV;
+
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ receiverV = state->getSValAsScalarOrLoc(Receiver);
- // FIXME: Eventually replace the use of state->get<RefBindings> with
- // a generic API for reasoning about the Objective-C types of symbolic
- // objects.
- if (SymbolRef Sym = receiverV.getAsLocSymbol())
- if (const RefVal *T = state->get<RefBindings>(Sym))
- if (const ObjCObjectPointerType* PT =
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ ID = PT->getInterfaceDecl();
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+ } else {
+ // FIXME: Hack for 'super'.
+ ID = ME->getReceiverInterface();
}
-
+
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
// Get the region associated with 'self'.
if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
// Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
if (const FunctionDecl* FD = X.getAsFunctionDecl())
- os << "Call to function '" << FD->getNameAsString() <<'\'';
+ os << "Call to function '" << FD << '\'';
else
os << "function call";
}
@@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- if (const Expr *receiver = ME->getReceiver())
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
@@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
- const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
+ const ObjCInterfaceDecl *D = ME->getReceiverInterface();
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}
@@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- assert(Receiver);
- SVal V = state->getSValAsScalarOrLoc(Receiver);
bool found = false;
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
-
+ if (Receiver) {
+ SVal V = state->getSValAsScalarOrLoc(Receiver);
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state->get<RefBindings>(Sym)) {
+ found = true;
+ RE = Summaries.getObjAllocRetEffect();
+ }
+ } // FIXME: Otherwise, this is a send-to-super instance message.
if (!found)
RE = RetEffect::MakeNoRet();
}
@@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
ExplodedNode* Pred,
const GRState *state) {
RetainSummary *Summ =
- ME->getReceiver()
+ ME->isInstanceMessage()
? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index dec375e65da7..82e93a425e6e 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangChecker
FlatStore.cpp
GRBlockCounter.cpp
GRCoreEngine.cpp
+ GRCXXExprEngine.cpp
GRExprEngine.cpp
GRExprEngineExperimentalChecks.cpp
GRState.cpp
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index dd1856c9d2d6..c619d75479ed 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
- os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
- << "')";
+ os << " (e.g., field: '" << F.FieldChain[0] << "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
@@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
first = false;
else
os << '.';
- os << (*DI)->getNameAsString();
+ os << *DI;
}
os << "')";
}
@@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const GRState *state = C.getState();
- if (const Expr *receiver = ME->getReceiver())
+ // FIXME: Handle 'super'?
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_undef)
@@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- const Expr *receiver = ME->getReceiver();
- report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ if (const Expr *receiver = ME->getInstanceReceiver()) {
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ }
C.EmitReport(report);
}
@@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
- if (CanRetTy->isStructureType()) {
+ if (CanRetTy->isStructureOrClassType()) {
// FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
// have the "use of undefined value" be smarter about where the
// undefined value came from.
diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index 2c16f8905811..eeaed970b533 100644
--- a/lib/Checker/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
QualType OrigPointeeTy = OrigPTy->getPointeeType();
QualType ToPointeeTy = ToPTy->getPointeeType();
- if (!ToPointeeTy->isStructureType())
+ if (!ToPointeeTy->isStructureOrClassType())
return;
// We allow cast from void*.
diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index d9606f1306d4..c23be873f481 100644
--- a/lib/Checker/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -27,10 +27,14 @@ using namespace clang;
static bool scan_dealloc(Stmt* S, Selector Dealloc) {
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
- return isa<ObjCSuperExpr>(Receiver);
+ if (ME->getSelector() == Dealloc) {
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: return false;
+ case ObjCMessageExpr::SuperInstance: return true;
+ case ObjCMessageExpr::Class: break;
+ case ObjCMessageExpr::SuperClass: break;
+ }
+ }
// Recurse to children.
@@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
@@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "Objective-C class '" << D->getNameAsString()
- << "' lacks a 'dealloc' instance method";
+ os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
@@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '"
- << D->getNameAsString()
+ os << "The 'dealloc' instance method in Objective-C class '" << D
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
@@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "missing ivar release (leak)"
: "missing ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was retained by a synthesized property but "
"wasn't released in 'dealloc'";
} else {
@@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "extra ivar release (use-after-release)"
: "extra ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was not retained by a synthesized property "
"but was released in 'dealloc'";
}
diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp
index 8c43a45d92c0..76a092393bb4 100644
--- a/lib/Checker/CheckObjCInstMethSignature.cpp
+++ b/lib/Checker/CheckObjCInstMethSignature.cpp
@@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
llvm::raw_string_ostream os(sbuf);
os << "The Objective-C class '"
- << MethDerived->getClassInterface()->getNameAsString()
+ << MethDerived->getClassInterface()
<< "', which is derived from class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "', defines the instance method '"
<< MethDerived->getSelector().getAsString()
<< "' whose return type is '"
<< ResDerived.getAsString()
<< "'. A method with the same name (same selector) is also defined in "
"class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "' and has a return type of '"
<< ResAncestor.getAsString()
<< "'. These two types are incompatible, and may result in undefined "
diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index efbce6126146..74e12b18a81a 100644
--- a/lib/Checker/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
+ os1 << '\'' << FD << "' is a poor random number generator";
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "Function '" << FD->getNameAsString()
+ os2 << "Function '" << FD
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
@@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "Return value is not checked in call to '" << FD->getNameAsString()
- << "'";
+ os1 << "Return value is not checked in call to '" << FD << '\'';
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "The return value from the call to '" << FD->getNameAsString()
- << "' is not checked. If an error occurs in '"
- << FD->getNameAsString()
+ os2 << "The return value from the call to '" << FD
+ << "' is not checked. If an error occurs in '" << FD
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp
index be1a677d9118..addfc21c1805 100644
--- a/lib/Checker/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
return ValMgr.makeIntVal(C->getValue(), C->getType());
}
+ case Stmt::CXXBoolLiteralExprClass: {
+ const SVal *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<CXXBoolLiteralExpr>(E));
+ }
case Stmt::IntegerLiteralClass: {
// In C++, this expression may have been bound to a temporary object.
SVal const *X = ExprBindings.lookup(E);
diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp
new file mode 100644
index 000000000000..00ac99559282
--- /dev/null
+++ b/lib/Checker/GRCXXExprEngine.cpp
@@ -0,0 +1,246 @@
+//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 C++ expression evaluation engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+
+void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE,
+ const FunctionProtoType *FnType,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AI);
+ WorkList.push_back(CallExprWLItem(AI, Pred));
+
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ Dst.insert(Item.N);
+ continue;
+ }
+
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AI;
+ bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType()
+ : false;
+ if (VisitAsLvalue)
+ VisitLValue(*Item.I, Item.N, Tmp);
+ else
+ Visit(*Item.I, Item.N, Tmp);
+
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
+ }
+}
+
+const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
+ const StackFrameContext *SFC) {
+ Type *T = D->getParent()->getTypeForDecl();
+ QualType PT = getContext().getPointerType(QualType(T,0));
+ return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
+}
+
+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 =
+ ValMgr.getRegionManager().getCXXObjectRegion(Ex,
+ Pred->getLocationContext());
+
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+ }
+}
+
+void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (E->isElidable()) {
+ VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
+ return;
+ }
+
+ const CXXConstructorDecl *CD = E->getConstructor();
+ assert(CD);
+
+ if (!CD->isThisDeclarationADefinition())
+ // FIXME: invalidate the object.
+ return;
+
+
+ // Evaluate other arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
+ EvalArguments(const_cast<CXXConstructExpr*>(E)->arg_begin(),
+ const_cast<CXXConstructExpr*>(E)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+ // The callee stack frame context used to create the 'this' parameter region.
+ const StackFrameContext *SFC = AMgr.getStackFrame(CD,
+ Pred->getLocationContext(),
+ E, Builder->getBlock(), Builder->getIndex());
+
+ const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
+
+ CallEnter Loc(E, CD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
+ NE = ArgsEvaluated.end(); NI != NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ // Setup 'this' region.
+ state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
+ ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the method type.
+ const FunctionProtoType *FnType =
+ MCE->getCallee()->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Method type not available");
+
+ // Evaluate explicit arguments with a worklist.
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
+ const_cast<CXXMemberCallExpr*>(MCE)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Evaluate the implicit object argument.
+ ExplodedNodeSet AllArgsEvaluated;
+ const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
+ if (!ME)
+ return;
+ Expr *ObjArgExpr = ME->getBase();
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ if (ME->isArrow())
+ Visit(ObjArgExpr, *I, AllArgsEvaluated);
+ else
+ VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
+ }
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+ assert(MD && "not a CXXMethodDecl?");
+
+ if (!MD->isThisDeclarationADefinition())
+ // FIXME: conservative method call evaluation.
+ return;
+
+ const StackFrameContext *SFC = AMgr.getStackFrame(MD,
+ Pred->getLocationContext(),
+ MCE,
+ Builder->getBlock(),
+ Builder->getIndex());
+ const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
+ CallEnter Loc(MCE, MD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
+ E = AllArgsEvaluated.end(); I != E; ++I) {
+ // Set up 'this' region.
+ const GRState *state = GetState(*I);
+ state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
+ ExplodedNode *N = Builder->generateNode(Loc, state, *I);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (CNE->isArray()) {
+ // FIXME: allocating an array has not been handled.
+ return;
+ }
+
+ unsigned Count = Builder->getCurrentBlockCount();
+ DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE,
+ CNE->getType(), Count);
+ const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion();
+
+ QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+
+ const ElementRegion *EleReg =
+ getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+
+ // Evaluate constructor arguments.
+ const FunctionProtoType *FnType = NULL;
+ const CXXConstructorDecl *CD = CNE->getConstructor();
+ if (CD)
+ FnType = CD->getType()->getAs<FunctionProtoType>();
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Initialize the object region and bind the 'new' expression.
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ if (ObjTy->isRecordType()) {
+ Store store = state->getStore();
+ StoreManager::InvalidatedSymbols IS;
+ store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS);
+ state = state->makeWithStore(store);
+ } else {
+ if (CNE->hasInitializer()) {
+ SVal V = state->getSVal(*CNE->constructor_arg_begin());
+ state = state->bindLoc(loc::MemRegionVal(EleReg), V);
+ } else {
+ // Explicitly set to undefined, because currently we retrieve symbolic
+ // value from symbolic region.
+ state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
+ }
+ }
+ state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ MakeNode(Dst, CNE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Should do more checking.
+ ExplodedNodeSet ArgEvaluated;
+ Visit(CDE->getArgument(), Pred, ArgEvaluated);
+ for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(),
+ E = ArgEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+ MakeNode(Dst, CDE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the this object region from StoreManager.
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(
+ getContext().getCanonicalType(TE->getType()),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+}
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index e4ef6b0e106f..23a87d303b4d 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
+ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St,
+ ProgramPoint::Kind K) {
+ const GRState* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ ExplodedNode* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+}
+
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC, const void *tag){
switch (K) {
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index bab8922a8c2b..67090b86694f 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
switch (S->getStmtClass()) {
// C++ stuff we don't support yet.
- case Stmt::CXXNamedCastExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXConstCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CXXTypeidExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXThrowExprClass:
- case Stmt::CXXDefaultArgExprClass:
- case Stmt::CXXZeroInitValueExprClass:
- case Stmt::CXXNewExprClass:
- case Stmt::CXXDeleteExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::UnresolvedLookupExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::CXXConstructExprClass:
+ case Stmt::CXXBindReferenceExprClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass:
+ case Stmt::CXXThrowExprClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::CXXTypeidExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
- case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::CXXZeroInitValueExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
- case Stmt::CXXCatchStmtClass:
- case Stmt::CXXTryStmtClass: {
+ {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
MakeNode(Dst, S, Pred, GetState(Pred));
break;
}
- default:
- // Cases we intentionally have "default" handle:
- // AddrLabelExpr, IntegerLiteral, CharacterLiteral
+ // Cases that should never be evaluated simply because they shouldn't
+ // appear in the CFG.
+ case Stmt::BreakStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::NoStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::SwitchCaseClass:
+ llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+ break;
+ // Cases not handled yet; but will handle some day.
+ case Stmt::DesignatedInitExprClass:
+ case Stmt::ExtVectorElementExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ImplicitValueInitExprClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCEncodeExprClass:
+ case Stmt::ObjCImplicitSetterGetterRefExprClass:
+ case Stmt::ObjCIsaExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCProtocolExprClass:
+ case Stmt::ObjCSelectorExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSuperExprClass:
+ case Stmt::ParenListExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::ShuffleVectorExprClass:
+ case Stmt::TypesCompatibleExprClass:
+ case Stmt::VAArgExprClass:
+ // Fall through.
+
+ // Cases we intentionally don't evaluate, since they don't need
+ // to be explicitly evaluated.
+ case Stmt::AddrLabelExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
break;
@@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXNewExprClass: {
+ CXXNewExpr *NE = cast<CXXNewExpr>(S);
+ VisitCXXNewExpr(NE, Pred, Dst);
+ break;
+ }
+
+ case Stmt::CXXDeleteExprClass: {
+ CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
+ VisitCXXDeleteExpr(CDE, Pred, Dst);
+ break;
+ }
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
@@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
case Stmt::ImplicitCastExprClass:
- case Stmt::CStyleCastExprClass: {
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass: {
CastExpr* C = cast<CastExpr>(S);
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
@@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
break;
+ case Stmt::OffsetOfExprClass:
+ VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+ break;
+
case Stmt::SizeOfAlignOfExprClass:
VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
break;
@@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
// In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
@@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
}
-//===----------------------------------------------------------------------===//
-// Transfer function: Function calls.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class CallExprWLItem {
-public:
- CallExpr::arg_iterator I;
- ExplodedNode *N;
-
- CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-} // end anonymous namespace
-
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
continue;
}
- const GRState* state = Pred->getState();
+ const GRState* state = GetState(Pred);
SVal V = state->getSVal(Ex);
if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
// First assume that the condition is true.
@@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// But first evaluate the receiver (if any).
ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (Expr *Receiver = ME->getReceiver()) {
+ if (Expr *Receiver = ME->getInstanceReceiver()) {
ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
@@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- if (const Expr *Receiver = ME->getReceiver()) {
- const GRState *state = Pred->getState();
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ const GRState *state = GetState(Pred);
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal =
@@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// Dispatch to plug-in transfer function.
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
- else {
- IdentifierInfo* ClsName = ME->getClassName();
+ else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+ IdentifierInfo* ClsName = Iface->getIdentifier();
Selector S = ME->getSelector();
// Check for special instance methods.
@@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
QualType T = getContext().getCanonicalType(E->getType());
unsigned NumInitElements = E->getNumInits();
- if (T->isArrayType() || T->isStructureType() ||
- T->isUnionType() || T->isVectorType()) {
-
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
+void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
+ Expr::EvalResult Res;
+ if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+ assert(OOE->getType()->isIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
+ return;
+ }
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
+ Dst.Add(Pred);
+}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue) {
@@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
case UnaryOperator::OffsetOf: {
Expr::EvalResult Res;
if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
- assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
- assert(U->getType()->isIntegerType());
- assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
- MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
- return;
- }
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+ assert(U->getType()->isIntegerType());
+ assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
+ return;
+ }
// FIXME: Handle the case where __builtin_offsetof is not a constant.
Dst.Add(Pred);
return;
}
-
+
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
@@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
}
-
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
- ExplodedNodeSet & Dst) {
- // Get the this object region from StoreManager.
- const MemRegion *R =
- ValMgr.getRegionManager().getCXXThisRegion(
- getContext().getCanonicalType(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,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
@@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
ExplodedNodeSet Tmp3;
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
- SVal LeftV = (*I1)->getState()->getSVal(LHS);
+ SVal LeftV = GetState(*I1)->getSVal(LHS);
ExplodedNodeSet Tmp2;
Visit(RHS, *I1, Tmp2);
@@ -3147,184 +3190,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
-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 =
- ValMgr.getRegionManager().getCXXObjectRegion(Ex,
- Pred->getLocationContext());
-
- state = state->bindLoc(loc::MemRegionVal(R), V);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
-}
-
-void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
- return;
- }
-
- const CXXConstructorDecl *CD = E->getConstructor();
- assert(CD);
-
- if (!CD->isThisDeclarationADefinition())
- // FIXME: invalidate the object.
- return;
-
-
- // Evaluate other arguments.
- CXXConstructExpr::arg_iterator AB
- = const_cast<CXXConstructExpr*>(E)->arg_begin();
- CXXConstructExpr::arg_iterator AE
- = const_cast<CXXConstructExpr*>(E)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
- const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>();
-
- 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 - AB;
-
- bool VisitAsLvalue = false;
-
- if (ParamIdx < Proto->getNumArgs())
- VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // The callee stack frame context used to create the 'this' parameter region.
- const StackFrameContext *SFC = AMgr.getStackFrame(CD,
- Pred->getLocationContext(),
- E, Builder->getBlock(), Builder->getIndex());
-
- const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
-
- CallEnter Loc(E, CD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
- NE = ArgsEvaluated.end(); NI != NE; ++NI) {
- const GRState *state = GetState(*NI);
- // Setup 'this' region.
- state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- if (N)
- Dst.Add(N);
- }
-}
-
-void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
- AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- ExplodedNodeSet Tmp;
- const unsigned ParamIdx = Item.I - AB;
- bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllArgsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
- E = ArgsEvaluated.end(); I != E; ++I) {
- if (ME->isArrow())
- Visit(ObjArgExpr, *I, AllArgsEvaluated);
- else
- VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
- }
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
-
- if (!MD->isThisDeclarationADefinition())
- // FIXME: conservative method call evaluation.
- return;
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, MD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
- E = AllArgsEvaluated.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
- ExplodedNode *N = Builder->generateNode(Loc, state, *I);
- if (N)
- Dst.Add(N);
- }
-}
-
-const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
- const StackFrameContext *SFC) {
- Type *T = D->getParent()->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T,0));
- return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
-}
-
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9f12ab622fbf..9a664c78a77c 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << superRegion << "->" << getDecl()->getNameAsString();
+ os << superRegion << "->" << getDecl();
}
void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}';
+ os << "ivar{" << superRegion << ',' << getDecl() << '}';
}
void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
@@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << cast<VarDecl>(D)->getNameAsString();
+ os << cast<VarDecl>(D);
}
void RegionRawOffset::dump() const {
@@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
const MemRegion *MemRegion::getBaseRegion() const {
const MemRegion *R = this;
while (true) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- R = ER->getSuperRegion();
- continue;
- }
- if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- R = FR->getSuperRegion();
- continue;
+ switch (R->getKind()) {
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ R = cast<SubRegion>(R)->getSuperRegion();
+ continue;
+ default:
+ break;
}
break;
}
diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 29bac9c384c2..48f03a369ed5 100644
--- a/lib/Checker/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -56,7 +56,7 @@ void
NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
- const Expr *receiver = ME->getReceiver();
+ const Expr *receiver = ME->getInstanceReceiver();
if (!receiver)
return;
diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index 9130bfad8407..e30d54ccd79c 100644
--- a/lib/Checker/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
else
os << "documented in CoreFoundation/CFError.h the parameter '";
- os << Param->getNameAsString() << "' may be null.";
+ os << Param << "' may be null.";
BugReport *report = new BugReport(*this, os.str(), *I);
// FIXME: Notable symbols are now part of the report. We should
diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp
index 04d897aec894..0e47621d4205 100644
--- a/lib/Checker/ObjCUnusedIVarsChecker.cpp
+++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp
@@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (I->second == Unused) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Instance variable '" << I->first->getNameAsString()
- << "' in class '" << ID->getNameAsString()
+ os << "Instance variable '" << I->first << "' in class '" << ID
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index c97da33aaac6..1e15d43a5ac2 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -14,22 +14,22 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
-#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"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-
-#include "llvm/ADT/ImmutableMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using llvm::Optional;
//===----------------------------------------------------------------------===//
// Representation of binding keys.
@@ -346,8 +346,6 @@ public: // Part of public interface to class.
Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
const TypedRegion *R);
- const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
-
//===------------------------------------------------------------------===//
// State pruning.
//===------------------------------------------------------------------===//
@@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
return true;
}
-const ElementRegion *
-RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
- ASTContext &Ctx = getContext();
- SVal idx = ValMgr.makeZeroArrayIndex();
- assert(!T.isNull());
- return MRMgr.getElementRegion(T, idx, R, Ctx);
-}
-
SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
#endif
- if (RTy->isStructureType() || RTy->isClassType())
+ if (RTy->isStructureOrClassType())
return RetrieveStruct(store, R);
// FIXME: Handle unions.
@@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
- assert(T->isStructureType() || T->isClassType());
+ assert(T->isStructureOrClassType());
return ValMgr.makeLazyCompoundVal(store, R);
}
@@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, 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())
+ if (TR->getValueType(getContext())->isStructureOrClassType())
return BindStruct(store, TR, V);
// Special case: the current region represents a cast and it and the super
@@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
if (T->isArrayType())
return BindArray(store, VR, InitVal);
- if (T->isStructureType())
+ if (T->isStructureOrClassType())
return BindStruct(store, VR, InitVal);
return Bind(store, ValMgr.makeLoc(VR), InitVal);
@@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store,
V = ValMgr.makeNull();
else if (T->isIntegerType())
V = ValMgr.makeZeroVal(T);
- else if (T->isStructureType() || T->isArrayType()) {
+ else if (T->isStructureOrClassType() || T->isArrayType()) {
// Set the default value to a zero constant when it is a structure
// or array. The type doesn't really matter.
V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
@@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
- if (ElementTy->isStructureType())
+ if (ElementTy->isStructureOrClassType())
store = BindStruct(store, ER, *VI);
else
store = Bind(store, ValMgr.makeLoc(ER), *VI);
@@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
return store;
QualType T = R->getValueType(getContext());
- assert(T->isStructureType());
+ assert(T->isStructureOrClassType());
const RecordType* RT = T->getAs<RecordType>();
RecordDecl* RD = RT->getDecl();
@@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
if (FTy->isArrayType())
store = BindArray(store, FR, *VI);
- else if (FTy->isStructureType())
+ else if (FTy->isStructureOrClassType())
store = BindStruct(store, FR, *VI);
else
store = Bind(store, ValMgr.makeLoc(FR), *VI);
diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp
index 4bfa2cdafb46..d756be70dc25 100644
--- a/lib/Checker/SVals.cpp
+++ b/lib/Checker/SVals.cpp
@@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
case nonloc::LazyCompoundValKind: {
const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
- os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion()
+ os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
+ << ',' << C.getRegion()
<< '}';
break;
}
diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp
index fb1d74a99046..dd38a435a1d7 100644
--- a/lib/Checker/SimpleSValuator.cpp
+++ b/lib/Checker/SimpleSValuator.cpp
@@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) {
if (castTy->isUnionType())
return UnknownVal();
- assert(castTy->isIntegerType());
- unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
+ if (castTy->isIntegerType()) {
+ unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
- if (!isa<loc::ConcreteInt>(val))
- return ValMgr.makeLocAsInteger(val, BitWidth);
+ if (!isa<loc::ConcreteInt>(val))
+ return ValMgr.makeLocAsInteger(val, BitWidth);
- llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
- i.extOrTrunc(BitWidth);
- return ValMgr.makeIntVal(i);
+ llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(BitWidth);
+ return ValMgr.makeIntVal(i);
+ }
+
+ // All other cases: return 'UnknownVal'. This includes casting pointers
+ // to floats, which is probably badness it itself, but this is a good
+ // intermediate solution until we do something better.
+ return UnknownVal();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp
index e524cb3d7cc3..c12065b89a04 100644
--- a/lib/Checker/Store.cpp
+++ b/lib/Checker/Store.cpp
@@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
return true;
}
+const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
+ QualType T) {
+ SVal idx = ValMgr.makeZeroArrayIndex();
+ assert(!T.isNull());
+ return MRMgr.getElementRegion(T, idx, R, Ctx);
+}
+
const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) {
ASTContext& Ctx = StateMgr.getContext();
@@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
-
- // Is the offset a multiple of the size? If so, we can layer the
- // ElementRegion (with elementType == PointeeTy) directly on top of
- // the base region.
- if (off % pointeeTySize == 0) {
- newIndex = off / pointeeTySize;
- newSuperR = baseR;
+ if (!pointeeTySize.isZero()) {
+ // Is the offset a multiple of the size? If so, we can layer the
+ // ElementRegion (with elementType == PointeeTy) directly on top of
+ // the base region.
+ if (off % pointeeTySize == 0) {
+ newIndex = off / pointeeTySize;
+ newSuperR = baseR;
+ }
}
}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index d75e5d25c49d..e9b8f0966ae1 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -13,23 +13,30 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
using namespace clang;
+using llvm::Optional;
namespace {
class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
enum SubChecks {
OpenFn = 0,
+ PthreadOnceFn = 1,
NumChecks
};
BugType *BTypes[NumChecks];
public:
+ Optional<uint64_t> Val_O_CREAT;
+
+public:
UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
static void *getTag() { static unsigned tag = 0; return &tag; }
@@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) {
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
+static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT) {
+ // The definition of O_CREAT is platform specific. We need a better way
+ // of querying this information from the checking environment.
+ if (!UC.Val_O_CREAT.hasValue()) {
+ if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+ UC.Val_O_CREAT = 0x0200;
+ else {
+ // FIXME: We need a more general way of getting the O_CREAT value.
+ // We could possibly grovel through the preprocessor state, but
+ // that would require passing the Preprocessor object to the GRExprEngine.
+ return;
+ }
+ }
+
LazyInitialize(BT, "Improper use of 'open'");
// Look at the 'oflags' argument for the O_CREAT flag.
@@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
NonLoc oflags = cast<NonLoc>(V);
NonLoc ocreateFlag =
- cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT,
+ cast<NonLoc>(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(),
oflagsEx->getType()));
SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And,
oflags, ocreateFlag,
@@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
//===----------------------------------------------------------------------===//
+// pthread_once
+//===----------------------------------------------------------------------===//
+
+static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+ const CallExpr *CE, BugType *&BT) {
+
+ // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
+ // They can possibly be refactored.
+
+ LazyInitialize(BT, "Improper use of 'pthread_once'");
+
+ if (CE->getNumArgs() < 1)
+ return;
+
+ // Check if the first argument is stack allocated. If so, issue a warning
+ // because that's likely to be bad news.
+ const GRState *state = C.getState();
+ const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+ return;
+
+ ExplodedNode *N = C.GenerateSink(state);
+ if (!N)
+ return;
+
+ llvm::SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to 'pthread_once' uses";
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ os << " the local variable '" << VR->getDecl()->getName() << '\'';
+ else
+ os << " stack allocated memory";
+ os << " for the \"control\" value. Using such transient memory for "
+ "the control value is potentially dangerous.";
+ if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+ os << " Perhaps you intended to declare the variable as 'static'?";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT);
+typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT);
namespace {
class SubCheck {
SubChecker SC;
+ UnixAPIChecker *UC;
BugType **BT;
public:
- SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
- SubCheck() : SC(NULL), BT(NULL) {}
+ SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
+ BT(&bt) {}
+ SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE) const {
if (SC)
- SC(C, CE, *BT);
+ SC(C, *UC, CE, *BT);
}
};
} // end anonymous namespace
@@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
const SubCheck &SC =
llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("open", SubCheck(CheckOpen, BTypes[OpenFn]))
+ .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn]))
+ .Case("pthread_once", SubCheck(CheckPthreadOnce, this,
+ BTypes[PthreadOnceFn]))
.Default(SubCheck());
SC.run(C, CE);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 509734123b0c..db24def216d5 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -706,7 +706,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
BlockDeclRefDecls);
// FIXME: This leaks
ImplicitParamDecl *SelfDecl =
- ImplicitParamDecl::Create(getContext(), 0,
+ ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD),
SourceLocation(), II,
ParmTy);
@@ -812,7 +812,8 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
Pad.getQuantity()),
ArrayType::Normal, 0);
ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
- 0, QualType(PadTy), 0, VarDecl::None);
+ 0, QualType(PadTy), 0,
+ VarDecl::None, VarDecl::None);
Expr *E;
E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
SourceLocation());
@@ -860,7 +861,9 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false,
true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
@@ -941,8 +944,9 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
if (NoteForHelperp) {
@@ -1025,8 +1029,9 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
// dst->x
@@ -1089,8 +1094,9 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
FunctionDecl *FD = FunctionDecl::Create(getContext(),
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
- FunctionDecl::Static, false,
- true);
+ FunctionDecl::Static,
+ FunctionDecl::None,
+ false, true);
CGF.StartFunction(FD, R, Fn, Args, SourceLocation());
llvm::Value *V = CGF.GetAddrOfLocalVar(Src);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index efee0e36b853..5646d0036e90 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -38,6 +38,7 @@ namespace llvm {
class GlobalValue;
class TargetData;
class FunctionType;
+ class PointerType;
class Value;
class LLVMContext;
}
@@ -127,7 +128,7 @@ protected:
llvm::LLVMContext &VMContext;
public:
- const llvm::Type *PtrToInt8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
struct HelperInfo {
int index;
int flag;
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 38c40ed489d2..95c41db86e09 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -682,13 +682,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
case Builtin::BIsqrtl: {
- // Rewrite sqrt to intrinsic if allowed.
- if (!FD->hasAttr<ConstAttr>())
- break;
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- const llvm::Type *ArgType = Arg0->getType();
- Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1);
- return RValue::get(Builder.CreateCall(F, Arg0, "tmp"));
+ // TODO: there is currently no set of optimizer flags
+ // sufficient for us to rewrite sqrt to @llvm.sqrt.
+ // -fmath-errno=0 is not good enough; we need finiteness.
+ // We could probably precondition the call with an ult
+ // against 0, but is that worth the complexity?
+ break;
}
case Builtin::BIpow:
@@ -983,8 +982,38 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateStore(Ops[1], Ops[0]);
}
case X86::BI__builtin_ia32_palignr: {
- Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r);
- return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size());
+ unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
+
+ // If palignr is shifting the pair of input vectors less than 9 bytes,
+ // emit a shuffle instruction.
+ if (shiftVal <= 8) {
+ const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext);
+
+ llvm::SmallVector<llvm::Constant*, 8> Indices;
+ for (unsigned i = 0; i != 8; ++i)
+ Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i));
+
+ Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size());
+ return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr");
+ }
+
+ // If palignr is shifting the pair of input vectors more than 8 but less
+ // than 16 bytes, emit a logical right shift of the destination.
+ if (shiftVal < 16) {
+ // MMX has these as 1 x i64 vectors for some odd optimization reasons.
+ const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext);
+ const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1);
+
+ Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast");
+ Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8);
+
+ // create i32 constant
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr");
+ }
+
+ // If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
case X86::BI__builtin_ia32_palignr128: {
unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue();
@@ -1025,5 +1054,49 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
+ llvm::SmallVector<Value*, 4> Ops;
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+
+ switch (BuiltinID) {
+ default: return 0;
+
+ // vec_st
+ case PPC::BI__builtin_altivec_stvx:
+ case PPC::BI__builtin_altivec_stvxl:
+ case PPC::BI__builtin_altivec_stvebx:
+ case PPC::BI__builtin_altivec_stvehx:
+ case PPC::BI__builtin_altivec_stvewx:
+ {
+ Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext));
+ Ops[1] = !isa<Constant>(Ops[1]) || !cast<Constant>(Ops[1])->isNullValue()
+ ? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2];
+ Ops.pop_back();
+
+ switch (BuiltinID) {
+ default: assert(0 && "Unsupported vavg intrinsic!");
+ case PPC::BI__builtin_altivec_stvx:
+ ID = Intrinsic::ppc_altivec_stvx;
+ break;
+ case PPC::BI__builtin_altivec_stvxl:
+ ID = Intrinsic::ppc_altivec_stvxl;
+ break;
+ case PPC::BI__builtin_altivec_stvebx:
+ ID = Intrinsic::ppc_altivec_stvebx;
+ break;
+ case PPC::BI__builtin_altivec_stvehx:
+ ID = Intrinsic::ppc_altivec_stvehx;
+ break;
+ case PPC::BI__builtin_altivec_stvewx:
+ ID = Intrinsic::ppc_altivec_stvewx;
+ break;
+ }
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), "");
+ }
+ }
return 0;
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 93a182f5cc47..74cf1134d5b7 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -297,15 +297,15 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
-static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
- llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty);
- Vtable = CGF.Builder.CreateLoad(Vtable);
+ llvm::Value *VTable = CGF.Builder.CreateBitCast(This, Ty);
+ VTable = CGF.Builder.CreateLoad(VTable);
llvm::Value *VFuncPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn");
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
return CGF.Builder.CreateLoad(VFuncPtr);
}
@@ -313,7 +313,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD);
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
@@ -323,7 +323,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
uint64_t VTableIndex =
- CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type));
+ CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type));
return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index cb1ecc1aa616..92d15d9d8c97 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -528,7 +528,7 @@ static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) {
}
const llvm::Type *
-CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
if (!HasIncompleteReturnTypeOrArgumentTypes(FPT))
@@ -586,8 +586,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect:
PAL.push_back(llvm::AttributeWithIndex::get(Index,
- llvm::Attribute::StructRet |
- llvm::Attribute::NoAlias));
+ llvm::Attribute::StructRet));
++Index;
// sret disables readnone and readonly
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
@@ -870,7 +869,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
- const Decl *TargetDecl) {
+ const Decl *TargetDecl,
+ llvm::Instruction **callOrInvoke) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.
llvm::SmallVector<llvm::Value*, 16> Args;
@@ -996,6 +996,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Args.data(), Args.data()+Args.size());
EmitBlock(Cont);
}
+ if (callOrInvoke) {
+ *callOrInvoke = CS.getInstruction();
+ }
CS.setAttributes(Attrs);
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 177e86230477..a604eef49a13 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -20,65 +20,61 @@ using namespace clang;
using namespace CodeGen;
static uint64_t
-ComputeNonVirtualBaseClassOffset(ASTContext &Context,
- const CXXBasePath &Path,
- unsigned Start) {
+ComputeNonVirtualBaseClassOffset(ASTContext &Context,
+ const CXXRecordDecl *DerivedClass,
+ CXXBaseSpecifierArray::iterator Start,
+ CXXBaseSpecifierArray::iterator End) {
uint64_t Offset = 0;
-
- for (unsigned i = Start, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
+
+ const CXXRecordDecl *RD = DerivedClass;
+
+ for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ assert(!Base->isVirtual() && "Should not see virtual bases here!");
// Get the layout.
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXBaseSpecifier *BS = Element.Base;
- assert(!BS->isVirtual() && "Should not see virtual bases here!");
-
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
// Add the offset.
- Offset += Layout.getBaseClassOffset(Base) / 8;
+ Offset += Layout.getBaseClassOffset(BaseDecl);
+
+ RD = BaseDecl;
}
-
- return Offset;
+
+ // FIXME: We should not use / 8 here.
+ return Offset / 8;
}
llvm::Constant *
-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 *>(Class)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return 0;
- }
+CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
+ const CXXBaseSpecifierArray &BasePath) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
- uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(),
- Paths.front(), 0);
+ uint64_t Offset =
+ ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl,
+ BasePath.begin(), BasePath.end());
if (!Offset)
return 0;
-
+
const llvm::Type *PtrDiffTy =
- Types.ConvertType(getContext().getPointerDiffType());
-
+ Types.ConvertType(getContext().getPointerDiffType());
+
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-/// Gets the address of a virtual base class within a complete object.
+/// Gets the address of a direct 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) {
+CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base,
+ bool BaseIsVirtual) {
// 'this' must be a pointer (in some address space) to Derived.
assert(This->getType()->isPointerTy() &&
cast<llvm::PointerType>(This->getType())->getElementType()
@@ -87,7 +83,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
// Compute the offset of the virtual base.
uint64_t Offset;
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived);
- if (isBaseVirtual)
+ if (BaseIsVirtual)
Offset = Layout.getVBaseClassOffset(Base);
else
Offset = Layout.getBaseClassOffset(Base);
@@ -105,51 +101,63 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
return V;
}
-llvm::Value *
-CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *Class,
- const CXXRecordDecl *BaseClass,
- bool NullCheckValue) {
- QualType BTy =
- getContext().getCanonicalType(
- getContext().getTypeDeclType(BaseClass));
- const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
-
- if (Class == BaseClass) {
- // Just cast back.
- return Builder.CreateBitCast(Value, BasePtrTy);
- }
+static llvm::Value *
+ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
+ uint64_t NonVirtual, llvm::Value *Virtual) {
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ llvm::Value *NonVirtualOffset = 0;
+ if (NonVirtual)
+ NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual);
+
+ llvm::Value *BaseOffset;
+ if (Virtual) {
+ if (NonVirtualOffset)
+ BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset);
+ else
+ BaseOffset = Virtual;
+ } else
+ BaseOffset = NonVirtualOffset;
+
+ // Apply the base offset.
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr");
- 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;
- }
+ return ThisPtr;
+}
- unsigned Start = 0;
- llvm::Value *VirtualOffset = 0;
+llvm::Value *
+CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
+ bool NullCheckValue) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
- const CXXBasePath &Path = Paths.front();
+ CXXBaseSpecifierArray::iterator Start = BasePath.begin();
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());
- }
+
+ // Get the virtual base.
+ if ((*Start)->isVirtual()) {
+ VBase =
+ cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl());
+ ++Start;
}
+
+ uint64_t NonVirtualOffset =
+ ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived,
+ Start, BasePath.end());
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
+ // Get the base pointer type.
+ const llvm::Type *BasePtrTy =
+ ConvertType((BasePath.end()[-1])->getType())->getPointerTo();
- if (!Offset && !VBase) {
+ if (!NonVirtualOffset && !VBase) {
// Just cast back.
return Builder.CreateBitCast(Value, BasePtrTy);
}
-
+
llvm::BasicBlock *CastNull = 0;
llvm::BasicBlock *CastNotNull = 0;
llvm::BasicBlock *CastEnd = 0;
@@ -165,28 +173,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
-
+
+ llvm::Value *VirtualOffset = 0;
+
if (VBase)
- VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase);
+ VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase);
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
- llvm::Value *NonVirtualOffset = 0;
- if (Offset)
- NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
-
- 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");
+ // Apply the offsets.
+ Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset,
+ VirtualOffset);
// Cast back.
Value = Builder.CreateBitCast(Value, BasePtrTy);
@@ -210,21 +205,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
llvm::Value *
CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *Class,
- const CXXRecordDecl *DerivedClass,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue) {
+ assert(!BasePath.empty() && "Base path should not be empty!");
+
QualType DerivedTy =
- getContext().getCanonicalType(
- getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass)));
+ getContext().getCanonicalType(getContext().getTagDeclType(Derived));
const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
- if (Class == DerivedClass) {
- // Just cast back.
- return Builder.CreateBitCast(Value, DerivedPtrTy);
- }
-
llvm::Value *NonVirtualOffset =
- CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class);
+ CGM.GetNonVirtualBaseClassOffset(Derived, BasePath);
if (!NonVirtualOffset) {
// No offset, we can just cast back.
@@ -274,23 +265,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
/// EmitCopyCtorCall - Emit a call to a copy constructor.
static void
-EmitCopyCtorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType,
- llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) {
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType);
+EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor,
+ llvm::Value *ThisPtr, llvm::Value *Src) {
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete);
CallArgList CallArgs;
// Push the this ptr.
CallArgs.push_back(std::make_pair(RValue::get(ThisPtr),
CopyCtor->getThisType(CGF.getContext())));
-
- // Push the VTT parameter if necessary.
- if (VTT) {
- QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy);
- CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
- }
-
+
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType()));
@@ -325,13 +309,8 @@ EmitCopyCtorCall(CodeGenFunction &CGF,
// FIXME. Consolidate this with EmitCXXAggrConstructorCall.
void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be copied over");
- bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor();
-
+ const ConstantArrayType *Array,
+ const CXXRecordDecl *ClassDecl) {
// Create a temporary for the loop index and initialize it with 0.
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
@@ -347,7 +326,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// Generate: if (loop-index < number-of-elements fall to the loop body,
// otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
+ uint64_t NumElements = getContext().getConstantArrayElementCount(Array);
llvm::Value * NumElementsPtr =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
@@ -362,95 +341,8 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
Counter = Builder.CreateLoad(IndexPtr);
Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- if (BitwiseCopy)
- EmitAggregateCopy(Dest, Src, Ty);
- else if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0))
- EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src);
-
- EmitBlock(ContinueBlock);
-
- // Emit the increment of the loop counter.
- llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
- Counter = Builder.CreateLoad(IndexPtr);
- NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitClassAggrCopyAssignment - This routine generates code to assign a class
-/// array of objects from SrcValue to DestValue. Assignment can be either a
-/// bitwise assignment or via a copy assignment operator function call.
-/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy
-void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
- llvm::Value *Src,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "VLA cannot be asssigned");
- bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment();
-
- // Create a temporary for the loop index and initialize it with 0.
- llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
- "loop.index");
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr);
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- uint64_t NumElements = getContext().getConstantArrayElementCount(CA);
- llvm::Value * NumElementsPtr =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr,
- "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the assignment operator call on array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress");
- Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress");
- const CXXMethodDecl *MD = 0;
- if (BitwiseAssign)
- EmitAggregateCopy(Dest, Src, Ty);
- else {
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
- assert(MD && "EmitClassAggrCopyAssignment - No user assign");
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- QualType SrcTy = MD->getParamDecl(0)->getType();
- RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
- RValue::getAggregate(Src);
- CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, MD);
- }
+ EmitClassMemberwiseCopy(Dest, Src, ClassDecl);
+
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -468,7 +360,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
/// GetVTTParameter - Return the VTT parameter that should be passed to a
/// base constructor/destructor with virtual bases.
-static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
+static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
+ bool ForVirtualBase) {
if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
@@ -486,9 +379,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
if (RD == Base) {
assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
+ assert(!ForVirtualBase && "Can't have same class as virtual base!");
SubVTTIndex = 0;
} else {
- SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base);
+ const ASTRecordLayout &Layout =
+ CGF.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = ForVirtualBase ?
+ Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base);
+
+ SubVTTIndex =
+ CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
@@ -511,75 +411,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
/// or via a copy constructor call.
void CodeGenFunction::EmitClassMemberwiseCopy(
llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl, QualType Ty) {
- CXXCtorType CtorType = Ctor_Complete;
-
- if (ClassDecl) {
- Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
-
- // We want to call the base constructor.
- CtorType = Ctor_Base;
- }
- if (BaseClassDecl->hasTrivialCopyConstructor()) {
- EmitAggregateCopy(Dest, Src, Ty);
+ const CXXRecordDecl *ClassDecl) {
+ if (ClassDecl->hasTrivialCopyConstructor()) {
+ EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl));
return;
}
- CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0);
- if (!BaseCopyCtor)
- return;
+ CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0);
+ assert(CopyCtor && "Did not have copy ctor!");
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType));
- EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src);
-}
-
-/// EmitClassCopyAssignment - This routine generates code to copy assign a class
-/// object from SrcValue to DestValue. Assignment can be either a bitwise
-/// assignment of via an assignment operator call.
-// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot.
-void CodeGenFunction::EmitClassCopyAssignment(
- llvm::Value *Dest, llvm::Value *Src,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty) {
- if (ClassDecl) {
- Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- }
- if (BaseClassDecl->hasTrivialCopyAssignment()) {
- EmitAggregateCopy(Dest, Src, Ty);
- return;
- }
-
- const CXXMethodDecl *MD = 0;
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
- assert(MD && "EmitClassCopyAssignment - missing copy assign");
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *LTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy);
-
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- MD->getThisType(getContext())));
-
- // Push the Src ptr.
- QualType SrcTy = MD->getParamDecl(0)->getType();
- RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
- RValue::getAggregate(Src);
- CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, MD);
+ EmitCopyCtorCall(*this, CopyCtor, Dest, Src);
}
/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a
@@ -600,30 +441,25 @@ void CodeGenFunction::EmitClassCopyAssignment(
void
CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
+ CXXCtorType CtorType = CurGD.getCtorType();
+ (void) CtorType;
+
const CXXRecordDecl *ClassDecl = Ctor->getParent();
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"SynthesizeCXXCopyConstructor - copy constructor has definition already");
assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy constrution of virtual base NYI
- if (Base->isVirtual())
- continue;
+ llvm::Value *ThisPtr = LoadCXXThis();
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
+ // Find the source pointer.
+ unsigned SrcArgIndex = Args.size() - 1;
+ assert(CtorType == Ctor_Base || SrcArgIndex == 1);
+ assert(CtorType != Ctor_Base ||
+ (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) ||
+ SrcArgIndex == 1);
+
+ llvm::Value *SrcPtr =
+ Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first));
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
@@ -638,27 +474,26 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, Field, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0);
+ LValue LHS = EmitLValueForField(ThisPtr, Field, 0);
+ LValue RHS = EmitLValueForField(SrcPtr, Field, 0);
if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo();
llvm::Value *DestBaseAddrPtr =
Builder.CreateBitCast(LHS.getAddress(), BasePtr);
llvm::Value *SrcBaseAddrPtr =
Builder.CreateBitCast(RHS.getAddress(), BasePtr);
EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
+ FieldClassDecl);
}
else
EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
+ FieldClassDecl);
continue;
}
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0);
- LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0);
+ LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0);
+ LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0);
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
@@ -675,100 +510,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
InitializeVTablePointers(ClassDecl);
}
-/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
-/// Before the implicitly-declared copy assignment operator for a class is
-/// implicitly defined, all implicitly- declared copy assignment operators for
-/// its direct base classes and its nonstatic data members shall have been
-/// implicitly defined. [12.8-p12]
-/// The implicitly-defined copy assignment operator for class X performs
-/// memberwise assignment of its subob- jects. The direct base classes of X are
-/// assigned first, in the order of their declaration in
-/// the base-specifier-list, and then the immediate nonstatic data members of X
-/// are assigned, in the order in which they were declared in the class
-/// definition.Each subobject is assigned in the manner appropriate to its type:
-/// if the subobject is of class type, the copy assignment operator for the
-/// class is used (as if by explicit qualification; that is, ignoring any
-/// possible virtual overriding functions in more derived classes);
-///
-/// if the subobject is an array, each element is assigned, in the manner
-/// appropriate to the element type;
-///
-/// if the subobject is of scalar type, the built-in assignment operator is
-/// used.
-void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) {
- const CXXMethodDecl *CD = cast<CXXMethodDecl>(CurGD.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "SynthesizeCXXCopyAssignment - copy assignment has user declaration");
-
- FunctionArgList::const_iterator i = Args.begin();
- const VarDecl *ThisArg = i->first;
- llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg);
- llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this");
- const VarDecl *SrcArg = (i+1)->first;
- llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg);
- llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj);
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl,
- Base->getType());
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
-
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- 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);
- llvm::Value *DestBaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- llvm::Value *SrcBaseAddrPtr =
- Builder.CreateBitCast(RHS.getAddress(), BasePtr);
- EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array,
- FieldClassDecl, FieldType);
- }
- else
- EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(),
- 0 /*ClassDecl*/, FieldClassDecl, FieldType);
- continue;
- }
- // Do a built-in assignment of scalar data members.
- 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());
- } else if (Field->getType()->isAnyComplexType()) {
- ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
- RHS.isVolatileQualified());
- StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
- EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
- }
- }
-
- // return *this;
- Builder.CreateStore(LoadOfThis, ReturnValue);
-}
-
static void EmitBaseInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXBaseOrMemberInitializer *BaseInit,
@@ -782,15 +523,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CXXRecordDecl *BaseClassDecl =
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- // FIXME: This method of determining whether a base is virtual is ridiculous;
- // it should be part of BaseInit.
- bool isBaseVirtual = false;
- for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); I != E; ++I)
- if (I->getType()->getAs<RecordType>()->getDecl() == BaseClassDecl) {
- isBaseVirtual = true;
- break;
- }
+ bool isBaseVirtual = BaseInit->isBaseVirtual();
// The base constructor doesn't construct virtual bases.
if (CtorType == Ctor_Base && isBaseVirtual)
@@ -798,9 +531,10 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
// 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);
+ llvm::Value *V =
+ CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ BaseInit->isBaseVirtual());
CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true);
@@ -809,7 +543,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
CodeGenFunction::EHCleanupBlock Cleanup(CGF);
CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext());
- CGF.EmitCXXDestructorCall(DD, Dtor_Base, V);
+ CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V);
}
}
@@ -850,7 +584,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LHS.isVolatileQualified());
} else {
CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(),
- LHS.isVolatileQualified(), false, true);
+ LHS.isVolatileQualified(),
+ /*IgnoreResult*/ false,
+ /*IsInitializer*/ true);
if (!CGF.Exceptions)
return;
@@ -868,7 +604,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext());
- CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress());
+ CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false,
+ LHS.getAddress());
}
}
}
@@ -976,8 +713,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers;
- // FIXME: Add vbase initialization
-
for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
E = CD->init_end();
B != E; ++B) {
@@ -1028,7 +763,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// variant, then call the appropriate operator delete() on the way
// out.
if (DtorType == Dtor_Deleting) {
- EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis());
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
+ LoadCXXThis());
SkipBody = true;
// If this is the complete variant, just invoke the base variant;
@@ -1036,7 +772,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// this optimization if the body is a function-try-block, because
// we'd introduce *two* handler blocks.
} else if (!isTryBody && DtorType == Dtor_Complete) {
- EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis());
+ EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
+ LoadCXXThis());
SkipBody = true;
// Otherwise, we're in the base variant, so we need to ensure the
@@ -1117,11 +854,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
if (BaseClassDecl->hasTrivialDestructor())
continue;
const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
- llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
- true,
- ClassDecl,
- BaseClassDecl);
- EmitCXXDestructorCall(D, Dtor_Base, V);
+ llvm::Value *V =
+ GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*BaseIsVirtual=*/true);
+ EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V);
}
return;
}
@@ -1175,7 +912,8 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
Array, BaseAddrPtr);
} else
EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ LHS.getAddress());
}
// Destroy non-virtual bases.
@@ -1193,12 +931,14 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
- const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
-
- llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(D, Dtor_Base, V);
+
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V =
+ GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl,
+ BaseClassDecl,
+ /*BaseIsVirtual=*/false);
+
+ EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V);
}
}
@@ -1271,7 +1011,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
{
CXXTemporariesCleanupScope Scope(*this);
- EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address,
+ ArgBeg, ArgEnd);
}
EmitBlock(ContinueBlock);
@@ -1345,7 +1086,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address);
EmitBlock(ContinueBlock);
@@ -1390,6 +1131,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
getContext().getTranslationUnitDecl(),
SourceLocation(), II, R, 0,
FunctionDecl::Static,
+ FunctionDecl::None,
false, true);
StartFunction(FD, R, Fn, Args, SourceLocation());
QualType BaseElementTy = getContext().getBaseElementType(Array);
@@ -1407,7 +1149,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
+ CXXCtorType Type, bool ForVirtualBase,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -1429,7 +1171,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
@@ -1450,7 +1192,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
++I;
// vtt
- if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) {
+ if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
+ /*ForVirtualBase=*/false)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
@@ -1502,8 +1245,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
+ bool ForVirtualBase,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
+ ForVirtualBase);
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
@@ -1538,7 +1283,8 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
void
CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass) {
const CXXRecordDecl *RD = Base.getBase();
@@ -1548,7 +1294,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
// Check if we need to use a vtable from the VTT.
if (CodeGenVTables::needsVTTParameter(CurGD) &&
- (RD->getNumVBases() || BaseIsMorallyVirtual)) {
+ (RD->getNumVBases() || NearestVBase)) {
// Get the secondary vpointer index.
uint64_t VirtualPointerIndex =
CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
@@ -1567,20 +1313,27 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
}
// Compute where to store the address point.
- llvm::Value *VTableField;
+ llvm::Value *VirtualOffset = 0;
+ uint64_t NonVirtualOffset = 0;
- if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) {
+ if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) {
// We need to use the virtual base offset offset because the virtual base
// might have a different offset in the most derived class.
- VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD,
- /*NullCheckValue=*/false);
+ VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass,
+ NearestVBase);
+ NonVirtualOffset = OffsetFromNearestVBase / 8;
} else {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
-
- VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy);
- VTableField =
- Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8);
+ // We can just use the base offset in the complete class.
+ NonVirtualOffset = Base.getBaseOffset() / 8;
}
+
+ // Apply the offsets.
+ llvm::Value *VTableField = LoadCXXThis();
+
+ if (NonVirtualOffset || VirtualOffset)
+ VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField,
+ NonVirtualOffset,
+ VirtualOffset);
// Finally, store the address point.
const llvm::Type *AddressPointPtrTy =
@@ -1591,7 +1344,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
void
CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -1600,7 +1354,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
// been set.
if (!BaseIsNonVirtualPrimaryBase) {
// Initialize the vtable pointer for this base.
- InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass);
+ InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase,
+ VTable, VTableClass);
}
const CXXRecordDecl *RD = Base.getBase();
@@ -1616,7 +1371,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
continue;
uint64_t BaseOffset;
- bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ uint64_t BaseOffsetFromNearestVBase;
bool BaseDeclIsNonVirtualPrimaryBase;
if (I->isVirtual()) {
@@ -1628,17 +1383,20 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
getContext().getASTRecordLayout(VTableClass);
BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- BaseDeclIsMorallyVirtual = true;
+ BaseOffsetFromNearestVBase = 0;
BaseDeclIsNonVirtualPrimaryBase = false;
} else {
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+ BaseOffsetFromNearestVBase =
+ OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl);
BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
}
InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
- BaseDeclIsMorallyVirtual,
+ I->isVirtual() ? BaseDecl : NearestVBase,
+ BaseOffsetFromNearestVBase,
BaseDeclIsNonVirtualPrimaryBase,
VTable, VTableClass, VBases);
}
@@ -1654,8 +1412,8 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
// Initialize the vtable pointers for this class and all of its bases.
VisitedVirtualBasesSetTy VBases;
- InitializeVTablePointers(BaseSubobject(RD, 0),
- /*BaseIsMorallyVirtual=*/false,
+ InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0,
+ /*OffsetFromNearestVBase=*/0,
/*BaseIsNonVirtualPrimaryBase=*/false,
VTable, RD, VBases);
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index bcbda8a0a747..4963e73fe464 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -320,27 +320,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
FieldOffset = 0;
FType = CGM.getContext().UnsignedLongTy;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
- FieldSize = CGM.getContext().getTypeSize(FType);
- FieldAlign = CGM.getContext().getTypeAlign(FType);
- FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- "reserved", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset));
- FieldOffset += FieldSize;
- FType = CGM.getContext().UnsignedLongTy;
- 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", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
EltTys.clear();
@@ -360,49 +342,13 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
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", Unit,
- 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", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
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,
- "__reserved", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
-
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset));
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,
- "__FuncPtr", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
+ EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset));
- FieldOffset += FieldSize;
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
FieldTy = DescTy;
FieldSize = CGM.getContext().getTypeSize(Ty);
@@ -525,13 +471,20 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit,
uint64_t FieldOffset = RL.getFieldOffset(FieldNo);
+ unsigned Flags = 0;
+ AccessSpecifier Access = I->getAccess();
+ if (Access == clang::AS_private)
+ Flags |= llvm::DIType::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ Flags |= llvm::DIType::FlagProtected;
+
// Create a DW_TAG_member node to remember the offset of this field in the
// struct. FIXME: This is an absolutely insane way to capture this
// information. When we gut debug info, this should be fixed.
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
FieldName, FieldDefUnit,
FieldLine, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
+ FieldOffset, Flags, FieldTy);
EltTys.push_back(FieldTy);
}
}
@@ -626,7 +579,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
// 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.getVTables().getMethodVtableIndex(Method);
+ VIndex = CGM.getVTables().getMethodVTableIndex(Method);
ContainingType = RecordTy;
}
@@ -734,8 +687,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
return VTablePtrType;
}
-/// getVtableName - Get vtable name for the given Class.
-llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
+/// 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();
@@ -746,10 +699,10 @@ llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) {
}
-/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate
+/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate
/// debug info entry in EltTys vector.
void CGDebugInfo::
-CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
+CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
@@ -764,7 +717,7 @@ CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
= DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- getVtableName(RD), Unit,
+ getVTableName(RD), Unit,
0, Size, 0, 0, 0,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
@@ -832,7 +785,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
if (CXXDecl) {
CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl);
- CollectVtableInfo(CXXDecl, Unit, EltTys);
+ CollectVTableInfo(CXXDecl, Unit, EltTys);
}
CollectRecordFields(RD, Unit, EltTys);
llvm::MDNode *ContainingType = NULL;
@@ -1293,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::MemberPointer:
return CreateType(cast<MemberPointerType>(Ty), Unit);
- case Type::InjectedClassName:
case Type::TemplateSpecialization:
case Type::Elaborated:
case Type::QualifiedName:
@@ -1318,6 +1270,21 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
return llvm::DIType();
}
+/// CreateMemberType - Create new member and increase Offset by FType's size.
+llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
+ llvm::StringRef Name,
+ uint64_t *Offset) {
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ uint64_t FieldSize = CGM.getContext().getTypeSize(FType);
+ unsigned FieldAlign = CGM.getContext().getTypeAlign(FType);
+ llvm::DIType Ty = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member,
+ Unit, Name, Unit, 0,
+ FieldSize, FieldAlign,
+ *Offset, 0, FieldTy);
+ *Offset += FieldSize;
+ return Ty;
+}
+
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
@@ -1341,17 +1308,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
}
Name = getFunctionName(FD);
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
// Use mangled name as linkage name for c/c++ functions.
CGM.getMangledName(LinkageName, GD);
} else {
// Use llvm function name as linkage name.
Name = Fn->getName();
LinkageName.setString(Name);
- if (!Name.empty() && Name[0] == '\01')
- Name = Name.substr(1);
}
+ if (!Name.empty() && Name[0] == '\01')
+ Name = Name.substr(1);
// It is expected that CurLoc is set before using EmitFunctionStart.
// Usually, CurLoc points to the left bracket location of compound
@@ -1437,72 +1402,19 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
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", Unit,
- 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", Unit,
- 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", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
+ EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset));
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", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
-
+ EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
+
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", Unit,
- 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", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
+ &FieldOffset));
+ EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
+ &FieldOffset));
}
CharUnits Align = CGM.getContext().getDeclAlign(VD);
@@ -1517,20 +1429,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
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, "", Unit,
- 0, FieldSize, FieldAlign,
- FieldOffset, 0, FieldTy);
- EltTys.push_back(FieldTy);
- FieldOffset += FieldSize;
+ EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
}
}
FType = Type;
- FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = Align.getQuantity()*8;
@@ -1558,13 +1462,6 @@ 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::DIFile Unit = getOrCreateFile(VD->getLocation());
llvm::DIType Ty;
uint64_t XOffset = 0;
@@ -1608,11 +1505,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
const ValueDecl *VD = BDRE->getDecl();
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 || Builder.GetInsertBlock() == 0)
+ if (Builder.GetInsertBlock() == 0)
return;
uint64_t XOffset = 0;
@@ -1708,7 +1601,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- llvm::StringRef DeclName = Var->getName();
+ llvm::StringRef DeclName = D->getName();
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit);
DebugFactory.CreateGlobalVariable(DContext, DeclName,
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 8397245e3184..c16379aca34c 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -112,7 +112,7 @@ class CGDebugInfo {
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
llvm::SmallVectorImpl<llvm::DIDescriptor> &E);
- void CollectVtableInfo(const CXXRecordDecl *Decl,
+ void CollectVTableInfo(const CXXRecordDecl *Decl,
llvm::DIFile F,
llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys);
@@ -196,13 +196,17 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// CreateMemberType - Create new member and increase Offset by FType's size.
+ llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
+ llvm::StringRef Name, uint64_t *Offset);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
llvm::StringRef getFunctionName(const FunctionDecl *FD);
- /// getVtableName - Get vtable name for the given Class.
- llvm::StringRef getVtableName(const CXXRecordDecl *Decl);
+ /// getVTableName - Get vtable name for the given Class.
+ llvm::StringRef getVTableName(const CXXRecordDecl *Decl);
};
} // namespace CodeGen
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 07d219f1fbfc..ba3a2b47edb4 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -31,11 +31,44 @@ using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
- default:
- CGM.ErrorUnsupported(&D, "decl");
- return;
+ case Decl::TranslationUnit:
+ case Decl::Namespace:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::TemplateTypeParm:
+ case Decl::UnresolvedUsingValue:
+ case Decl::NonTypeTemplateParm:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::Field:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
case Decl::ParmVar:
- assert(0 && "Parmdecls should not be in declstmts!");
+ case Decl::ImplicitParam:
+ case Decl::ClassTemplate:
+ case Decl::FunctionTemplate:
+ case Decl::TemplateTemplateParm:
+ case Decl::ObjCMethod:
+ case Decl::ObjCCategory:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCProperty:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCForwardProtocol:
+ case Decl::FileScopeAsm:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::Block:
+
+ assert(0 && "Declaration not should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
case Decl::Enum: // enum X;
@@ -44,6 +77,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Using: // using X; [C++]
case Decl::UsingShadow:
case Decl::UsingDirective: // using namespace X; [C++]
+ case Decl::NamespaceAlias:
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
// None of these decls require codegen support.
return;
@@ -197,6 +231,9 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage) {
+ // Bail out early if the block is unreachable.
+ if (!Builder.GetInsertBlock()) return;
+
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
@@ -205,6 +242,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D,
// Store into LocalDeclMap before generating initializer to handle
// circular references.
DMEntry = GV;
+ if (getContext().getLangOptions().CPlusPlus)
+ CGM.setStaticLocalDeclAddress(&D, GV);
// Make sure to evaluate VLA bounds now so that we have them for later.
//
@@ -610,6 +649,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ llvm::Value *Loc = DeclPtr;
+ if (isByRef)
+ Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
+ D.getNameAsString());
+
if (!ClassDecl->hasTrivialDestructor()) {
const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
assert(D && "EmitLocalBlockVarDecl - destructor is nul");
@@ -622,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
+ Builder.CreateBitCast(Loc, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
// Make sure to jump to the exit block.
@@ -634,20 +678,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
+ Builder.CreateBitCast(Loc, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
{
DelayedCleanupBlock Scope(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
+ Loc);
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
+ Loc);
}
}
}
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 40c18ca3c2a3..f6c805fdcaa0 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -219,9 +219,14 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
SourceLocation());
// Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i)
- Builder.CreateCall(DtorsAndObjects[e - i - 1].first,
- DtorsAndObjects[e - i - 1].second);
+ for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+ llvm::Constant *Callee = DtorsAndObjects[e - i - 1].first;
+ llvm::CallInst *CI = Builder.CreateCall(Callee,
+ DtorsAndObjects[e - i - 1].second);
+ // Make sure the call and the callee agree on calling convention.
+ if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
+ CI->setCallingConv(F->getCallingConv());
+ }
FinishFunction();
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 1e1506683ddd..c1d05bf233b2 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
}
-// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
-// DestPtr is casted to the right type.
-static void CopyObject(CodeGenFunction &CGF, const Expr *E,
- llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) {
- QualType ObjectType = E->getType();
-
- // Store the throw exception in the exception object.
- if (!CGF.hasAggregateLLVMType(ObjectType)) {
- llvm::Value *Value = CGF.EmitScalarExpr(E);
- const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo();
-
- CGF.Builder.CreateStore(Value,
- CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy));
- } else {
- const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
-
- llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty);
- if (RD->hasTrivialCopyConstructor()) {
- CGF.EmitAggExpr(E, This, false);
- } else if (CXXConstructorDecl *CopyCtor
- = RD->getCopyConstructor(CGF.getContext(), 0)) {
- llvm::Value *CondPtr = 0;
- if (CGF.Exceptions) {
- CodeGenFunction::EHCleanupBlock Cleanup(CGF);
- llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
-
- llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
- "doEHfree");
-
- CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
- CondBlock, Cont);
- CGF.EmitBlock(CondBlock);
-
- // Load the exception pointer.
- llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
- CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
-
- CGF.EmitBlock(Cont);
- }
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::Value *Src = CGF.EmitLValue(E).getAddress();
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
- CGF.setInvokeDest(TerminateHandler);
-
- // Stolen from EmitClassAggrMemberwiseCopy
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- CallArgs.push_back(std::make_pair(RValue::get(This),
- CopyCtor->getThisType(CGF.getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- CopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT
- = CopyCtor->getType()->getAs<FunctionProtoType>();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, CopyCtor);
- CGF.setInvokeDest(PrevLandingPad);
- } else
- llvm_unreachable("uncopyable object");
+// Emits an exception expression into the given location. This
+// differs from EmitAnyExprToMem only in that, if a final copy-ctor
+// call is required, an exception within that copy ctor causes
+// std::terminate to be invoked.
+static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *ExnLoc) {
+ // We want to release the allocated exception object if this
+ // expression throws. We do this by pushing an EH-only cleanup
+ // block which, furthermore, deactivates itself after the expression
+ // is complete.
+ llvm::AllocaInst *ShouldFreeVar =
+ CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
+ "should-free-exnobj.var");
+ CGF.InitTempAlloca(ShouldFreeVar,
+ llvm::ConstantInt::getFalse(CGF.getLLVMContext()));
+
+ // A variable holding the exception pointer. This is necessary
+ // because the throw expression does not necessarily dominate the
+ // cleanup, for example if it appears in a conditional expression.
+ llvm::AllocaInst *ExnLocVar =
+ CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var");
+
+ llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest();
+ {
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
+ llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
+
+ llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
+ "should-free-exnobj");
+ CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
+ CGF.EmitBlock(FreeBB);
+ llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
+ CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal);
+ CGF.EmitBlock(DoneBB);
}
+ llvm::BasicBlock *Cleanup = CGF.getInvokeDest();
+
+ CGF.Builder.CreateStore(ExnLoc, ExnLocVar);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // __cxa_allocate_exception returns a void*; we need to cast this
+ // to the appropriate type for the object.
+ const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo();
+ llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty);
+
+ // FIXME: this isn't quite right! If there's a final unelided call
+ // to a copy constructor, then according to [except.terminate]p1 we
+ // must call std::terminate() if that constructor throws, because
+ // technically that copy occurs after the exception expression is
+ // evaluated but before the exception is caught. But the best way
+ // to handle that is to teach EmitAggExpr to do the final copy
+ // differently if it can't be elided.
+ CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false);
+
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // Pop the cleanup block if it's still the top of the cleanup stack.
+ // Otherwise, temporaries have been created and our cleanup will get
+ // properly removed in time.
+ // TODO: this is not very resilient.
+ if (CGF.getInvokeDest() == Cleanup)
+ CGF.setInvokeDest(SavedInvokeDest);
}
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
@@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Now allocate the exception object.
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
+ uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
llvm::Value *ExceptionPtr =
@@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
- llvm::Value *ExceptionPtrPtr =
- CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
- Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
-
-
- CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
+ EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
- llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
+ llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true);
+
+ // The address of the destructor. If the exception type has a
+ // trivial destructor (or isn't a record), we just pass null.
+ llvm::Constant *Dtor = 0;
+ if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!Record->hasTrivialDestructor()) {
+ CXXDestructorDecl *DtorD = Record->getDestructor(getContext());
+ Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete);
+ Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy);
+ }
+ }
+ if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
@@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
QualType Ty = Proto->getExceptionType(i);
QualType ExceptType
= Ty.getNonReferenceType().getUnqualifiedType();
- llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
+ llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true);
SelectorArgs.push_back(EHType);
}
if (Proto->getNumExceptions())
@@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
// are ignored.
QualType CaughtType = C->getCaughtType().getNonReferenceType();
llvm::Value *EHTypeInfo
- = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
+ = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true);
SelectorArgs.push_back(EHTypeInfo);
} else {
// null indicates catch all
@@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
}
CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
- llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
- CGF.EmitBranch(Cont1);
CGF.setInvokeDest(PreviousInvokeDest);
+ llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(CleanupHandler);
-
+ // Jump to the beginning of the cleanup.
+ CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin());
+
+ // The libstdc++ personality function.
+ // TODO: generalize to work with other libraries.
llvm::Constant *Personality =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
(CGF.VMContext),
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
+
+ // %exception = call i8* @llvm.eh.exception()
+ // Magic intrinsic which tells gives us a handle to the caught
+ // exception.
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
- llvm::Value *llvm_eh_selector =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
-
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
- const llvm::IntegerType *Int8Ty;
- const llvm::PointerType *PtrToInt8Ty;
- Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
- // C string type. Used in lots of places.
- PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
- llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty);
+
+ // %ignored = call i32 @llvm.eh.selector(i8* %exception,
+ // i8* @__gxx_personality_v0,
+ // i8* null)
+ // Magic intrinsic which tells LLVM that this invoke landing pad is
+ // just a cleanup block.
llvm::Value *Args[] = { Exc, Personality, Null };
+ llvm::Value *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
- CGF.EmitBlock(CleanupEntryBB);
-
- CGF.EmitBlock(Cont1);
+ // And then we fall through into the code that the user put there.
+ // Jump back to the end of the cleanup.
+ CGF.Builder.SetInsertPoint(EndOfCleanup);
+ // Rethrow the exception.
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
@@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
CGF.EmitBlock(Cont);
} else
CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
-
CGF.Builder.CreateUnreachable();
- CGF.EmitBlock(Cont);
+ // Resume inserting where we started, but put the new cleanup
+ // handler in place.
+ if (PreviousInsertionBlock)
+ CGF.Builder.SetInsertPoint(PreviousInsertionBlock);
+ else
+ CGF.Builder.ClearInsertionPoint();
+
if (CGF.Exceptions)
CGF.setInvokeDest(CleanupHandler);
}
@@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
if (TerminateHandler)
return TerminateHandler;
- llvm::BasicBlock *Cont = 0;
-
- if (HaveInsertPoint()) {
- Cont = createBasicBlock("cont");
- EmitBranch(Cont);
- }
+ // We don't want to change anything at the current location, so
+ // save it aside and clear the insert point.
+ llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock();
+ llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint();
+ Builder.ClearInsertionPoint();
llvm::Constant *Personality =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
@@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
-
- if (Cont)
- EmitBlock(Cont);
+ // Restore the saved insertion state.
+ Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint);
return TerminateHandler;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 0aa4438f4f47..9ade916f42b7 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -37,6 +37,13 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty,
return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
}
+void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var,
+ llvm::Value *Init) {
+ llvm::StoreInst *Store = new llvm::StoreInst(Init, Var);
+ llvm::BasicBlock *Block = AllocaInsertPt->getParent();
+ Block->getInstList().insertAfter(&*AllocaInsertPt, Store);
+}
+
llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty,
const llvm::Twine &Name) {
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name);
@@ -111,6 +118,23 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E,
IsInitializer);
}
+/// EmitAnyExprToMem - Evaluate an expression into a given memory
+/// location.
+void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
+ llvm::Value *Location,
+ bool IsLocationVolatile,
+ bool IsInit) {
+ if (E->getType()->isComplexType())
+ EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
+ else if (hasAggregateLLVMType(E->getType()))
+ EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit);
+ else {
+ RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
+ LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType()));
+ EmitStoreThroughLValue(RV, LV, E->getType());
+ }
+}
+
RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
bool IsInitializer) {
bool ShouldDestroyTemporaries = false;
@@ -150,16 +174,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
PopCXXTemporary();
}
} else {
- const CXXRecordDecl *BaseClassDecl = 0;
+ const CXXBaseSpecifierArray *BasePath = 0;
const CXXRecordDecl *DerivedClassDecl = 0;
if (const CastExpr *CE =
dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBase) {
E = CE->getSubExpr();
-
- BaseClassDecl =
- cast<CXXRecordDecl>(CE->getType()->getAs<RecordType>()->getDecl());
+
+ BasePath = &CE->getBasePath();
DerivedClassDecl =
cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
}
@@ -185,6 +208,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
{
DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ /*ForVirtualBase=*/false,
Val.getAggregateAddr());
// Make sure to jump to the exit block.
@@ -193,6 +217,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ /*ForVirtualBase=*/false,
Val.getAggregateAddr());
}
}
@@ -201,10 +226,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
}
// Check if need to perform the derived-to-base cast.
- if (BaseClassDecl) {
+ if (BasePath) {
llvm::Value *Derived = Val.getAggregateAddr();
llvm::Value *Base =
- GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
+ GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath,
/*NullCheckValue=*/false);
return RValue::get(Base);
}
@@ -240,18 +265,15 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
if (!CatchUndefined)
return;
- const llvm::IntegerType *Size_tTy
+ const llvm::Type *Size_tTy
= llvm::IntegerType::get(VMContext, LLVMPointerWidth);
Address = Builder.CreateBitCast(Address, PtrToInt8Ty);
- const llvm::Type *ResType[] = {
- Size_tTy
- };
- llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1);
- const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
- CGM.getTypes().ConvertType(CGM.getContext().IntTy));
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &Size_tTy, 1);
+ const llvm::IntegerType *Int1Ty = llvm::IntegerType::get(VMContext, 1);
+
// In time, people may want to control this and use a 1 here.
- llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0);
+ llvm::Value *Arg = llvm::ConstantInt::get(Int1Ty, 0);
llvm::Value *C = Builder.CreateCall2(F, Address, Arg);
llvm::BasicBlock *Cont = createBasicBlock();
llvm::BasicBlock *Check = createBasicBlock();
@@ -457,6 +479,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
case Expr::BinaryOperatorClass:
return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
+ case Expr::CompoundAssignOperatorClass:
+ return EmitCompoundAssignOperatorLValue(cast<CompoundAssignOperator>(E));
case Expr::CallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
@@ -606,63 +630,73 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
QualType ExprType) {
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
- unsigned StartBit = Info.Start;
- unsigned BitfieldSize = Info.Size;
- llvm::Value *Ptr = LV.getBitFieldAddr();
- const llvm::Type *EltTy =
- cast<llvm::PointerType>(Ptr->getType())->getElementType();
- unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+ // Get the output type.
+ const llvm::Type *ResLTy = ConvertType(ExprType);
+ unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
- // In some cases the bitfield may straddle two memory locations. Currently we
- // load the entire bitfield, then do the magic to sign-extend it if
- // necessary. This results in somewhat more code than necessary for the common
- // case (one load), since two shifts accomplish both the masking and sign
- // extension.
- unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
- llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp");
+ // Compute the result as an OR of all of the individual component accesses.
+ llvm::Value *Res = 0;
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- // Shift to proper location.
- if (StartBit)
- Val = Builder.CreateLShr(Val, StartBit, "bf.lo");
+ // Get the field pointer.
+ llvm::Value *Ptr = LV.getBitFieldBaseAddr();
- // Mask off unused bits.
- llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, LowBits));
- Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared");
+ // Only offset by the field index if used, so that incoming values are not
+ // required to be structures.
+ if (AI.FieldIndex)
+ Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
- // Fetch the high bits if necessary.
- if (LowBits < BitfieldSize) {
- unsigned HighBits = BitfieldSize - LowBits;
- llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi");
- llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
- LV.isVolatileQualified(),
- "tmp");
+ // Offset by the byte offset, if used.
+ if (AI.FieldByteOffset) {
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ Ptr = Builder.CreateBitCast(Ptr, i8PTy);
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ }
- // Mask off unused bits.
- llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, HighBits));
- HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared");
+ // Cast to the access type.
+ const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth,
+ ExprType.getAddressSpace());
+ Ptr = Builder.CreateBitCast(Ptr, PTy);
- // Shift to proper location and or in to bitfield value.
- HighVal = Builder.CreateShl(HighVal, LowBits);
- Val = Builder.CreateOr(Val, HighVal, "bf.val");
- }
+ // Perform the load.
+ llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Load->setAlignment(AI.AccessAlignment);
- // Sign extend if necessary.
- if (Info.IsSigned) {
- llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy,
- EltTySize - BitfieldSize);
- Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits),
- ExtraBits, "bf.val.sext");
+ // Shift out unused low bits and mask out unused high bits.
+ llvm::Value *Val = Load;
+ if (AI.FieldBitStart)
+ Val = Builder.CreateLShr(Load, AI.FieldBitStart);
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth,
+ AI.TargetBitWidth),
+ "bf.clear");
+
+ // Extend or truncate to the target size.
+ if (AI.AccessWidth < ResSizeInBits)
+ Val = Builder.CreateZExt(Val, ResLTy);
+ else if (AI.AccessWidth > ResSizeInBits)
+ Val = Builder.CreateTrunc(Val, ResLTy);
+
+ // Shift into place, and OR into the result.
+ if (AI.TargetBitOffset)
+ Val = Builder.CreateShl(Val, AI.TargetBitOffset);
+ Res = Res ? Builder.CreateOr(Res, Val) : Val;
}
- // The bitfield type and the normal type differ when the storage sizes differ
- // (currently just _Bool).
- Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp");
+ // If the bit-field is signed, perform the sign-extension.
+ //
+ // FIXME: This can easily be folded into the load of the high bits, which
+ // could also eliminate the mask of high bits in some situations.
+ if (Info.isSigned()) {
+ unsigned ExtraBits = ResSizeInBits - Info.getSize();
+ if (ExtraBits)
+ Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits),
+ ExtraBits, "bf.val.sext");
+ }
- return RValue::get(Val);
+ return RValue::get(Res);
}
RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
@@ -783,88 +817,103 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
QualType Ty,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
- unsigned StartBit = Info.Start;
- unsigned BitfieldSize = Info.Size;
- llvm::Value *Ptr = Dst.getBitFieldAddr();
- const llvm::Type *EltTy =
- cast<llvm::PointerType>(Ptr->getType())->getElementType();
- unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy);
+ // Get the output type.
+ const llvm::Type *ResLTy = ConvertTypeForMem(Ty);
+ unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy);
- // Get the new value, cast to the appropriate type and masked to exactly the
- // size of the bit-field.
+ // Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp");
- llvm::Constant *Mask = llvm::ConstantInt::get(VMContext,
- llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize));
- NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value");
+
+ if (Ty->isBooleanType())
+ SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
+
+ SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
+ Info.getSize()),
+ "bf.value");
// Return the new value of the bit-field, if requested.
if (Result) {
// Cast back to the proper type for result.
- const llvm::Type *SrcTy = SrcVal->getType();
- llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false,
- "bf.reload.val");
+ const llvm::Type *SrcTy = Src.getScalarVal()->getType();
+ llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
+ "bf.reload.val");
// Sign extend if necessary.
- if (Info.IsSigned) {
- unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy);
- llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy,
- SrcTySize - BitfieldSize);
- SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits),
- ExtraBits, "bf.reload.sext");
+ if (Info.isSigned()) {
+ unsigned ExtraBits = ResSizeInBits - Info.getSize();
+ if (ExtraBits)
+ ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits),
+ ExtraBits, "bf.reload.sext");
}
- *Result = SrcTrunc;
+ *Result = ReloadVal;
}
- // In some cases the bitfield may straddle two memory locations. Emit the low
- // part first and check to see if the high needs to be done.
- unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit);
- llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
- "bf.prev.low");
-
- // Compute the mask for zero-ing the low part of this bitfield.
- llvm::Constant *InvMask =
- llvm::ConstantInt::get(VMContext,
- ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits));
+ // Iterate over the components, writing each piece to memory.
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- // Compute the new low part as
- // LowVal = (LowVal & InvMask) | (NewVal << StartBit),
- // with the shift of NewVal implicitly stripping the high bits.
- llvm::Value *NewLowVal =
- Builder.CreateShl(NewVal, StartBit, "bf.value.lo");
- LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared");
- LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo");
+ // Get the field pointer.
+ llvm::Value *Ptr = Dst.getBitFieldBaseAddr();
- // Write back.
- Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified());
+ // Only offset by the field index if used, so that incoming values are not
+ // required to be structures.
+ if (AI.FieldIndex)
+ Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
- // If the low part doesn't cover the bitfield emit a high part.
- if (LowBits < BitfieldSize) {
- unsigned HighBits = BitfieldSize - LowBits;
- llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi");
- llvm::Value *HighVal = Builder.CreateLoad(HighPtr,
- Dst.isVolatileQualified(),
- "bf.prev.hi");
-
- // Compute the mask for zero-ing the high part of this bitfield.
- llvm::Constant *InvMask =
- llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize,
- HighBits));
+ // Offset by the byte offset, if used.
+ if (AI.FieldByteOffset) {
+ const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext);
+ Ptr = Builder.CreateBitCast(Ptr, i8PTy);
+ Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs");
+ }
- // Compute the new high part as
- // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits),
- // where the high bits of NewVal have already been cleared and the
- // shift stripping the low bits.
- llvm::Value *NewHighVal =
- Builder.CreateLShr(NewVal, LowBits, "bf.value.high");
- HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared");
- HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi");
+ // Cast to the access type.
+ const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth,
+ Ty.getAddressSpace());
+ Ptr = Builder.CreateBitCast(Ptr, PTy);
+
+ // Extract the piece of the bit-field value to write in this access, limited
+ // to the values that are part of this access.
+ llvm::Value *Val = SrcVal;
+ if (AI.TargetBitOffset)
+ Val = Builder.CreateLShr(Val, AI.TargetBitOffset);
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits,
+ AI.TargetBitWidth));
+
+ // Extend or truncate to the access size.
+ const llvm::Type *AccessLTy =
+ llvm::Type::getIntNTy(VMContext, AI.AccessWidth);
+ if (ResSizeInBits < AI.AccessWidth)
+ Val = Builder.CreateZExt(Val, AccessLTy);
+ else if (ResSizeInBits > AI.AccessWidth)
+ Val = Builder.CreateTrunc(Val, AccessLTy);
+
+ // Shift into the position in memory.
+ if (AI.FieldBitStart)
+ Val = Builder.CreateShl(Val, AI.FieldBitStart);
+
+ // If necessary, load and OR in bits that are outside of the bit-field.
+ if (AI.TargetBitWidth != AI.AccessWidth) {
+ llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Load->setAlignment(AI.AccessAlignment);
+
+ // Compute the mask for zeroing the bits that are part of the bit-field.
+ llvm::APInt InvMask =
+ ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart,
+ AI.FieldBitStart + AI.TargetBitWidth);
+
+ // Apply the mask and OR in to the value to write.
+ Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val);
+ }
- // Write back.
- Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified());
+ // Write the value.
+ llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
+ Dst.isVolatileQualified());
+ if (AI.AccessAlignment)
+ Store->setAlignment(AI.AccessAlignment);
}
}
@@ -1084,6 +1133,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>();
llvm::Value *V = LocalDeclMap[VD];
+ if (!V && getContext().getLangOptions().CPlusPlus &&
+ VD->isStaticLocal())
+ V = CGM.getStaticLocalDeclAddress(VD);
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
Qualifiers Quals = MakeQualifiers(E->getType());
@@ -1474,19 +1526,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(Field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
-
- // FIXME: CodeGenTypes should expose a method to get the appropriate type for
- // FieldTy (the appropriate type is ABI-dependent).
- const llvm::Type *FieldTy =
- CGM.getTypes().ConvertTypeForMem(Field->getType());
- const llvm::PointerType *BaseTy =
- cast<llvm::PointerType>(BaseValue->getType());
- unsigned AS = BaseTy->getAddressSpace();
- BaseValue = Builder.CreateBitCast(BaseValue,
- llvm::PointerType::get(FieldTy, AS));
- llvm::Value *V = Builder.CreateConstGEP1_32(BaseValue, Info.FieldNo);
-
- return LValue::MakeBitfield(V, Info,
+ return LValue::MakeBitfield(BaseValue, Info,
Field->getType().getCVRQualifiers()|CVRQualifiers);
}
@@ -1548,12 +1588,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){
const Expr* InitExpr = E->getInitializer();
LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType()));
- if (E->getType()->isComplexType())
- EmitComplexExprIntoAddr(InitExpr, DeclPtr, false);
- else if (hasAggregateLLVMType(E->getType()))
- EmitAnyExpr(InitExpr, DeclPtr, false);
- else
- EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType());
+ EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false);
return Result;
}
@@ -1647,27 +1682,19 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
E->getSubExpr()->getType()->getAs<RecordType>();
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
-
- const RecordType *BaseClassTy = E->getType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
// Perform the derived-to-base conversion
llvm::Value *Base =
GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl,
- BaseClassDecl, /*NullCheckValue=*/false);
+ E->getBasePath(), /*NullCheckValue=*/false);
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
case CastExpr::CK_ToUnion:
return EmitAggExprToLValue(E);
case CastExpr::CK_BaseToDerived: {
- const RecordType *BaseClassTy =
- E->getSubExpr()->getType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseClassTy->getDecl());
-
const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
@@ -1676,8 +1703,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// Perform the base-to-derived conversion
llvm::Value *Derived =
- GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl,
- DerivedClassDecl, /*NullCheckValue=*/false);
+ GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
+ E->getBasePath(),/*NullCheckValue=*/false);
return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 4d5160f39b0b..d1b0dff11e5a 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -263,7 +263,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
std::swap(DerivedDecl, BaseDecl);
if (llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
@@ -321,6 +321,11 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
(void) MPT;
assert(MPT->getPointeeType()->isFunctionProtoType() &&
"Unexpected member pointer type!");
+
+ // The creation of member function pointers has no side effects; if
+ // there is no destination pointer, we have nothing to do.
+ if (!DestPtr)
+ return;
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
const CXXMethodDecl *MD =
@@ -329,17 +334,23 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
llvm::Value *FuncPtr;
if (MD->isVirtual()) {
- int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD);
+ int64_t Index = CGF.CGM.getVTables().getMethodVTableIndex(MD);
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t PointerWidthInBytes =
+ CGF.CGM.getContext().Target.getPointerWidth(0) / 8;
+
// 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);
+ FuncPtr = llvm::ConstantInt::get(PtrDiffTy,
+ (Index * PointerWidthInBytes) + 1);
} else {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -738,6 +749,14 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
bool isVolatile) {
assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
+ // Ignore empty classes in C++.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
+ return;
+ }
+ }
+
// Aggregate assignment turns into llvm.memcpy. This is almost valid per
// C99 6.5.16.1p3, which states "If the value being stored in an object is
// read from another object that overlaps in anyway the storage of the first
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 1fd1da858193..b57cdc93340e 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -205,20 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
EmitBlock(FnVirtual);
- const llvm::Type *VtableTy =
+ const llvm::Type *VTableTy =
FTy->getPointerTo()->getPointerTo();
- llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo());
- Vtable = Builder.CreateLoad(Vtable);
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
+ VTable = Builder.CreateLoad(VTable);
- Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy);
- llvm::Value *VtableOffset =
+ VTable = Builder.CreateBitCast(VTable, Int8PtrTy);
+ llvm::Value *VTableOffset =
Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
- Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn");
- Vtable = Builder.CreateBitCast(Vtable, VtableTy);
+ 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);
@@ -316,17 +316,22 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest, BasePtr);
+ Builder.CreateBitCast(Dest, BasePtr);
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
E->arg_begin(), E->arg_end());
}
- else
+ else {
+ CXXCtorType Type =
+ (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ ? Ctor_Complete : Ctor_Base;
+ bool ForVirtualBase =
+ E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
+
// Call the constructor.
- EmitCXXConstructorCall(CD,
- E->isBaseInitialization()? Ctor_Base : Ctor_Complete,
- Dest,
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest,
E->arg_begin(), E->arg_end());
+ }
}
static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
@@ -460,18 +465,20 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements) {
if (E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor())
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end());
- return;
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ if (!Ctor->getParent()->hasTrivialConstructor())
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+ return;
+ }
}
QualType AllocType = E->getAllocatedType();
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
- E->constructor_arg_begin(),
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
+ NewPtr, E->constructor_arg_begin(),
E->constructor_arg_end());
return;
@@ -760,7 +767,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
// The dtor took care of deleting the object.
ShouldCallDelete = false;
} else
- EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
+ Ptr);
}
}
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 172a77d78e5f..2595ff0060ca 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -27,359 +27,387 @@
using namespace clang;
using namespace CodeGen;
-namespace {
+//===----------------------------------------------------------------------===//
+// ConstStructBuilder
+//===----------------------------------------------------------------------===//
+
+namespace {
class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
bool Packed;
-
unsigned NextFieldOffsetInBytes;
-
unsigned LLVMStructAlignment;
-
std::vector<llvm::Constant *> Elements;
-
+public:
+ static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
+ InitListExpr *ILE);
+
+private:
ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
: CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
LLVMStructAlignment(1) { }
bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
- const Expr *InitExpr) {
- uint64_t FieldOffsetInBytes = FieldOffset / 8;
+ llvm::Constant *InitExpr);
- assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
- && "Field offset mismatch!");
+ bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitExpr);
- // Emit the field.
- llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF);
- if (!C)
- return false;
+ void AppendPadding(uint64_t NumBytes);
- unsigned FieldAlignment = getAlignment(C);
+ void AppendTailPadding(uint64_t RecordSize);
- // Round up the field offset to the alignment of the field type.
- uint64_t AlignedNextFieldOffsetInBytes =
- llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
+ void ConvertStructToPacked();
+
+ bool Build(InitListExpr *ILE);
- if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
- assert(!Packed && "Alignment is wrong even with a packed struct!");
+ unsigned getAlignment(const llvm::Constant *C) const {
+ if (Packed) return 1;
+ return CGM.getTargetData().getABITypeAlignment(C->getType());
+ }
- // Convert the struct to a packed struct.
- ConvertStructToPacked();
-
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
- }
+ uint64_t getSizeInBytes(const llvm::Constant *C) const {
+ return CGM.getTargetData().getTypeAllocSize(C->getType());
+ }
+};
- if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
- // We need to append padding.
- AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
+bool ConstStructBuilder::
+AppendField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitCst) {
+ uint64_t FieldOffsetInBytes = FieldOffset / 8;
- assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
- "Did not add enough padding!");
+ assert(NextFieldOffsetInBytes <= FieldOffsetInBytes
+ && "Field offset mismatch!");
- AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
- }
+ // Emit the field.
+ if (!InitCst)
+ return false;
- // Add the field.
- Elements.push_back(C);
- NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
-
- if (Packed)
- assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
- else
- LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
+ unsigned FieldAlignment = getAlignment(InitCst);
- return true;
- }
+ // Round up the field offset to the alignment of the field type.
+ uint64_t AlignedNextFieldOffsetInBytes =
+ llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
- bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
- const Expr *InitExpr) {
- llvm::ConstantInt *CI =
- cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr,
- Field->getType(),
- CGF));
- // FIXME: Can this ever happen?
- if (!CI)
- return false;
-
- if (FieldOffset > NextFieldOffsetInBytes * 8) {
- // We need to add padding.
- uint64_t NumBytes =
- llvm::RoundUpToAlignment(FieldOffset -
- NextFieldOffsetInBytes * 8, 8) / 8;
+ if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
+ assert(!Packed && "Alignment is wrong even with a packed struct!");
- AppendPadding(NumBytes);
- }
+ // Convert the struct to a packed struct.
+ ConvertStructToPacked();
+
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
+ if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
+ // We need to append padding.
+ AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes);
- llvm::APInt FieldValue = CI->getValue();
+ assert(NextFieldOffsetInBytes == FieldOffsetInBytes &&
+ "Did not add enough padding!");
- // Promote the size of FieldValue if necessary
- // FIXME: This should never occur, but currently it can because initializer
- // constants are cast to bool, and because clang is not enforcing bitfield
- // width limits.
- if (FieldSize > FieldValue.getBitWidth())
- FieldValue.zext(FieldSize);
+ AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
+ }
- // Truncate the size of FieldValue to the bit field size.
- if (FieldSize < FieldValue.getBitWidth())
- FieldValue.trunc(FieldSize);
+ // Add the field.
+ Elements.push_back(InitCst);
+ NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes +
+ getSizeInBytes(InitCst);
+
+ if (Packed)
+ assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!");
+ else
+ LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
- if (FieldOffset < NextFieldOffsetInBytes * 8) {
- // Either part of the field or the entire field can go into the previous
- // byte.
- assert(!Elements.empty() && "Elements can't be empty!");
+ return true;
+}
- unsigned BitsInPreviousByte =
- NextFieldOffsetInBytes * 8 - FieldOffset;
+bool ConstStructBuilder::
+ AppendBitField(const FieldDecl *Field, uint64_t FieldOffset,
+ llvm::Constant *InitCst) {
+ llvm::ConstantInt *CI = cast_or_null<llvm::ConstantInt>(InitCst);
+ // FIXME: Can this ever happen?
+ if (!CI)
+ return false;
- bool FitsCompletelyInPreviousByte =
- BitsInPreviousByte >= FieldValue.getBitWidth();
+ if (FieldOffset > NextFieldOffsetInBytes * 8) {
+ // We need to add padding.
+ uint64_t NumBytes =
+ llvm::RoundUpToAlignment(FieldOffset -
+ NextFieldOffsetInBytes * 8, 8) / 8;
- llvm::APInt Tmp = FieldValue;
+ AppendPadding(NumBytes);
+ }
- if (!FitsCompletelyInPreviousByte) {
- unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue();
- if (CGM.getTargetData().isBigEndian()) {
- Tmp = Tmp.lshr(NewFieldWidth);
- Tmp.trunc(BitsInPreviousByte);
+ llvm::APInt FieldValue = CI->getValue();
- // We want the remaining high bits.
- FieldValue.trunc(NewFieldWidth);
- } else {
- Tmp.trunc(BitsInPreviousByte);
+ // Promote the size of FieldValue if necessary
+ // FIXME: This should never occur, but currently it can because initializer
+ // constants are cast to bool, and because clang is not enforcing bitfield
+ // width limits.
+ if (FieldSize > FieldValue.getBitWidth())
+ FieldValue.zext(FieldSize);
- // We want the remaining low bits.
- FieldValue = FieldValue.lshr(BitsInPreviousByte);
- FieldValue.trunc(NewFieldWidth);
- }
- }
+ // Truncate the size of FieldValue to the bit field size.
+ if (FieldSize < FieldValue.getBitWidth())
+ FieldValue.trunc(FieldSize);
- Tmp.zext(8);
- if (CGM.getTargetData().isBigEndian()) {
- if (FitsCompletelyInPreviousByte)
- Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
- } else {
- Tmp = Tmp.shl(8 - BitsInPreviousByte);
- }
+ if (FieldOffset < NextFieldOffsetInBytes * 8) {
+ // Either part of the field or the entire field can go into the previous
+ // byte.
+ assert(!Elements.empty() && "Elements can't be empty!");
- // Or in the bits that go into the previous byte.
- if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back()))
- Tmp |= Val->getValue();
- else
- assert(isa<llvm::UndefValue>(Elements.back()));
+ unsigned BitsInPreviousByte =
+ NextFieldOffsetInBytes * 8 - FieldOffset;
- Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
+ bool FitsCompletelyInPreviousByte =
+ BitsInPreviousByte >= FieldValue.getBitWidth();
- if (FitsCompletelyInPreviousByte)
- return true;
- }
+ llvm::APInt Tmp = FieldValue;
- while (FieldValue.getBitWidth() > 8) {
- llvm::APInt Tmp;
+ if (!FitsCompletelyInPreviousByte) {
+ unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
if (CGM.getTargetData().isBigEndian()) {
- // We want the high bits.
- Tmp = FieldValue;
- Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
- Tmp.trunc(8);
+ Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining high bits.
+ FieldValue.trunc(NewFieldWidth);
} else {
- // We want the low bits.
- Tmp = FieldValue;
- Tmp.trunc(8);
+ Tmp.trunc(BitsInPreviousByte);
- FieldValue = FieldValue.lshr(8);
+ // We want the remaining low bits.
+ FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.trunc(NewFieldWidth);
}
-
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
- NextFieldOffsetInBytes++;
-
- FieldValue.trunc(FieldValue.getBitWidth() - 8);
}
- assert(FieldValue.getBitWidth() > 0 &&
- "Should have at least one bit left!");
- assert(FieldValue.getBitWidth() <= 8 &&
- "Should not have more than a byte left!");
+ Tmp.zext(8);
+ if (CGM.getTargetData().isBigEndian()) {
+ if (FitsCompletelyInPreviousByte)
+ Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
+ } else {
+ Tmp = Tmp.shl(8 - BitsInPreviousByte);
+ }
- if (FieldValue.getBitWidth() < 8) {
- if (CGM.getTargetData().isBigEndian()) {
- unsigned BitWidth = FieldValue.getBitWidth();
+ // Or in the bits that go into the previous byte.
+ if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back()))
+ Tmp |= Val->getValue();
+ else
+ assert(isa<llvm::UndefValue>(Elements.back()));
- FieldValue.zext(8);
- FieldValue = FieldValue << (8 - BitWidth);
- } else
- FieldValue.zext(8);
- }
+ Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
- // Append the last element.
- Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
- FieldValue));
- NextFieldOffsetInBytes++;
- return true;
+ if (FitsCompletelyInPreviousByte)
+ return true;
}
- void AppendPadding(uint64_t NumBytes) {
- if (!NumBytes)
- return;
+ while (FieldValue.getBitWidth() > 8) {
+ llvm::APInt Tmp;
+
+ if (CGM.getTargetData().isBigEndian()) {
+ // We want the high bits.
+ Tmp = FieldValue;
+ Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
+ Tmp.trunc(8);
+ } else {
+ // We want the low bits.
+ Tmp = FieldValue;
+ Tmp.trunc(8);
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ FieldValue = FieldValue.lshr(8);
+ }
- llvm::Constant *C = llvm::UndefValue::get(Ty);
- Elements.push_back(C);
- assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
+ NextFieldOffsetInBytes++;
- NextFieldOffsetInBytes += getSizeInBytes(C);
+ FieldValue.trunc(FieldValue.getBitWidth() - 8);
}
- void AppendTailPadding(uint64_t RecordSize) {
- assert(RecordSize % 8 == 0 && "Invalid record size!");
+ assert(FieldValue.getBitWidth() > 0 &&
+ "Should have at least one bit left!");
+ assert(FieldValue.getBitWidth() <= 8 &&
+ "Should not have more than a byte left!");
- uint64_t RecordSizeInBytes = RecordSize / 8;
- assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
+ if (FieldValue.getBitWidth() < 8) {
+ if (CGM.getTargetData().isBigEndian()) {
+ unsigned BitWidth = FieldValue.getBitWidth();
- unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
- AppendPadding(NumPadBytes);
+ FieldValue.zext(8);
+ FieldValue = FieldValue << (8 - BitWidth);
+ } else
+ FieldValue.zext(8);
}
- void ConvertStructToPacked() {
- std::vector<llvm::Constant *> PackedElements;
- uint64_t ElementOffsetInBytes = 0;
+ // Append the last element.
+ Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(),
+ FieldValue));
+ NextFieldOffsetInBytes++;
+ return true;
+}
- for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
- llvm::Constant *C = Elements[i];
+void ConstStructBuilder::AppendPadding(uint64_t NumBytes) {
+ if (!NumBytes)
+ return;
- unsigned ElementAlign =
- CGM.getTargetData().getABITypeAlignment(C->getType());
- uint64_t AlignedElementOffsetInBytes =
- llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
- if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
- // We need some padding.
- uint64_t NumBytes =
- AlignedElementOffsetInBytes - ElementOffsetInBytes;
+ llvm::Constant *C = llvm::UndefValue::get(Ty);
+ Elements.push_back(C);
+ assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!");
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- if (NumBytes > 1)
- Ty = llvm::ArrayType::get(Ty, NumBytes);
+ NextFieldOffsetInBytes += getSizeInBytes(C);
+}
- llvm::Constant *Padding = llvm::UndefValue::get(Ty);
- PackedElements.push_back(Padding);
- ElementOffsetInBytes += getSizeInBytes(Padding);
- }
+void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) {
+ assert(RecordSize % 8 == 0 && "Invalid record size!");
- PackedElements.push_back(C);
- ElementOffsetInBytes += getSizeInBytes(C);
- }
+ uint64_t RecordSizeInBytes = RecordSize / 8;
+ assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
- assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
- "Packing the struct changed its size!");
+ unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
+ AppendPadding(NumPadBytes);
+}
- Elements = PackedElements;
- LLVMStructAlignment = 1;
- Packed = true;
- }
-
- bool Build(InitListExpr *ILE) {
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
- unsigned FieldNo = 0;
- unsigned ElementNo = 0;
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- ElementNo < ILE->getNumInits() && Field != FieldEnd;
- ++Field, ++FieldNo) {
- if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
- continue;
-
- if (Field->isBitField()) {
- if (!Field->getIdentifier())
- continue;
-
- if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo),
- ILE->getInit(ElementNo)))
- return false;
- } else {
- if (!AppendField(*Field, Layout.getFieldOffset(FieldNo),
- ILE->getInit(ElementNo)))
- return false;
- }
+void ConstStructBuilder::ConvertStructToPacked() {
+ std::vector<llvm::Constant *> PackedElements;
+ uint64_t ElementOffsetInBytes = 0;
- ElementNo++;
- }
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+ llvm::Constant *C = Elements[i];
- uint64_t LayoutSizeInBytes = Layout.getSize() / 8;
+ unsigned ElementAlign =
+ CGM.getTargetData().getABITypeAlignment(C->getType());
+ uint64_t AlignedElementOffsetInBytes =
+ llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
- if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
- // If the struct is bigger than the size of the record type,
- // we must have a flexible array member at the end.
- assert(RD->hasFlexibleArrayMember() &&
- "Must have flexible array member if struct is bigger than type!");
-
- // No tail padding is necessary.
- return true;
- }
+ if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
+ // We need some padding.
+ uint64_t NumBytes =
+ AlignedElementOffsetInBytes - ElementOffsetInBytes;
- uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
- LLVMStructAlignment);
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ if (NumBytes > 1)
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
- // Check if we need to convert the struct to a packed struct.
- if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
- LLVMSizeInBytes > LayoutSizeInBytes) {
- assert(!Packed && "Size mismatch!");
-
- ConvertStructToPacked();
- assert(NextFieldOffsetInBytes == LayoutSizeInBytes &&
- "Converting to packed did not help!");
+ llvm::Constant *Padding = llvm::UndefValue::get(Ty);
+ PackedElements.push_back(Padding);
+ ElementOffsetInBytes += getSizeInBytes(Padding);
}
- // Append tail padding if necessary.
- AppendTailPadding(Layout.getSize());
-
- assert(Layout.getSize() / 8 == NextFieldOffsetInBytes &&
- "Tail padding mismatch!");
-
- return true;
+ PackedElements.push_back(C);
+ ElementOffsetInBytes += getSizeInBytes(C);
}
- unsigned getAlignment(const llvm::Constant *C) const {
- if (Packed)
- return 1;
+ assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
+ "Packing the struct changed its size!");
- return CGM.getTargetData().getABITypeAlignment(C->getType());
+ Elements = PackedElements;
+ LLVMStructAlignment = 1;
+ Packed = true;
+}
+
+bool ConstStructBuilder::Build(InitListExpr *ILE) {
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ unsigned FieldNo = 0;
+ unsigned ElementNo = 0;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isBitField() && !Field->getIdentifier())
+ continue;
+
+ // Get the initializer. A struct can include fields without initializers,
+ // we just use explicit null values for them.
+ llvm::Constant *EltInit;
+ if (ElementNo < ILE->getNumInits())
+ EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++),
+ Field->getType(), CGF);
+ else
+ EltInit = CGM.EmitNullConstant(Field->getType());
+
+ if (!Field->isBitField()) {
+ // Handle non-bitfield members.
+ if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit))
+ return false;
+ } else {
+ // Otherwise we have a bitfield.
+ if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit))
+ return false;
+ }
}
- uint64_t getSizeInBytes(const llvm::Constant *C) const {
- return CGM.getTargetData().getTypeAllocSize(C->getType());
+ uint64_t LayoutSizeInBytes = Layout.getSize() / 8;
+
+ if (NextFieldOffsetInBytes > LayoutSizeInBytes) {
+ // If the struct is bigger than the size of the record type,
+ // we must have a flexible array member at the end.
+ assert(RD->hasFlexibleArrayMember() &&
+ "Must have flexible array member if struct is bigger than type!");
+
+ // No tail padding is necessary.
+ return true;
}
-public:
- static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF,
- InitListExpr *ILE) {
- ConstStructBuilder Builder(CGM, CGF);
+ uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
+ LLVMStructAlignment);
- if (!Builder.Build(ILE))
- return 0;
+ // Check if we need to convert the struct to a packed struct.
+ if (NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ LLVMSizeInBytes > LayoutSizeInBytes) {
+ assert(!Packed && "Size mismatch!");
+
+ ConvertStructToPacked();
+ assert(NextFieldOffsetInBytes <= LayoutSizeInBytes &&
+ "Converting to packed did not help!");
+ }
- llvm::Constant *Result =
- llvm::ConstantStruct::get(CGM.getLLVMContext(),
- Builder.Elements, Builder.Packed);
+ // Append tail padding if necessary.
+ AppendTailPadding(Layout.getSize());
- assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
- Builder.getAlignment(Result)) ==
- Builder.getSizeInBytes(Result) && "Size mismatch!");
+ assert(Layout.getSize() / 8 == NextFieldOffsetInBytes &&
+ "Tail padding mismatch!");
- return Result;
- }
-};
+ return true;
+}
+
+llvm::Constant *ConstStructBuilder::
+ BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) {
+ ConstStructBuilder Builder(CGM, CGF);
+
+ if (!Builder.Build(ILE))
+ return 0;
+
+ llvm::Constant *Result =
+ llvm::ConstantStruct::get(CGM.getLLVMContext(),
+ Builder.Elements, Builder.Packed);
+
+ assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes,
+ Builder.getAlignment(Result)) ==
+ Builder.getSizeInBytes(Result) && "Size mismatch!");
+
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// ConstExprEmitter
+//===----------------------------------------------------------------------===//
+
class ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
@@ -418,13 +446,18 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
+ // FIXME: We shouldn't use / 8 here.
+ uint64_t PointerWidthInBytes =
+ CGM.getContext().Target.getPointerWidth(0) / 8;
+
// 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);
+ Values[0] = llvm::ConstantInt::get(PtrDiffTy,
+ (Index * PointerWidthInBytes) + 1);
} else {
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -528,8 +561,6 @@ public:
const MemberPointerType *DestTy =
E->getType()->getAs<MemberPointerType>();
- const CXXRecordDecl *BaseClass =
- cast<CXXRecordDecl>(cast<RecordType>(SrcTy->getClass())->getDecl());
const CXXRecordDecl *DerivedClass =
cast<CXXRecordDecl>(cast<RecordType>(DestTy->getClass())->getDecl());
@@ -543,7 +574,7 @@ public:
// Check if we need to update the adjustment.
if (llvm::Constant *Offset =
- CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) {
+ CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) {
llvm::Constant *Values[2];
Values[0] = CS->getOperand(0);
@@ -587,17 +618,15 @@ public:
}
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
- std::vector<llvm::Constant*> Elts;
- const llvm::ArrayType *AType =
- cast<llvm::ArrayType>(ConvertType(ILE->getType()));
unsigned NumInitElements = ILE->getNumInits();
- // FIXME: Check for wide strings
- // FIXME: Check for NumInitElements exactly equal to 1??
- if (NumInitElements > 0 &&
+ if (NumInitElements == 1 &&
(isa<StringLiteral>(ILE->getInit(0)) ||
- isa<ObjCEncodeExpr>(ILE->getInit(0))) &&
- ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType())
+ isa<ObjCEncodeExpr>(ILE->getInit(0))))
return Visit(ILE->getInit(0));
+
+ std::vector<llvm::Constant*> Elts;
+ const llvm::ArrayType *AType =
+ cast<llvm::ArrayType>(ConvertType(ILE->getType()));
const llvm::Type *ElemTy = AType->getElementType();
unsigned NumElements = AType->getNumElements();
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index d1c0f8dc3d73..984968802382 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -133,6 +133,7 @@ public:
CGF.getContext().typesAreCompatible(
E->getArgType1(), E->getArgType2()));
}
+ Value *VisitOffsetOfExpr(const OffsetOfExpr *E);
Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
@@ -242,7 +243,7 @@ public:
return Visit(E->getSubExpr());
}
Value *VisitUnaryOffsetOf(const UnaryOperator *E);
-
+
// C++
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
@@ -314,6 +315,10 @@ public:
}
BinOpInfo EmitBinOps(const BinaryOperator *E);
+ LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
+ Value *&BitFieldResult);
+
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
@@ -818,16 +823,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));
case CastExpr::CK_BaseToDerived: {
- const CXXRecordDecl *BaseClassDecl =
- E->getType()->getCXXRecordDeclForPointerType();
const CXXRecordDecl *DerivedClassDecl =
DestTy->getCXXRecordDeclForPointerType();
- Value *Src = Visit(const_cast<Expr*>(E));
-
- bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
- return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
- NullCheckValue);
+ return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ CE->getBasePath(),
+ ShouldNullCheckClassCastValue(CE));
}
case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
@@ -836,15 +837,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
- const RecordType *BaseClassTy =
- DestTy->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
-
- Value *Src = Visit(const_cast<Expr*>(E));
-
- bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
- return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
- NullCheckValue);
+ return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
+ CE->getBasePath(),
+ ShouldNullCheckClassCastValue(CE));
}
case CastExpr::CK_Dynamic: {
Value *V = Visit(const_cast<Expr*>(E));
@@ -894,7 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
std::swap(DerivedDecl, BaseDecl);
if (llvm::Constant *Adj =
- CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) {
+ CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
+ CE->getBasePath())) {
if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
Src = Builder.CreateSub(Src, Adj, "adj");
else
@@ -1035,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext");
}
+Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+ Expr::EvalResult Result;
+ if(E->Evaluate(Result, CGF.getContext()))
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+
+ // FIXME: Cannot support code generation for non-constant offsetof.
+ unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error,
+ "cannot compile non-constant __builtin_offsetof");
+ CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()),
+ DiagID)
+ << E->getSourceRange();
+
+ return llvm::Constant::getNullValue(ConvertType(E->getType()));
+}
+
/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of
/// argument of the sizeof expression as an integer.
Value *
@@ -1103,22 +1114,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
return Result;
}
-Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
- Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
- bool Ignore = TestAndClearIgnoreResultAssign();
+LValue ScalarExprEmitter::EmitCompoundAssignLValue(
+ const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
+ Value *&BitFieldResult) {
QualType LHSTy = E->getLHS()->getType();
-
+ BitFieldResult = 0;
BinOpInfo OpInfo;
-
+
if (E->getComputationResultType()->isAnyComplexType()) {
// This needs to go through the complex expression emitter, but it's a tad
// complicated to do that... I'm leaving it out for now. (Note that we do
// actually need the imaginary part of the RHS for multiplication and
// division.)
CGF.ErrorUnsupported(E, "complex compound assignment");
- return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ return LValue();
}
-
+
// Emit the RHS first. __block variables need to have the rhs evaluated
// first, plus this should improve codegen a little.
OpInfo.RHS = Visit(E->getRHS());
@@ -1129,13 +1142,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
-
+
// Expand the binary operator.
Value *Result = (this->*Func)(OpInfo);
-
+
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
-
+
// Store the result value into the LHS lvalue. Bit-fields are handled
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after the
@@ -1144,11 +1157,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LHSLV.isVolatileQualified()) {
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
&Result);
- return Result;
+ BitFieldResult = Result;
+ return LHSLV;
} else
CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
} else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+ return LHSLV;
+}
+
+Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
+ Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
+ bool Ignore = TestAndClearIgnoreResultAssign();
+ Value *BitFieldResult;
+ LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult);
+ if (BitFieldResult)
+ return BitFieldResult;
+
if (Ignore)
return 0;
return EmitLoadOfLValue(LHSLV, E->getType());
@@ -1914,3 +1939,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
return LV;
}
+
+LValue CodeGenFunction::EmitCompoundAssignOperatorLValue(
+ const CompoundAssignOperator *E) {
+ ScalarExprEmitter Scalar(*this);
+ Value *BitFieldResult = 0;
+ switch (E->getOpcode()) {
+#define COMPOUND_OP(Op) \
+ case BinaryOperator::Op##Assign: \
+ return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \
+ BitFieldResult)
+ COMPOUND_OP(Mul);
+ COMPOUND_OP(Div);
+ COMPOUND_OP(Rem);
+ COMPOUND_OP(Add);
+ COMPOUND_OP(Sub);
+ COMPOUND_OP(Shl);
+ COMPOUND_OP(Shr);
+ COMPOUND_OP(And);
+ COMPOUND_OP(Xor);
+ COMPOUND_OP(Or);
+#undef COMPOUND_OP
+
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ case BinaryOperator::Assign:
+ case BinaryOperator::Comma:
+ assert(false && "Not valid compound assignment operators");
+ break;
+ }
+
+ llvm_unreachable("Unhandled compound assignment operator");
+}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 206d438ced67..33592501d734 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -53,31 +53,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
// arguments in generic code.
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- const Expr *ReceiverExpr = E->getReceiver();
bool isSuperMessage = false;
bool isClassMessage = false;
+ ObjCInterfaceDecl *OID = 0;
// Find the receiver
- llvm::Value *Receiver;
- if (!ReceiverExpr) {
- const ObjCInterfaceDecl *OID = E->getClassInfo().Decl;
-
- // Very special case, super send in class method. The receiver is
- // self (the class object) and the send uses super semantics.
- if (!OID) {
- assert(E->getClassName()->isStr("super") &&
- "Unexpected missing class interface in message send.");
- isSuperMessage = true;
- Receiver = LoadObjCSelf();
- } else {
- Receiver = Runtime.GetClass(Builder, OID);
- }
-
+ llvm::Value *Receiver = 0;
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Receiver = EmitScalarExpr(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class: {
+ const ObjCInterfaceType *IFace
+ = E->getClassReceiver()->getAs<ObjCInterfaceType>();
+ OID = IFace->getDecl();
+ assert(IFace && "Invalid Objective-C class message send");
+ Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
- } else if (isa<ObjCSuperExpr>(E->getReceiver())) {
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:
+ Receiver = LoadObjCSelf();
isSuperMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperClass:
Receiver = LoadObjCSelf();
- } else {
- Receiver = EmitScalarExpr(E->getReceiver());
+ isSuperMessage = true;
+ isClassMessage = true;
+ break;
}
CallArgList Args;
@@ -98,7 +103,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
}
return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(),
- Receiver, isClassMessage, Args,
+ Receiver, Args, OID,
E->getMethodDecl());
}
@@ -148,19 +153,21 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ bool IsAtomic =
+ !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
// FIXME: This is rather murky, we create this here since they will not have
// been created by Sema for us.
OMD->createImplicitParams(getContext(), IMP->getClassInterface());
StartObjCMethod(OMD, IMP->getClassInterface());
-
+
// Determine if we should use an objc_getProperty call for
// this. Non-atomic properties are directly evaluated.
// atomic 'copy' and 'retain' properties are also directly
// evaluated in gc-only mode.
if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
+ IsAtomic &&
(PD->getSetterKind() == ObjCPropertyDecl::Copy ||
PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
llvm::Value *GetPropertyFn =
@@ -208,7 +215,44 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
}
else if (hasAggregateLLVMType(Ivar->getType())) {
- EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
+ bool IsStrong = false;
+ if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType())))
+ && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
+ && CGM.getObjCRuntime().GetCopyStructFunction()) {
+ llvm::Value *GetCopyStructFn =
+ CGM.getObjCRuntime().GetCopyStructFunction();
+ CodeGenTypes &Types = CGM.getTypes();
+ // objc_copyStruct (ReturnValue, &structIvar,
+ // sizeof (Type of Ivar), isAtomic, false);
+ CallArgList Args;
+ RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue,
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ // sizeof (Type of Ivar)
+ uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8;
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size);
+ Args.push_back(std::make_pair(RValue::get(SizeVal),
+ getContext().LongTy));
+ llvm::Value *isAtomic =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
+ IsAtomic ? 1 : 0);
+ Args.push_back(std::make_pair(RValue::get(isAtomic),
+ getContext().BoolTy));
+ llvm::Value *hasStrong =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
+ IsStrong ? 1 : 0);
+ Args.push_back(std::make_pair(RValue::get(hasStrong),
+ getContext().BoolTy));
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ FunctionType::ExtInfo()),
+ GetCopyStructFn, ReturnValueSlot(), Args);
+ }
+ else
+ EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
} else {
CodeGenTypes &Types = CGM.getTypes();
RValue RV = EmitLoadOfLValue(LV, Ivar->getType());
@@ -289,6 +333,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FunctionType::ExtInfo()),
SetPropertyFn,
ReturnValueSlot(), Args);
+ } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) &&
+ !Ivar->getType()->isAnyComplexType() &&
+ IndirectObjCSetterArg(*CurFnInfo)
+ && CGM.getObjCRuntime().GetCopyStructFunction()) {
+ // objc_copyStruct (&structIvar, &Arg,
+ // sizeof (struct something), true, false);
+ llvm::Value *GetCopyStructFn =
+ CGM.getObjCRuntime().GetCopyStructFunction();
+ CodeGenTypes &Types = CGM.getTypes();
+ CallArgList Args;
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
+ RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
+ Types.ConvertType(getContext().VoidPtrTy)));
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
+ llvm::Value *ArgAsPtrTy =
+ Builder.CreateBitCast(Arg,
+ Types.ConvertType(getContext().VoidPtrTy));
+ RV = RValue::get(ArgAsPtrTy);
+ Args.push_back(std::make_pair(RV, getContext().VoidPtrTy));
+ // sizeof (Type of Ivar)
+ uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8;
+ llvm::Value *SizeVal =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size);
+ Args.push_back(std::make_pair(RValue::get(SizeVal),
+ getContext().LongTy));
+ llvm::Value *True =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
+ Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
+ llvm::Value *False =
+ llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
+ Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy));
+ EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
+ FunctionType::ExtInfo()),
+ GetCopyStructFn, ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
SourceLocation Loc = PD->getLocation();
@@ -304,7 +383,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
if (getContext().getCanonicalType(Ivar->getType()) !=
getContext().getCanonicalType(ArgDecl->getType())) {
ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg,
- false);
+ CXXBaseSpecifierArray(), false);
BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign,
Ivar->getType(), Loc);
EmitStmt(&Assign);
@@ -318,6 +397,83 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
+void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
+ ObjCMethodDecl *MD,
+ bool ctor) {
+ llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> IvarInitializers;
+ MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
+ StartObjCMethod(MD, IMP->getClassInterface());
+ for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
+ E = IMP->init_end(); B != E; ++B) {
+ CXXBaseOrMemberInitializer *Member = (*B);
+ IvarInitializers.push_back(Member);
+ }
+ if (ctor) {
+ for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) {
+ CXXBaseOrMemberInitializer *IvarInit = IvarInitializers[I];
+ FieldDecl *Field = IvarInit->getMember();
+ QualType FieldType = Field->getType();
+ ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
+ LoadObjCSelf(), Ivar, 0);
+ EmitAggExpr(IvarInit->getInit(), LV.getAddress(),
+ LV.isVolatileQualified(), false, true);
+ }
+ // constructor returns 'self'.
+ CodeGenTypes &Types = CGM.getTypes();
+ QualType IdTy(CGM.getContext().getObjCIdType());
+ llvm::Value *SelfAsId =
+ Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
+ EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
+ }
+ else {
+ // dtor
+ for (size_t i = IvarInitializers.size(); i > 0; --i) {
+ FieldDecl *Field = IvarInitializers[i - 1]->getMember();
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
+ LoadObjCSelf(), Ivar, 0);
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(LV.getAddress(), BasePtr);
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ }
+ else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(CGM.getContext()),
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ LV.getAddress());
+ }
+ }
+ FinishFunction();
+}
+
+bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) {
+ CGFunctionInfo::const_arg_iterator it = FI.arg_begin();
+ it++; it++;
+ const ABIArgInfo &AI = it->info;
+ // FIXME. Is this sufficient check?
+ return (AI.getKind() == ABIArgInfo::Indirect);
+}
+
+bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
+ if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ return false;
+ if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
+ return FDTTy->getDecl()->hasObjectMember();
+ return false;
+}
+
llvm::Value *CodeGenFunction::LoadObjCSelf() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
// See if we need to lazily forward self inside a block literal.
@@ -360,7 +516,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
return CGM.getObjCRuntime().
GenerateMessageSend(*this, Exp->getType(), S,
EmitScalarExpr(E->getBase()),
- false, CallArgList());
+ CallArgList());
} else {
const ObjCImplicitSetterGetterRefExpr *KE =
cast<ObjCImplicitSetterGetterRefExpr>(Exp);
@@ -376,7 +532,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
return CGM.getObjCRuntime().
GenerateMessageSend(*this, Exp->getType(), S,
Receiver,
- KE->getInterfaceDecl() != 0, CallArgList());
+ CallArgList(), KE->getInterfaceDecl());
}
}
@@ -413,7 +569,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
Args.push_back(std::make_pair(Src, E->getType()));
CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
EmitScalarExpr(E->getBase()),
- false, Args);
+ Args);
} else if (const ObjCImplicitSetterGetterRefExpr *E =
dyn_cast<ObjCImplicitSetterGetterRefExpr>(Exp)) {
Selector S = E->getSetterMethod()->getSelector();
@@ -430,7 +586,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp,
Args.push_back(std::make_pair(Src, E->getType()));
CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
Receiver,
- E->getInterfaceDecl() != 0, Args);
+ Args, E->getInterfaceDecl());
} else
assert (0 && "bad expression node in EmitObjCPropertySet");
}
@@ -498,7 +654,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
CGM.getObjCRuntime().GenerateMessageSend(*this,
getContext().UnsignedLongTy,
FastEnumSel,
- Collection, false, Args);
+ Collection, Args);
llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy,
"limit.ptr");
@@ -623,7 +779,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
CGM.getObjCRuntime().GenerateMessageSend(*this,
getContext().UnsignedLongTy,
FastEnumSel,
- Collection, false, Args);
+ Collection, Args);
Builder.CreateStore(CountRV.getScalarVal(), LimitPtr);
Limit = Builder.CreateLoad(LimitPtr);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index d4452000dc04..3c51b7ee9de7 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -26,6 +26,7 @@
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
+#include "llvm/LLVMContext.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Compiler.h"
@@ -81,6 +82,8 @@ private:
llvm::Constant *Zeros[2];
llvm::Constant *NULLPtr;
llvm::LLVMContext &VMContext;
+ /// Metadata kind used to tie method lookups to message sends.
+ unsigned msgSendMDKind;
private:
llvm::Constant *GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
@@ -112,7 +115,8 @@ private:
llvm::Constant *Methods,
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
- llvm::Constant *Properties);
+ llvm::Constant *Properties,
+ bool isMeta=false);
llvm::Constant *GenerateProtocolMethodList(
const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames,
const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes);
@@ -141,8 +145,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
@@ -170,6 +174,7 @@ public:
virtual llvm::Function *ModuleInitFunction();
virtual llvm::Function *GetPropertyGetFunction();
virtual llvm::Function *GetPropertySetFunction();
+ virtual llvm::Function *GetCopyStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
@@ -221,10 +226,6 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
}
-static std::string SymbolNameForClass(const std::string &ClassName) {
- return "_OBJC_CLASS_" + ClassName;
-}
-
static std::string SymbolNameForMethod(const std::string &ClassName, const
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
{
@@ -238,6 +239,9 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
: CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0),
MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) {
+
+ msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
+
IntTy = cast<llvm::IntegerType>(
CGM.getTypes().ConvertType(CGM.getContext().IntTy));
LongTy = cast<llvm::IntegerType>(
@@ -452,12 +456,15 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
return RValue::get(0);
}
}
- llvm::Value *cmd = GetSelector(CGF.Builder, Sel);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *cmd = GetSelector(Builder, Sel);
+
CallArgList ActualArgs;
ActualArgs.push_back(
- std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+ std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)),
ASTIdTy));
ActualArgs.push_back(std::make_pair(RValue::get(cmd),
CGF.getContext().getObjCSelType()));
@@ -481,7 +488,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
IdTy, Params, true), "objc_get_class");
}
- ReceiverClass = CGF.Builder.CreateCall(classLookupFunction,
+ ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
} else {
// Set up global aliases for the metaclass or class pointer if they do not
@@ -506,36 +513,64 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
// Cast the pointer to a simplified version of the class structure
- ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass,
+ ReceiverClass = Builder.CreateBitCast(ReceiverClass,
llvm::PointerType::getUnqual(
llvm::StructType::get(VMContext, IdTy, IdTy, NULL)));
// Get the superclass pointer
- ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1);
+ ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1);
// Load the superclass pointer
- ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass);
+ ReceiverClass = Builder.CreateLoad(ReceiverClass);
// Construct the structure used to look up the IMP
llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext,
Receiver->getType(), IdTy, NULL);
- llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy);
+ llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
- CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0));
- CGF.Builder.CreateStore(ReceiverClass,
- CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+ Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
+ Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
// Get the IMP
std::vector<const llvm::Type*> Params;
Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy));
Params.push_back(SelectorTy);
+
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+ llvm::Value *imp;
+
+ if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
+ // The lookup function returns a slot, which can be safely cached.
+ llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy,
+ IntTy, llvm::PointerType::getUnqual(impType), NULL);
+
+ llvm::Constant *lookupFunction =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::PointerType::getUnqual(SlotTy), Params, true),
+ "objc_slot_lookup_super");
+
+ llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs,
+ lookupArgs+2);
+ slot->setOnlyReadsMemory();
+
+ imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+ } else {
llvm::Constant *lookupFunction =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::PointerType::getUnqual(impType), Params, true),
"objc_msg_lookup_super");
+ imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2);
+ }
- llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs,
- lookupArgs+2);
-
- return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
+ llvm::Value *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage)
+ };
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+
+ llvm::Instruction *call;
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ 0, &call);
+ call->setMetadata(msgSendMDKind, node);
+ return msgRet;
}
/// Generate code for a message send expression.
@@ -544,9 +579,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
+ // Strip out message sends to retain / release in GC mode
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
return RValue::get(Receiver);
@@ -555,7 +591,39 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
return RValue::get(0);
}
}
+
CGBuilderTy &Builder = CGF.Builder;
+
+ // If the return type is something that goes in an integer register, the
+ // runtime will handle 0 returns. For other cases, we fill in the 0 value
+ // ourselves.
+ //
+ // The language spec says the result of this kind of message send is
+ // undefined, but lots of people seem to have forgotten to read that
+ // paragraph and insist on sending messages to nil that have structure
+ // returns. With GCC, this generates a random return value (whatever happens
+ // to be on the stack / in those registers at the time) on most platforms,
+ // and generates a SegV on SPARC. With LLVM it corrupts the stack.
+ bool isPointerSizedReturn = false;
+ if (ResultType->isAnyPointerType() || ResultType->isIntegralType() ||
+ ResultType->isVoidType())
+ isPointerSizedReturn = true;
+
+ llvm::BasicBlock *startBB = 0;
+ llvm::BasicBlock *messageBB = 0;
+ llvm::BasicBlock *contiueBB = 0;
+
+ if (!isPointerSizedReturn) {
+ startBB = Builder.GetInsertBlock();
+ messageBB = CGF.createBasicBlock("msgSend");
+ contiueBB = CGF.createBasicBlock("continue");
+
+ llvm::Value *isNil = Builder.CreateICmpEQ(Receiver,
+ llvm::Constant::getNullValue(Receiver->getType()));
+ Builder.CreateCondBr(isNil, contiueBB, messageBB);
+ CGF.EmitBlock(messageBB);
+ }
+
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
@@ -577,6 +645,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
+ llvm::Value *impMD[] = {
+ llvm::MDString::get(VMContext, Sel.getAsString()),
+ llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0)
+ };
+ llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3);
+
+
llvm::Value *imp;
// For sender-aware dispatch, we pass the sender as the third argument to a
// lookup function. When sending messages from C code, the sender is nil.
@@ -611,9 +687,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
LookupFn->setDoesNotCapture(1);
}
- llvm::Value *slot =
+ llvm::CallInst *slot =
Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self);
+ slot->setOnlyReadsMemory();
+ slot->setMetadata(msgSendMDKind, node);
+
imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
+
// The lookup function may have changed the receiver, so make sure we use
// the new one.
ActualArgs[0] =
@@ -628,9 +708,46 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
"objc_msg_lookup");
imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);
+ cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node);
}
-
- return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs);
+ llvm::Instruction *call;
+ RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs,
+ 0, &call);
+ call->setMetadata(msgSendMDKind, node);
+
+ if (!isPointerSizedReturn) {
+ CGF.EmitBlock(contiueBB);
+ if (msgRet.isScalar()) {
+ llvm::Value *v = msgRet.getScalarVal();
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ phi->addIncoming(v, messageBB);
+ phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB);
+ msgRet = RValue::get(phi);
+ } else if (msgRet.isAggregate()) {
+ llvm::Value *v = msgRet.getAggregateAddr();
+ llvm::PHINode *phi = Builder.CreatePHI(v->getType());
+ const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType());
+ llvm::AllocaInst *NullVal =
+ CGF.CreateTempAlloca(RetTy->getElementType(), "null");
+ CGF.InitTempAlloca(NullVal,
+ llvm::Constant::getNullValue(RetTy->getElementType()));
+ phi->addIncoming(v, messageBB);
+ phi->addIncoming(NullVal, startBB);
+ msgRet = RValue::getAggregate(phi);
+ } else /* isComplex() */ {
+ std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal();
+ llvm::PHINode *phi = Builder.CreatePHI(v.first->getType());
+ phi->addIncoming(v.first, messageBB);
+ phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()),
+ startBB);
+ llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType());
+ phi2->addIncoming(v.second, messageBB);
+ phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()),
+ startBB);
+ msgRet = RValue::getComplex(phi, phi2);
+ }
+ }
+ return msgRet;
}
/// Generates a MethodList. Used in construction of a objc_class and
@@ -749,7 +866,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
llvm::Constant *Methods,
llvm::Constant *Protocols,
llvm::Constant *IvarOffsets,
- llvm::Constant *Properties) {
+ llvm::Constant *Properties,
+ bool isMeta) {
// Set up the class structure
// Note: Several of these are char*s when they should be ids. This is
// because the runtime performs this translation on load.
@@ -799,8 +917,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
// Create an instance of the structure
// This is now an externally visible symbol, so that we can speed up class
// messages in the next ABI.
- return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name),
- llvm::GlobalValue::ExternalLinkage);
+ return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_":
+ "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage);
}
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
@@ -1289,16 +1407,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
instanceSize = 0 - (instanceSize - superInstanceSize);
}
- for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(),
- endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) {
+
+ // Collect declared and synthesized ivars.
+ llvm::SmallVector<ObjCIvarDecl*, 16> OIvars;
+ CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars);
+
+ for (unsigned i = 0, e = OIvars.size(); i != e; ++i) {
+ ObjCIvarDecl *IVD = OIvars[i];
// Store the name
- IvarNames.push_back(MakeConstantString((*iter)->getNameAsString()));
+ IvarNames.push_back(MakeConstantString(IVD->getNameAsString()));
// Get the type encoding for this ivar
std::string TypeStr;
- Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
+ Context.getObjCEncodingForType(IVD->getType(), TypeStr);
IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
- uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD);
uint64_t Offset = BaseOffset;
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
@@ -1309,7 +1432,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
false, llvm::GlobalValue::ExternalLinkage,
llvm::ConstantInt::get(IntTy, BaseOffset),
"__objc_ivar_offset_value_" + ClassName +"." +
- (*iter)->getNameAsString()));
+ IVD->getNameAsString()));
}
llvm::Constant *IvarOffsetArrayInit =
llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy,
@@ -1411,7 +1534,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
- empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
+ empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true);
// Generate the class structure
llvm::Constant *ClassStruct =
@@ -1658,10 +1781,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
- Params.push_back(LongTy);
+ Params.push_back(IntTy);
Params.push_back(BoolTy);
- // void objc_getProperty (id, SEL, ptrdiff_t, bool)
+ // void objc_getProperty (id, SEL, int, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(IdTy, Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
@@ -1674,18 +1796,22 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() {
CGM.getTypes().ConvertType(CGM.getContext().BoolTy);
Params.push_back(IdTy);
Params.push_back(SelectorTy);
- // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64
- Params.push_back(LongTy);
+ Params.push_back(IntTy);
Params.push_back(IdTy);
Params.push_back(BoolTy);
Params.push_back(BoolTy);
- // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool)
+ // void objc_setProperty (id, SEL, int, id, bool, bool)
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy,
"objc_setProperty"));
}
+// FIXME. Implement this.
+llvm::Function *CGObjCGNU::GetCopyStructFunction() {
+ return 0;
+}
+
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -1764,7 +1890,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow");
llvm::SmallVector<llvm::Value*, 8> ESelArgs;
- llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+ llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers;
ESelArgs.push_back(Exc);
ESelArgs.push_back(Personality);
@@ -1772,12 +1898,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
bool HasCatchAll = false;
// Only @try blocks are allowed @catch blocks, but both can have @finally
if (isTry) {
- if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+ const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
CGF.setInvokeDest(CatchInCatch);
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
- const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
+ const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
Handlers.push_back(std::make_pair(CatchDecl,
CatchStmt->getCatchBody()));
@@ -1816,7 +1943,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
ESelArgs.begin(), ESelArgs.end(), "selector");
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
- const ParmVarDecl *CatchParam = Handlers[i].first;
+ const VarDecl *CatchParam = Handlers[i].first;
const Stmt *CatchBody = Handlers[i].second;
llvm::BasicBlock *Next = 0;
@@ -2046,7 +2173,14 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
// when linked against code which isn't (most of the time).
llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name);
if (!IvarOffsetPointer) {
- uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+ uint64_t Offset;
+ if (ObjCImplementationDecl *OID =
+ CGM.getContext().getObjCImplementation(
+ const_cast<ObjCInterfaceDecl *>(ID)))
+ Offset = ComputeIvarBaseOffset(CGM, OID, Ivar);
+ else
+ Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
+
llvm::ConstantInt *OffsetGuess =
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar");
// Don't emit the guess in non-PIC code because the linker will not be able
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index ac8fa057a0e7..77eabbfd4141 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -124,9 +124,19 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// layout object. However, this is blocked on other cleanups to the
// Objective-C code, so for now we just live with allocating a bunch of these
// objects.
- unsigned FieldNo = 0; // This value is unused.
+
+ // We always construct a single, possibly unaligned, access for this case.
+ CGBitFieldInfo::AccessInfo AI;
+ AI.FieldIndex = 0;
+ AI.FieldByteOffset = 0;
+ AI.FieldBitStart = BitOffset;
+ AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy);
+ AI.AccessAlignment = 0;
+ AI.TargetBitOffset = 0;
+ AI.TargetBitWidth = BitFieldSize;
+
CGBitFieldInfo *Info =
- new (CGF.CGM.getContext()) CGBitFieldInfo(FieldNo, BitOffset, BitFieldSize,
+ new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI,
IvarTy->isSignedIntegerType());
// FIXME: We need to set a very conservative alignment on this, or make sure
@@ -329,6 +339,24 @@ public:
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
+
+ llvm::Constant *getCopyStructFn() {
+ CodeGen::CodeGenTypes &Types = CGM.getTypes();
+ ASTContext &Ctx = CGM.getContext();
+ // void objc_copyStruct (void *, const void *, size_t, bool, bool)
+ llvm::SmallVector<CanQualType,5> Params;
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.VoidPtrTy);
+ Params.push_back(Ctx.LongTy);
+ Params.push_back(Ctx.BoolTy);
+ Params.push_back(Ctx.BoolTy);
+ const llvm::FunctionType *FTy =
+ Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
+ FunctionType::ExtInfo()),
+ false);
+ return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
+ }
+
llvm::Constant *getEnumerationMutationFn() {
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -954,6 +982,10 @@ protected:
const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
+ /// EmitImageInfo - Emit the image info marker used to encode some module
+ /// level information.
+ void EmitImageInfo();
+
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGM(cgm), VMContext(cgm.getLLVMContext()) { }
@@ -980,9 +1012,6 @@ public:
class CGObjCMac : public CGObjCCommonMac {
private:
ObjCTypesHelper ObjCTypes;
- /// EmitImageInfo - Emit the image info marker used to encode some module
- /// level information.
- void EmitImageInfo();
/// EmitModuleInfo - Another marker encoding module level
/// information.
@@ -1100,8 +1129,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
@@ -1134,6 +1163,7 @@ public:
virtual llvm::Constant *GetPropertyGetFunction();
virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetCopyStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
@@ -1327,8 +1357,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method);
virtual CodeGen::RValue
@@ -1366,6 +1396,11 @@ public:
virtual llvm::Constant *GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
+
+ virtual llvm::Constant *GetCopyStructFunction() {
+ return ObjCTypes.getCopyStructFn();
+ }
+
virtual llvm::Constant *EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
@@ -1459,9 +1494,20 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
};
*/
+/// or Generate a constant NSString object.
+/*
+ struct __builtin_NSString {
+ const int *isa; // point to __NSConstantStringClassReference
+ const char *str;
+ unsigned int length;
+ };
+*/
+
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
- return CGM.GetAddrOfConstantCFString(SL);
+ return (CGM.getLangOptions().NoConstantCFStrings == 0 ?
+ CGM.GetAddrOfConstantCFString(SL) :
+ CGM.GetAddrOfConstantNSString(SL));
}
/// Generates a message send where the super is the receiver. This is
@@ -1531,8 +1577,8 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitLegacyMessageSend(CGF, ResultType,
EmitSelector(CGF.Builder, Sel),
@@ -1696,7 +1742,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
Init,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
- Entry->setAlignment(4);
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
@@ -1718,7 +1763,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
0,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
- Entry->setAlignment(4);
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
@@ -2039,6 +2083,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Interface->protocol_begin(),
Interface->protocol_end());
unsigned Flags = eClassFlags_Factory;
+ if (ID->getNumIvarInitializers())
+ Flags |= eClassFlags_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8;
@@ -2430,6 +2476,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() {
return ObjCTypes.getSetPropertyFn();
}
+llvm::Constant *CGObjCMac::GetCopyStructFunction() {
+ return ObjCTypes.getCopyStructFn();
+}
+
llvm::Constant *CGObjCMac::EnumerationMutationFunction() {
return ObjCTypes.getEnumerationMutationFn();
}
@@ -2597,8 +2647,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
CallTryExitPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
- } else if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+ } else if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+ const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
+
// Enter a new exception try block (in case a @catch block throws
// an exception).
CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
@@ -2617,10 +2668,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// matched and avoid generating code for falling off the end if
// so.
bool AllMatched = false;
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+ for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
- const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
+ const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
const ObjCObjectPointerType *OPT = 0;
// catch(...) always matches.
@@ -2911,18 +2963,17 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
/// unsigned flags;
/// };
enum ImageInfoFlags {
- eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what
- // this implies.
+ eImageInfo_FixAndContinue = (1 << 0),
eImageInfo_GarbageCollected = (1 << 1),
eImageInfo_GCOnly = (1 << 2),
eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set.
- // A flag indicating that the module has no instances of an
- // @synthesize of a superclass variable. <rdar://problem/6803242>
+ // A flag indicating that the module has no instances of a @synthesize of a
+ // superclass variable. <rdar://problem/6803242>
eImageInfo_CorrectedSynthesize = (1 << 4)
};
-void CGObjCMac::EmitImageInfo() {
+void CGObjCCommonMac::EmitImageInfo() {
unsigned version = 0; // Version is unused?
unsigned flags = 0;
@@ -3132,19 +3183,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
if (RD) {
- const CGRecordLayout &RL =
- CGM.getTypes().getCGRecordLayout(Field->getParent());
- if (Field->isBitField()) {
- const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field);
-
- const llvm::Type *Ty =
- CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
- uint64_t TypeSize =
- CGM.getTypes().getTargetData().getTypeAllocSize(Ty);
- FieldOffset = Info.FieldNo * TypeSize;
- } else
- FieldOffset =
- Layout->getElementOffset(RL.getLLVMFieldNo(Field));
+ // Note that 'i' here is actually the field index inside RD of Field,
+ // although this dependency is hidden.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ FieldOffset = RL.getFieldOffset(i) / 8;
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
@@ -3536,7 +3578,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D,
<< '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID =
dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))
- OS << '(' << CID->getNameAsString() << ')';
+ OS << '(' << CID << ')';
OS << ' ' << D->getSelector().getAsString() << ']';
}
@@ -3574,14 +3616,14 @@ void CGObjCMac::FinishModule() {
Asm += '\n';
llvm::raw_svector_ostream OS(Asm);
- for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
- e = LazySymbols.end(); I != e; ++I)
- OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(),
e = DefinedSymbols.end(); I != e; ++I)
OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n"
<< "\t.globl .objc_class_name_" << (*I)->getName() << "\n";
-
+ for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(),
+ e = LazySymbols.end(); I != e; ++I)
+ OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n";
+
CGM.getModule().setModuleInlineAsm(OS.str());
}
}
@@ -3627,7 +3669,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// id self;
// Class cls;
// }
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
@@ -4088,7 +4131,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
// };
// First the clang type for struct _message_ref_t
- RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0,
+ RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct,
+ Ctx.getTranslationUnitDecl(),
SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0,
@@ -4162,7 +4206,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(const
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
- GV->setAlignment(8);
+ GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
@@ -4203,28 +4247,7 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
"\01L_OBJC_LABEL_NONLAZY_CATEGORY_$",
"__DATA, __objc_nlcatlist, regular, no_dead_strip");
- // static int L_OBJC_IMAGE_INFO[2] = { 0, flags };
- // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0
- std::vector<llvm::Constant*> Values(2);
- Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0);
- unsigned int flags = 0;
- // FIXME: Fix and continue?
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC)
- flags |= eImageInfo_GarbageCollected;
- if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly)
- flags |= eImageInfo_GCOnly;
- Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
- llvm::Constant* Init = llvm::ConstantArray::get(
- llvm::ArrayType::get(ObjCTypes.IntTy, 2),
- Values);
- llvm::GlobalVariable *IMGV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
- Init,
- "\01L_OBJC_IMAGE_INFO");
- IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip");
- IMGV->setConstant(true);
- CGM.AddUsedGlobal(IMGV);
+ EmitImageInfo();
}
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
@@ -4233,9 +4256,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
- if (CGM.getCodeGenOpts().ObjCLegacyDispatch)
+ switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
+ default:
+ assert(0 && "Invalid dispatch method!");
+ case CodeGenOptions::Legacy:
return true;
+ case CodeGenOptions::NonLegacy:
+ return false;
+ case CodeGenOptions::Mixed:
+ break;
+ }
+ // If so, see whether this selector is in the white-list of things which must
+ // use the new dispatch convention. We lazily build a dense set for this.
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
@@ -4265,6 +4298,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
NonLegacyDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
}
+
return (NonLegacyDispatchMethods.count(Sel) == 0);
}
@@ -4369,7 +4403,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
@@ -4405,7 +4439,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
@@ -4467,6 +4501,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
+ if (ID->getNumIvarInitializers())
+ flags |= eClassFlags_ABI2_HasCXXStructors;
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
flags |= CLS_ROOT;
@@ -4501,6 +4537,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
flags = CLS;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
+ if (ID->getNumIvarInitializers())
+ flags |= eClassFlags_ABI2_HasCXXStructors;
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
flags |= CLS_EXCEPTION;
@@ -4655,7 +4693,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Init,
ExtCatName);
GCATV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
@@ -4715,7 +4753,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name,
Init,
Name);
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
@@ -4750,7 +4788,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -4837,7 +4875,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Init,
Prefix + OID->getName());
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
@@ -4956,7 +4994,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -4969,7 +5007,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
@@ -5025,7 +5063,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name,
Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(Init->getType()));
+ CGM.getTargetData().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
@@ -5184,8 +5222,8 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return LegacyDispatchedSelector(Sel)
? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel),
@@ -5222,7 +5260,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -5245,7 +5283,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -5271,7 +5309,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getPrefTypeAlignment(
+ CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
@@ -5532,45 +5570,44 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr());
// Construct the lists of (type, catch body) to handle.
- llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
+ llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers;
bool HasCatchAll = false;
if (isTry) {
- if (const ObjCAtCatchStmt* CatchStmt =
- cast<ObjCAtTryStmt>(S).getCatchStmts()) {
- for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
- const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
- Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
-
- // catch(...) always matches.
- if (!CatchDecl) {
- // Use i8* null here to signal this is a catch all, not a cleanup.
- llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
- SelectorArgs.push_back(Null);
- HasCatchAll = true;
- break;
- }
+ const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
+ for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+ const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
+ const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+ Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
- if (CatchDecl->getType()->isObjCIdType() ||
- CatchDecl->getType()->isObjCQualifiedIdType()) {
- llvm::Value *IDEHType =
- CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
- if (!IDEHType)
- IDEHType =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
- false,
- llvm::GlobalValue::ExternalLinkage,
- 0, "OBJC_EHTYPE_id");
- SelectorArgs.push_back(IDEHType);
- } else {
- // All other types should be Objective-C interface pointer types.
- const ObjCObjectPointerType *PT =
- CatchDecl->getType()->getAs<ObjCObjectPointerType>();
- assert(PT && "Invalid @catch type.");
- const ObjCInterfaceType *IT = PT->getInterfaceType();
- assert(IT && "Invalid @catch type.");
- llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
- SelectorArgs.push_back(EHType);
- }
+ // catch(...) always matches.
+ if (!CatchDecl) {
+ // Use i8* null here to signal this is a catch all, not a cleanup.
+ llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+ SelectorArgs.push_back(Null);
+ HasCatchAll = true;
+ break;
+ }
+
+ if (CatchDecl->getType()->isObjCIdType() ||
+ CatchDecl->getType()->isObjCQualifiedIdType()) {
+ llvm::Value *IDEHType =
+ CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
+ if (!IDEHType)
+ IDEHType =
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
+ false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "OBJC_EHTYPE_id");
+ SelectorArgs.push_back(IDEHType);
+ } else {
+ // All other types should be Objective-C interface pointer types.
+ const ObjCObjectPointerType *PT =
+ CatchDecl->getType()->getAs<ObjCObjectPointerType>();
+ assert(PT && "Invalid @catch type.");
+ const ObjCInterfaceType *IT = PT->getInterfaceType();
+ assert(IT && "Invalid @catch type.");
+ llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
+ SelectorArgs.push_back(EHType);
}
}
}
@@ -5589,7 +5626,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
SelectorArgs.begin(), SelectorArgs.end(),
"selector");
for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
- const ParmVarDecl *CatchParam = Handlers[i].first;
+ const VarDecl *CatchParam = Handlers[i].first;
const Stmt *CatchBody = Handlers[i].second;
llvm::BasicBlock *Next = 0;
@@ -5612,14 +5649,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
if (CatchBody) {
llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end");
- llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler");
// Cleanups must call objc_end_catch.
- //
- // FIXME: It seems incorrect for objc_begin_catch to be inside this
- // context, but this matches gcc.
CGF.PushCleanupBlock(MatchEnd);
- CGF.setInvokeDest(MatchHandler);
llvm::Value *ExcObject =
CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc);
@@ -5636,25 +5668,37 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam));
}
+ // Exceptions inside the catch block must be rethrown. We set a special
+ // purpose invoke destination for this which just collects the thrown
+ // exception and overwrites the object in RethrowPtr, branches through the
+ // match.end to make sure we call objc_end_catch, before branching to the
+ // rethrow handler.
+ llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler");
+ CGF.setInvokeDest(MatchHandler);
CGF.ObjCEHValueStack.push_back(ExcObject);
CGF.EmitStmt(CatchBody);
CGF.ObjCEHValueStack.pop_back();
+ CGF.setInvokeDest(0);
CGF.EmitBranchThroughCleanup(FinallyEnd);
- CGF.EmitBlock(MatchHandler);
-
- llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
- // We are required to emit this call to satisfy LLVM, even
- // though we don't use the result.
- llvm::SmallVector<llvm::Value*, 8> Args;
- Args.push_back(Exc);
- Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
- CGF.Builder.CreateStore(Exc, RethrowPtr);
- CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ // Don't emit the extra match handler if there we no unprotected calls in
+ // the catch block.
+ if (MatchHandler->use_empty()) {
+ delete MatchHandler;
+ } else {
+ CGF.EmitBlock(MatchHandler);
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ CGF.Builder.CreateCall3(llvm_eh_selector,
+ Exc, ObjCTypes.getEHPersonalityPtr(),
+ llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0),
+ "unused_eh_selector");
+ CGF.Builder.CreateStore(Exc, RethrowPtr);
+ CGF.EmitBranchThroughCleanup(FinallyRethrow);
+ }
CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
@@ -5666,8 +5710,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.createBasicBlock("match.end.handler");
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(),
- Cont, MatchEndHandler,
- Args.begin(), Args.begin());
+ Cont, MatchEndHandler);
CGF.EmitBlock(Cont);
if (Info.SwitchBlock)
@@ -5676,15 +5719,14 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.EmitBlock(Info.EndBlock);
CGF.EmitBlock(MatchEndHandler);
- Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
- Args.clear();
- Args.push_back(Exc);
- Args.push_back(ObjCTypes.getEHPersonalityPtr());
- Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
- 0));
- CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ CGF.Builder.CreateCall3(llvm_eh_selector,
+ Exc, ObjCTypes.getEHPersonalityPtr(),
+ llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0),
+ "unused_eh_selector");
CGF.Builder.CreateStore(Exc, RethrowPtr);
CGF.EmitBranchThroughCleanup(FinallyRethrow);
@@ -5723,9 +5765,19 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Branch around the rethrow code.
CGF.EmitBranch(FinallyEnd);
+ // Generate the rethrow code, taking care to use an invoke if we are in a
+ // nested exception scope.
CGF.EmitBlock(FinallyRethrow);
- CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
- CGF.Builder.CreateLoad(RethrowPtr));
+ if (PrevLandingPad) {
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ Cont, PrevLandingPad,
+ CGF.Builder.CreateLoad(RethrowPtr));
+ CGF.EmitBlock(Cont);
+ } else {
+ CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(),
+ CGF.Builder.CreateLoad(RethrowPtr));
+ }
CGF.Builder.CreateUnreachable();
CGF.EmitBlock(FinallyEnd);
@@ -5816,7 +5868,8 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Entry->setAlignment(8);
+ Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
+ ObjCTypes.EHTypeTy));
if (ForDefinition) {
Entry->setSection("__DATA,__objc_const");
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index e478394fb1aa..654ad0a4bfae 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -122,8 +122,8 @@ public:
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
- bool IsClassMessage,
const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class = 0,
const ObjCMethodDecl *Method = 0) = 0;
/// Generate an Objective-C message send operation to the super
@@ -167,6 +167,9 @@ public:
/// Return the runtime function for setting properties.
virtual llvm::Constant *GetPropertySetFunction() = 0;
+ // API for atomic copying of qualified aggregates in setter/getter.
+ virtual llvm::Constant *GetCopyStructFunction() = 0;
+
/// GetClass - Return a reference to the class for the given
/// interface decl.
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 1caec97fc367..aec1c4554a35 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -31,8 +31,8 @@ class RTTIBuilder {
/// descriptor of the given type.
llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
- /// BuildVtablePointer - Build the vtable pointer for the given type.
- void BuildVtablePointer(const Type *Ty);
+ /// BuildVTablePointer - Build the vtable pointer for the given type.
+ void BuildVTablePointer(const Type *Ty);
/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
/// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
@@ -148,6 +148,9 @@ public:
};
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ ///
+ /// \param Force - true to force the creation of this RTTI value
+ /// \param ForEH - true if this is for exception handling
llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -242,9 +245,10 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
}
/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the typ
+/// the given type exists somewhere else, and that we should not emit the type
/// information in this translation unit.
-bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
+static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context,
+ QualType Ty) {
// Type info for builtin types is defined in the standard library.
if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
return TypeInfoIsInStandardLibrary(BuiltinTy);
@@ -254,6 +258,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) {
if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
return TypeInfoIsInStandardLibrary(PointerTy);
+ // If RTTI is disabled, don't consider key functions.
+ if (!Context.getLangOptions().RTTI) return false;
+
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!RD->hasDefinition())
@@ -337,7 +344,7 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (RD->isDynamicClass())
- return CodeGenModule::getVtableLinkage(RD);
+ return CodeGenModule::getVTableLinkage(RD);
}
return llvm::GlobalValue::WeakODRLinkage;
@@ -375,8 +382,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
return true;
}
-void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
- const char *VtableName;
+void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
+ const char *VTableName;
switch (Ty->getTypeClass()) {
default: assert(0 && "Unhandled type!");
@@ -386,24 +393,24 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
case Type::Vector:
case Type::ExtVector:
// abi::__fundamental_type_info.
- VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
break;
case Type::ConstantArray:
case Type::IncompleteArray:
// abi::__array_type_info.
- VtableName = "_ZTVN10__cxxabiv117__array_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
break;
case Type::FunctionNoProto:
case Type::FunctionProto:
// abi::__function_type_info.
- VtableName = "_ZTVN10__cxxabiv120__function_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
break;
case Type::Enum:
// abi::__enum_type_info.
- VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
break;
case Type::Record: {
@@ -412,13 +419,13 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
if (!RD->hasDefinition() || !RD->getNumBases()) {
// abi::__class_type_info.
- VtableName = "_ZTVN10__cxxabiv117__class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv117__class_type_infoE";
} else if (CanUseSingleInheritance(RD)) {
// abi::__si_class_type_info.
- VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE";
} else {
// abi::__vmi_class_type_info.
- VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
}
break;
@@ -426,30 +433,31 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
case Type::Pointer:
// abi::__pointer_type_info.
- VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
break;
case Type::MemberPointer:
// abi::__pointer_to_member_type_info.
- VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
+ VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;
}
- llvm::Constant *Vtable =
- CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy);
+ llvm::Constant *VTable =
+ CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy);
const llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
// The vtable address point is 2.
llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1);
- Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy);
+ VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1);
+ VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy);
- Fields.push_back(Vtable);
+ Fields.push_back(VTable);
}
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty,
+ bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -463,13 +471,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
// Check if there is already an external RTTI descriptor for this type.
- if (!Force && ShouldUseExternalRTTIDescriptor(Ty))
+ if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty))
return GetAddrOfExternalRTTIDescriptor(Ty);
llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
// Add the vtable pointer.
- BuildVtablePointer(cast<Type>(Ty));
+ BuildVTablePointer(cast<Type>(Ty));
// And the name.
Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage));
@@ -782,42 +790,17 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
}
-llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
- if (!getContext().getLangOptions().RTTI) {
+llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
+ bool ForEH) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!ForEH && !getContext().getLangOptions().RTTI) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
return llvm::Constant::getNullValue(Int8PtrTy);
}
-
- return RTTIBuilder(*this).BuildTypeInfo(Ty);
-}
-// Try to find the magic class __cxxabiv1::__fundamental_type_info. If
-// exists and has a destructor, we will emit the typeinfo for the fundamental
-// types. This is the same behaviour as GCC.
-static CXXRecordDecl *FindMagicClass(ASTContext &AC) {
- const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1");
- DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII);
- TranslationUnitDecl *TUD = AC.getTranslationUnitDecl();
- DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN);
- if (NamespaceLookup.first == NamespaceLookup.second)
- return NULL;
- const NamespaceDecl *Namespace =
- dyn_cast<NamespaceDecl>(*NamespaceLookup.first);
- if (!Namespace)
- return NULL;
-
- const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info");
- DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII);
- DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN);
- if (ClassLookup.first == ClassLookup.second)
- return NULL;
- CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(*ClassLookup.first);
-
- if (Class->hasDefinition() && Class->isDynamicClass() &&
- Class->getDestructor(AC))
- return Class;
-
- return NULL;
+ return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
@@ -829,12 +812,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
}
void CodeGenModule::EmitFundamentalRTTIDescriptors() {
- CXXRecordDecl *RD = FindMagicClass(getContext());
- if (!RD)
- return;
-
- getVTables().GenerateClassData(getVtableLinkage(RD), RD);
-
QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty,
Context.Char16Ty, Context.UnsignedLongLongTy,
Context.LongLongTy, Context.WCharTy,
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index fd1775ea5e6c..9f966fb7ae46 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -13,22 +13,137 @@
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Decl.h"
namespace llvm {
+ class raw_ostream;
class Type;
}
namespace clang {
namespace CodeGen {
+/// \brief Helper object for describing how to generate the code for access to a
+/// bit-field.
+///
+/// This structure is intended to describe the "policy" of how the bit-field
+/// should be accessed, which may be target, language, or ABI dependent.
class CGBitFieldInfo {
public:
- CGBitFieldInfo(unsigned FieldNo, unsigned Start, unsigned Size,
- bool IsSigned)
- : FieldNo(FieldNo), Start(Start), Size(Size), IsSigned(IsSigned) {}
+ /// Descriptor for a single component of a bit-field access. The entire
+ /// bit-field is constituted of a bitwise OR of all of the individual
+ /// components.
+ ///
+ /// Each component describes an accessed value, which is how the component
+ /// should be transferred to/from memory, and a target placement, which is how
+ /// that component fits into the constituted bit-field. The pseudo-IR for a
+ /// load is:
+ ///
+ /// %0 = gep %base, 0, FieldIndex
+ /// %1 = gep (i8*) %0, FieldByteOffset
+ /// %2 = (i(AccessWidth) *) %1
+ /// %3 = load %2, align AccessAlignment
+ /// %4 = shr %3, FieldBitStart
+ ///
+ /// and the composed bit-field is formed as the boolean OR of all accesses,
+ /// masked to TargetBitWidth bits and shifted to TargetBitOffset.
+ struct AccessInfo {
+ /// Offset of the field to load in the LLVM structure, if any.
+ unsigned FieldIndex;
+
+ /// Byte offset from the field address, if any. This should generally be
+ /// unused as the cleanest IR comes from having a well-constructed LLVM type
+ /// with proper GEP instructions, but sometimes its use is required, for
+ /// example if an access is intended to straddle an LLVM field boundary.
+ unsigned FieldByteOffset;
+
+ /// Bit offset in the accessed value to use. The width is implied by \see
+ /// TargetBitWidth.
+ unsigned FieldBitStart;
+
+ /// Bit width of the memory access to perform.
+ unsigned AccessWidth;
+
+ /// The alignment of the memory access, or 0 if the default alignment should
+ /// be used.
+ //
+ // FIXME: Remove use of 0 to encode default, instead have IRgen do the right
+ // thing when it generates the code, if avoiding align directives is
+ // desired.
+ unsigned AccessAlignment;
+
+ /// Offset for the target value.
+ unsigned TargetBitOffset;
+
+ /// Number of bits in the access that are destined for the bit-field.
+ unsigned TargetBitWidth;
+ };
- unsigned FieldNo;
- unsigned Start;
+private:
+ /// The components to use to access the bit-field. We may need up to three
+ /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte
+ /// accesses).
+ //
+ // FIXME: De-hardcode this, just allocate following the struct.
+ AccessInfo Components[3];
+
+ /// The total size of the bit-field, in bits.
unsigned Size;
+
+ /// The number of access components to use.
+ unsigned NumComponents;
+
+ /// Whether the bit-field is signed.
bool IsSigned : 1;
+
+public:
+ CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components,
+ bool IsSigned) : Size(Size), NumComponents(NumComponents),
+ IsSigned(IsSigned) {
+ assert(NumComponents <= 3 && "invalid number of components!");
+ for (unsigned i = 0; i != NumComponents; ++i)
+ Components[i] = _Components[i];
+
+ // Check some invariants.
+ unsigned AccessedSize = 0;
+ for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
+ const AccessInfo &AI = getComponent(i);
+ AccessedSize += AI.TargetBitWidth;
+
+ // We shouldn't try to load 0 bits.
+ assert(AI.TargetBitWidth > 0);
+
+ // We can't load more bits than we accessed.
+ assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth);
+
+ // We shouldn't put any bits outside the result size.
+ assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size);
+ }
+
+ // Check that the total number of target bits matches the total bit-field
+ // size.
+ assert(AccessedSize == Size && "Total size does not match accessed size!");
+ }
+
+public:
+ /// \brief Check whether this bit-field access is (i.e., should be sign
+ /// extended on loads).
+ bool isSigned() const { return IsSigned; }
+
+ /// \brief Get the size of the bit-field, in bits.
+ unsigned getSize() const { return Size; }
+
+ /// @name Component Access
+ /// @{
+
+ unsigned getNumComponents() const { return NumComponents; }
+
+ const AccessInfo &getComponent(unsigned Index) const {
+ assert(Index < getNumComponents() && "Invalid access!");
+ return Components[Index];
+ }
+
+ /// @}
+
+ void print(llvm::raw_ostream &OS) const;
+ void dump() const;
};
/// CGRecordLayout - This class handles struct and union layout info while
@@ -71,15 +186,15 @@ public:
return ContainsPointerToDataMember;
}
- /// \brief Return the BitFieldInfo that corresponds to the field FD.
+ /// \brief Return llvm::StructType element number that corresponds to the
+ /// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
assert(!FD->isBitField() && "Invalid call for bit-field decl!");
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
- /// \brief Return llvm::StructType element number that corresponds to the
- /// field FD.
+ /// \brief Return the BitFieldInfo that corresponds to the field FD.
const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
assert(FD->isBitField() && "Invalid call for non bit-field decl!");
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
@@ -87,6 +202,9 @@ public:
assert(it != BitFields.end() && "Unable to find bitfield info");
return it->second;
}
+
+ void print(llvm::raw_ostream &OS) const;
+ void dump() const;
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 4b9ec66e178c..6302cf8d1fc0 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -18,8 +18,10 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "CodeGenTypes.h"
-#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
+#include "llvm/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
@@ -67,6 +69,11 @@ private:
/// NextFieldOffsetInBytes - Holds the next field offset in bytes.
uint64_t NextFieldOffsetInBytes;
+ /// LayoutUnionField - Will layout a field in an union and return the type
+ /// that the field will have.
+ const llvm::Type *LayoutUnionField(const FieldDecl *Field,
+ const ASTRecordLayout &Layout);
+
/// LayoutUnion - Will layout a union RecordDecl.
void LayoutUnion(const RecordDecl *D);
@@ -87,10 +94,6 @@ private:
/// AppendField - Appends a field with the given offset and type.
void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
- /// AppendPadding - Appends enough padding bytes so that the total struct
- /// size matches the alignment of the passed in type.
- void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
-
/// AppendPadding - Appends enough padding bytes so that the total
/// struct size is a multiple of the field alignment.
void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
@@ -103,7 +106,6 @@ private:
void AppendTailPadding(uint64_t RecordSize);
unsigned getTypeAlignment(const llvm::Type *Ty) const;
- uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
/// CheckForPointerToDataMember - Check if the given type contains a pointer
/// to data member.
@@ -145,6 +147,104 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
LayoutFields(D);
}
+static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types,
+ const FieldDecl *FD,
+ uint64_t FieldOffset,
+ uint64_t FieldSize) {
+ const RecordDecl *RD = FD->getParent();
+ const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD);
+ uint64_t ContainingTypeSizeInBits = RL.getSize();
+ unsigned ContainingTypeAlign = RL.getAlignment();
+
+ const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType());
+ uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty);
+ uint64_t TypeSizeInBits = TypeSizeInBytes * 8;
+
+ bool IsSigned = FD->getType()->isSignedIntegerType();
+
+ if (FieldSize > TypeSizeInBits) {
+ // We have a wide bit-field. The extra bits are only used for padding, so
+ // if we have a bitfield of type T, with size N:
+ //
+ // T t : N;
+ //
+ // We can just assume that it's:
+ //
+ // T t : sizeof(T);
+ //
+ FieldSize = TypeSizeInBits;
+ }
+
+ // Compute the access components. The policy we use is to start by attempting
+ // to access using the width of the bit-field type itself and to always access
+ // at aligned indices of that type. If such an access would fail because it
+ // extends past the bound of the type, then we reduce size to the next smaller
+ // power of two and retry. The current algorithm assumes pow2 sized types,
+ // although this is easy to fix.
+ //
+ // FIXME: This algorithm is wrong on big-endian systems, I think.
+ assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!");
+ CGBitFieldInfo::AccessInfo Components[3];
+ unsigned NumComponents = 0;
+ unsigned AccessedTargetBits = 0; // The tumber of target bits accessed.
+ unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
+
+ // Round down from the field offset to find the first access position that is
+ // at an aligned offset of the initial access type.
+ uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
+
+ // Adjust initial access size to fit within record.
+ while (AccessWidth > 8 &&
+ AccessStart + AccessWidth > ContainingTypeSizeInBits) {
+ AccessWidth >>= 1;
+ AccessStart = FieldOffset - (FieldOffset % AccessWidth);
+ }
+
+ while (AccessedTargetBits < FieldSize) {
+ // Check that we can access using a type of this size, without reading off
+ // the end of the structure. This can occur with packed structures and
+ // -fno-bitfield-type-align, for example.
+ if (AccessStart + AccessWidth > ContainingTypeSizeInBits) {
+ // If so, reduce access size to the next smaller power-of-two and retry.
+ AccessWidth >>= 1;
+ assert(AccessWidth >= 8 && "Cannot access under byte size!");
+ continue;
+ }
+
+ // Otherwise, add an access component.
+
+ // First, compute the bits inside this access which are part of the
+ // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the
+ // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits
+ // in the target that we are reading.
+ assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!");
+ assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!");
+ uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset);
+ uint64_t AccessBitsInFieldSize =
+ std::min(AccessWidth + AccessStart,
+ FieldOffset + FieldSize) - AccessBitsInFieldStart;
+
+ assert(NumComponents < 3 && "Unexpected number of components!");
+ CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++];
+ AI.FieldIndex = 0;
+ // FIXME: We still follow the old access pattern of only using the field
+ // byte offset. We should switch this once we fix the struct layout to be
+ // pretty.
+ AI.FieldByteOffset = AccessStart / 8;
+ AI.FieldBitStart = AccessBitsInFieldStart - AccessStart;
+ AI.AccessWidth = AccessWidth;
+ AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8;
+ AI.TargetBitOffset = AccessedTargetBits;
+ AI.TargetBitWidth = AccessBitsInFieldSize;
+
+ AccessStart += AccessWidth;
+ AccessedTargetBits += AI.TargetBitWidth;
+ }
+
+ assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!");
+ return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned);
+}
+
void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
uint64_t FieldOffset) {
uint64_t FieldSize =
@@ -175,14 +275,9 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
assert(NumBytesToAppend && "No bytes to append!");
}
- const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
- uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8;
-
- bool IsSigned = D->getType()->isSignedIntegerType();
- LLVMBitFields.push_back(LLVMBitFieldInfo(
- D, CGBitFieldInfo(FieldOffset / TypeSizeInBits,
- FieldOffset % TypeSizeInBits,
- FieldSize, IsSigned)));
+ // Add the bit field info.
+ LLVMBitFields.push_back(
+ LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize)));
AppendBytes(NumBytesToAppend);
@@ -254,6 +349,35 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
+const llvm::Type *
+CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
+ const ASTRecordLayout &Layout) {
+ if (Field->isBitField()) {
+ uint64_t FieldSize =
+ Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
+
+ // Ignore zero sized bit fields.
+ if (FieldSize == 0)
+ return 0;
+
+ const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ unsigned NumBytesToAppend =
+ llvm::RoundUpToAlignment(FieldSize, 8) / 8;
+
+ if (NumBytesToAppend > 1)
+ FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
+
+ // Add the bit field info.
+ LLVMBitFields.push_back(
+ LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize)));
+ return FieldTy;
+ }
+
+ // This is a regular union field.
+ LLVMFields.push_back(LLVMFieldInfo(Field, 0));
+ return Types.ConvertTypeForMemRecursive(Field->getType());
+}
+
void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
@@ -270,28 +394,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
assert(Layout.getFieldOffset(FieldNo) == 0 &&
"Union field offset did not start at the beginning of record!");
+ const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout);
- if (Field->isBitField()) {
- uint64_t FieldSize =
- Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
-
- // Ignore zero sized bit fields.
- if (FieldSize == 0)
- continue;
-
- // Add the bit field info.
- bool IsSigned = Field->getType()->isSignedIntegerType();
- LLVMBitFields.push_back(LLVMBitFieldInfo(
- *Field, CGBitFieldInfo(0, 0, FieldSize,
- IsSigned)));
- } else {
- LLVMFields.push_back(LLVMFieldInfo(*Field, 0));
- }
+ if (!FieldTy)
+ continue;
HasOnlyZeroSizedBitFields = false;
- const llvm::Type *FieldTy =
- Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy);
@@ -334,7 +443,7 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
llvm::Type::getInt8PtrTy(Types.getLLVMContext());
assert(NextFieldOffsetInBytes == 0 &&
- "Vtable pointer must come first!");
+ "VTable pointer must come first!");
AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
}
}
@@ -388,7 +497,7 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct,
getTypeAlignment(FieldTy));
- uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy);
+ uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy);
FieldTypes.push_back(FieldTy);
@@ -396,12 +505,6 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
BitsAvailableInLastField = 0;
}
-void
-CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
- const llvm::Type *FieldTy) {
- AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy));
-}
-
void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
unsigned FieldAlignment) {
assert(NextFieldOffsetInBytes <= FieldOffsetInBytes &&
@@ -439,10 +542,6 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
return Types.getTargetData().getABITypeAlignment(Ty);
}
-uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
- return Types.getTargetData().getTypeAllocSize(Ty);
-}
-
void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
// This record already contains a member pointer.
if (ContainsPointerToDataMember)
@@ -481,9 +580,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),
Builder.FieldTypes,
Builder.Packed);
- assert(getContext().getASTRecordLayout(D).getSize() / 8 ==
- getTargetData().getTypeAllocSize(Ty) &&
- "Type size mismatch!");
CGRecordLayout *RL =
new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
@@ -496,5 +592,121 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i)
RL->BitFields.insert(Builder.LLVMBitFields[i]);
+ // Dump the layout, if requested.
+ if (getContext().getLangOptions().DumpRecordLayouts) {
+ llvm::errs() << "\n*** Dumping IRgen Record Layout\n";
+ llvm::errs() << "Record: ";
+ D->dump();
+ llvm::errs() << "\nLayout: ";
+ RL->dump();
+ }
+
+#ifndef NDEBUG
+ // Verify that the computed LLVM struct size matches the AST layout size.
+ uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize();
+ assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) &&
+ "Type size mismatch!");
+
+ // Verify that the LLVM and AST field offsets agree.
+ const llvm::StructType *ST =
+ dyn_cast<llvm::StructType>(RL->getLLVMType());
+ const llvm::StructLayout *SL = getTargetData().getStructLayout(ST);
+
+ const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D);
+ RecordDecl::field_iterator it = D->field_begin();
+ for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) {
+ const FieldDecl *FD = *it;
+
+ // For non-bit-fields, just check that the LLVM struct offset matches the
+ // AST offset.
+ if (!FD->isBitField()) {
+ unsigned FieldNo = RL->getLLVMFieldNo(FD);
+ assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) &&
+ "Invalid field offset!");
+ continue;
+ }
+
+ // Ignore unnamed bit-fields.
+ if (!FD->getDeclName())
+ continue;
+
+ const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
+ for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
+ const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
+
+ // Verify that every component access is within the structure.
+ uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
+ uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8;
+ assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
+ "Invalid bit-field access (out of range)!");
+ }
+ }
+#endif
+
return RL;
}
+
+void CGRecordLayout::print(llvm::raw_ostream &OS) const {
+ OS << "<CGRecordLayout\n";
+ OS << " LLVMType:" << *LLVMType << "\n";
+ OS << " ContainsPointerToDataMember:" << ContainsPointerToDataMember << "\n";
+ OS << " BitFields:[\n";
+
+ // Print bit-field infos in declaration order.
+ std::vector<std::pair<unsigned, const CGBitFieldInfo*> > BFIs;
+ for (llvm::DenseMap<const FieldDecl*, CGBitFieldInfo>::const_iterator
+ it = BitFields.begin(), ie = BitFields.end();
+ it != ie; ++it) {
+ const RecordDecl *RD = it->first->getParent();
+ unsigned Index = 0;
+ for (RecordDecl::field_iterator
+ it2 = RD->field_begin(); *it2 != it->first; ++it2)
+ ++Index;
+ BFIs.push_back(std::make_pair(Index, &it->second));
+ }
+ llvm::array_pod_sort(BFIs.begin(), BFIs.end());
+ for (unsigned i = 0, e = BFIs.size(); i != e; ++i) {
+ OS.indent(4);
+ BFIs[i].second->print(OS);
+ OS << "\n";
+ }
+
+ OS << "]>\n";
+}
+
+void CGRecordLayout::dump() const {
+ print(llvm::errs());
+}
+
+void CGBitFieldInfo::print(llvm::raw_ostream &OS) const {
+ OS << "<CGBitFieldInfo";
+ OS << " Size:" << Size;
+ OS << " IsSigned:" << IsSigned << "\n";
+
+ OS.indent(4 + strlen("<CGBitFieldInfo"));
+ OS << " NumComponents:" << getNumComponents();
+ OS << " Components: [";
+ if (getNumComponents()) {
+ OS << "\n";
+ for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
+ const AccessInfo &AI = getComponent(i);
+ OS.indent(8);
+ OS << "<AccessInfo"
+ << " FieldIndex:" << AI.FieldIndex
+ << " FieldByteOffset:" << AI.FieldByteOffset
+ << " FieldBitStart:" << AI.FieldBitStart
+ << " AccessWidth:" << AI.AccessWidth << "\n";
+ OS.indent(8 + strlen("<AccessInfo"));
+ OS << " AccessAlignment:" << AI.AccessAlignment
+ << " TargetBitOffset:" << AI.TargetBitOffset
+ << " TargetBitWidth:" << AI.TargetBitWidth
+ << ">\n";
+ }
+ OS.indent(4);
+ }
+ OS << "]>";
+}
+
+void CGBitFieldInfo::dump() const {
+ print(llvm::errs());
+}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index ae2f791719d3..a914c80da2ac 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -160,7 +160,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
EmitStmt(*I);
if (DI) {
- DI->setLocation(S.getLBracLoc());
+ DI->setLocation(S.getRBracLoc());
DI->EmitRegionEnd(CurFn, Builder);
}
@@ -205,6 +205,8 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) {
}
void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
+
// Fall out of the current block (if necessary).
EmitBranch(BB);
@@ -225,7 +227,12 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
}
}
- CurFn->getBasicBlockList().push_back(BB);
+ // Place the block after the current block, if possible, or else at
+ // the end of the function.
+ if (CurBB && CurBB->getParent())
+ CurFn->getBasicBlockList().insertAfter(CurBB, BB);
+ else
+ CurFn->getBasicBlockList().push_back(BB);
Builder.SetInsertPoint(BB);
}
@@ -974,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
unsigned InputNo;
for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) {
TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo];
- if (Input.hasTiedOperand() &&
- Input.getTiedOperand() == i)
+ if (Input.hasTiedOperand() && Input.getTiedOperand() == i)
break;
}
assert(InputNo != S.getNumInputs() && "Didn't find matching input!");
QualType InputTy = S.getInputExpr(InputNo)->getType();
- QualType OutputTy = OutExpr->getType();
+ QualType OutputType = OutExpr->getType();
uint64_t InputSize = getContext().getTypeSize(InputTy);
- if (getContext().getTypeSize(OutputTy) < InputSize) {
- // Form the asm to return the value as a larger integer type.
- ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize);
+ if (getContext().getTypeSize(OutputType) < InputSize) {
+ // Form the asm to return the value as a larger integer or fp type.
+ ResultRegTypes.back() = ConvertType(InputTy);
}
}
} else {
@@ -1036,17 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// that is usually cheaper, but LLVM IR should really get an anyext someday.
if (Info.hasTiedOperand()) {
unsigned Output = Info.getTiedOperand();
- QualType OutputTy = S.getOutputExpr(Output)->getType();
+ QualType OutputType = S.getOutputExpr(Output)->getType();
QualType InputTy = InputExpr->getType();
- if (getContext().getTypeSize(OutputTy) >
+ if (getContext().getTypeSize(OutputType) >
getContext().getTypeSize(InputTy)) {
// Use ptrtoint as appropriate so that we can do our extension.
if (isa<llvm::PointerType>(Arg->getType()))
Arg = Builder.CreatePtrToInt(Arg,
- llvm::IntegerType::get(VMContext, LLVMPointerWidth));
- unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy);
- Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize));
+ llvm::IntegerType::get(VMContext, LLVMPointerWidth));
+ const llvm::Type *OutputTy = ConvertType(OutputType);
+ if (isa<llvm::IntegerType>(OutputTy))
+ Arg = Builder.CreateZExt(Arg, OutputTy);
+ else
+ Arg = Builder.CreateFPExt(Arg, OutputTy);
}
}
@@ -1102,6 +1111,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end());
Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+ // Slap the source location of the inline asm into a !srcloc metadata on the
+ // call.
+ unsigned LocID = S.getAsmString()->getLocStart().getRawEncoding();
+ llvm::Value *LocIDC =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LocID);
+ Result->setMetadata("srcloc", llvm::MDNode::get(VMContext, &LocIDC, 1));
// Extract all of the register value results from the asm.
std::vector<llvm::Value*> RegResults;
@@ -1121,14 +1136,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
const llvm::Type *TruncTy = ResultTruncRegTypes[i];
- // Truncate the integer result to the right size, note that
- // ResultTruncRegTypes can be a pointer.
- uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
- Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize));
-
- if (Tmp->getType() != TruncTy) {
- assert(isa<llvm::PointerType>(TruncTy));
+
+ // Truncate the integer result to the right size, note that TruncTy can be
+ // a pointer.
+ if (TruncTy->isFloatingPointTy())
+ Tmp = Builder.CreateFPTrunc(Tmp, TruncTy);
+ else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) {
+ uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy);
+ Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext,
+ (unsigned)ResSize));
Tmp = Builder.CreateIntToPtr(Tmp, TruncTy);
+ } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) {
+ uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType());
+ Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(VMContext,
+ (unsigned)TmpSize));
+ Tmp = Builder.CreateTrunc(Tmp, TruncTy);
+ } else if (TruncTy->isIntegerTy()) {
+ Tmp = Builder.CreateTrunc(Tmp, TruncTy);
}
}
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index 6d38ab98dee6..a8f046759016 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
"Pushed the same temporary twice; AST is likely wrong");
llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor");
- llvm::Value *CondPtr = 0;
+ llvm::AllocaInst *CondPtr = 0;
// Check if temporaries need to be conditional. If so, we'll create a
// condition boolean, initialize it to 0 and
@@ -32,10 +32,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
// Initialize it to false. This initialization takes place right after
// the alloca insert point.
- llvm::StoreInst *SI =
- new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr);
- llvm::BasicBlock *Block = AllocaInsertPt->getParent();
- Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI);
+ InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext));
// Now set it to true.
Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr);
@@ -64,7 +61,8 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
}
EmitCXXDestructorCall(Info.Temporary->getDestructor(),
- Dtor_Complete, Info.ThisPtr);
+ Dtor_Complete, /*ForVirtualBase=*/false,
+ Info.ThisPtr);
if (CondEnd) {
// Reset the condition. to false.
@@ -107,7 +105,7 @@ void CodeGenFunction::PopCXXTemporary() {
}
EmitCXXDestructorCall(Info.Temporary->getDestructor(),
- Dtor_Complete, Info.ThisPtr);
+ Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr);
if (CondEnd) {
// Reset the condition. to false.
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 91d9f763bfe7..15e564810f83 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -43,7 +43,7 @@ class VTTBuilder {
/// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
/// class.
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+ llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
/// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
/// all subobjects of the most derived class.
@@ -116,8 +116,7 @@ public:
}
/// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
- const llvm::DenseMap<const CXXRecordDecl *, uint64_t> &
- getSubVTTIndicies() const {
+ const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
}
@@ -179,13 +178,14 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
// The vtable is a construction vtable, look in the construction vtable
// address points.
AddressPoint = AddressPoints.lookup(Base);
+ assert(AddressPoint != 0 && "Did not find ctor vtable address point!");
} else {
// Just get the address point for the regular vtable.
AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ assert(AddressPoint != 0 && "Did not find vtable address point!");
}
if (!AddressPoint) AddressPoint = 0;
- assert(AddressPoint != 0 && "Did not find an address point!");
llvm::Value *Idxs[] = {
llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0),
@@ -340,7 +340,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
if (!IsPrimaryVTT) {
// Remember the sub-VTT index.
- SubVTTIndicies[RD] = VTTComponents.size();
+ SubVTTIndicies[Base] = VTTComponents.size();
}
AddressPointsMapTy AddressPoints;
@@ -434,25 +434,25 @@ bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) {
}
uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *Base) {
- ClassPairTy ClassPair(RD, Base);
+ BaseSubobject Base) {
+ BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
- SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair);
+ SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
if (I != SubVTTIndicies.end())
return I->second;
VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I =
+ for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
// Insert all indices.
- ClassPairTy ClassPair(RD, I->first);
+ BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);
- SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
}
- I = SubVTTIndicies.find(ClassPair);
+ I = SubVTTIndicies.find(ClassSubobjectPair);
assert(I != SubVTTIndicies.end() && "Did not find index!");
return I->second;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVTables.cpp
index fc6d1a8e3709..159753aa359c 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -1,4 +1,4 @@
-//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===//
+//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -573,8 +573,8 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) {
}
}
-/// VtableComponent - Represents a single component in a vtable.
-class VtableComponent {
+/// VTableComponent - Represents a single component in a vtable.
+class VTableComponent {
public:
enum Kind {
CK_VCallOffset,
@@ -595,49 +595,49 @@ public:
CK_UnusedFunctionPointer
};
- static VtableComponent MakeVCallOffset(int64_t Offset) {
- return VtableComponent(CK_VCallOffset, Offset);
+ static VTableComponent MakeVCallOffset(int64_t Offset) {
+ return VTableComponent(CK_VCallOffset, Offset);
}
- static VtableComponent MakeVBaseOffset(int64_t Offset) {
- return VtableComponent(CK_VBaseOffset, Offset);
+ static VTableComponent MakeVBaseOffset(int64_t Offset) {
+ return VTableComponent(CK_VBaseOffset, Offset);
}
- static VtableComponent MakeOffsetToTop(int64_t Offset) {
- return VtableComponent(CK_OffsetToTop, 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 MakeRTTI(const CXXRecordDecl *RD) {
+ return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
}
- static VtableComponent MakeFunction(const CXXMethodDecl *MD) {
+ static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeFunction with destructors!");
- return VtableComponent(CK_FunctionPointer,
+ return VTableComponent(CK_FunctionPointer,
reinterpret_cast<uintptr_t>(MD));
}
- static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
- return VtableComponent(CK_CompleteDtorPointer,
+ 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,
+ static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
+ return VTableComponent(CK_DeletingDtorPointer,
reinterpret_cast<uintptr_t>(DD));
}
- static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
+ static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
assert(!isa<CXXDestructorDecl>(MD) &&
"Don't use MakeUnusedFunction with destructors!");
- return VtableComponent(CK_UnusedFunctionPointer,
+ return VTableComponent(CK_UnusedFunctionPointer,
reinterpret_cast<uintptr_t>(MD));
}
- static VtableComponent getFromOpaqueInteger(uint64_t I) {
- return VtableComponent(I);
+ static VTableComponent getFromOpaqueInteger(uint64_t I) {
+ return VTableComponent(I);
}
/// getKind - Get the kind of this vtable component.
@@ -689,7 +689,7 @@ public:
}
private:
- VtableComponent(Kind ComponentKind, int64_t Offset) {
+ VTableComponent(Kind ComponentKind, int64_t Offset) {
assert((ComponentKind == CK_VCallOffset ||
ComponentKind == CK_VBaseOffset ||
ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
@@ -698,7 +698,7 @@ private:
Value = ((Offset << 3) | ComponentKind);
}
- VtableComponent(Kind ComponentKind, uintptr_t Ptr) {
+ VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
assert((ComponentKind == CK_RTTI ||
ComponentKind == CK_FunctionPointer ||
ComponentKind == CK_CompleteDtorPointer ||
@@ -729,7 +729,7 @@ private:
return static_cast<uintptr_t>(Value & ~7ULL);
}
- explicit VtableComponent(uint64_t Value)
+ explicit VTableComponent(uint64_t Value)
: Value(Value) { }
/// The kind is stored in the lower 3 bits of the value. For offsets, we
@@ -855,8 +855,8 @@ private:
ASTContext &Context;
/// Components - vcall and vbase offset components
- typedef llvm::SmallVector<VtableComponent, 64> VtableComponentVectorTy;
- VtableComponentVectorTy Components;
+ typedef llvm::SmallVector<VTableComponent, 64> VTableComponentVectorTy;
+ VTableComponentVectorTy Components;
/// VisitedVirtualBases - Visited virtual bases.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
@@ -902,7 +902,7 @@ public:
}
/// Methods for iterating over the components.
- typedef VtableComponentVectorTy::const_reverse_iterator const_iterator;
+ typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
const_iterator components_begin() const { return Components.rbegin(); }
const_iterator components_end() const { return Components.rend(); }
@@ -982,30 +982,17 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
// Handle the primary base first.
- if (PrimaryBase) {
- uint64_t PrimaryBaseOffset;
-
+ // We only want to add vcall offsets if the base is non-virtual; a virtual
+ // primary base will have its vcall and vbase offsets emitted already.
+ if (PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) {
// Get the base offset of the primary base.
- if (Layout.getPrimaryBaseWasVirtual()) {
- assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
- "Primary vbase should have a zero offset!");
-
- const ASTRecordLayout &MostDerivedClassLayout =
- Context.getASTRecordLayout(MostDerivedClass);
-
- PrimaryBaseOffset =
- MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
- } else {
- assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
- "Primary base should have a zero offset!");
+ assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
- PrimaryBaseOffset = Base.getBaseOffset();
- }
-
- AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
+ AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
VBaseOffset);
}
-
+
// Add the vcall offsets.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
@@ -1034,7 +1021,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8;
}
- Components.push_back(VtableComponent::MakeVCallOffset(Offset));
+ Components.push_back(VTableComponent::MakeVCallOffset(Offset));
}
// And iterate over all non-virtual bases (ignoring the primary base).
@@ -1082,7 +1069,7 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
int64_t VBaseOffsetOffset = getCurrentOffsetOffset();
VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset));
- Components.push_back(VtableComponent::MakeVBaseOffset(Offset));
+ Components.push_back(VTableComponent::MakeVBaseOffset(Offset));
}
// Check the base class looking for more vbase offsets.
@@ -1090,8 +1077,8 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
}
}
-/// VtableBuilder - Class for building vtable layout information.
-class VtableBuilder {
+/// VTableBuilder - Class for building vtable layout information.
+class VTableBuilder {
public:
/// PrimaryBasesSetVectorTy - A set vector of direct and indirect
/// primary bases.
@@ -1140,7 +1127,7 @@ private:
VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
/// Components - The components of the vtable being built.
- llvm::SmallVector<VtableComponent, 64> Components;
+ llvm::SmallVector<VTableComponent, 64> Components;
/// AddressPoints - Address points for the vtable being built.
AddressPointsMapTy AddressPoints;
@@ -1155,17 +1142,17 @@ private:
/// method.
const uint64_t BaseOffsetInLayoutClass;
- /// VtableIndex - The index in the vtable that this method has.
+ /// VTableIndex - The index in the vtable that this method has.
/// (For destructors, this is the index of the complete destructor).
- const uint64_t VtableIndex;
+ const uint64_t VTableIndex;
MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass,
- uint64_t VtableIndex)
+ uint64_t VTableIndex)
: BaseOffset(BaseOffset),
BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
- VtableIndex(VtableIndex) { }
+ VTableIndex(VTableIndex) { }
- MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { }
+ MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { }
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -1174,11 +1161,11 @@ private:
/// currently building.
MethodInfoMapTy MethodInfoMap;
- typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy;
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
/// VTableThunks - The thunks by vtable index in the vtable currently being
/// built.
- VtableThunksMapTy VTableThunks;
+ VTableThunksMapTy VTableThunks;
typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
@@ -1253,22 +1240,29 @@ private:
uint64_t FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases);
- // LayoutVtable - Layout the vtable for the given base class, including its
+ // LayoutVTable - Layout the vtable for the given base class, including its
// secondary vtables and any vtables for virtual bases.
- void LayoutVtable();
+ void LayoutVTable();
- /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the
+ /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the
/// given base subobject, as well as all its secondary vtables.
- void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
- bool BaseIsVirtual,
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ ///
+ /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual
+ /// in the layout class.
+ void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
uint64_t OffsetInLayoutClass);
- /// LayoutSecondaryVtables - Layout the secondary vtables for the given base
+ /// LayoutSecondaryVTables - Layout the secondary vtables for the given base
/// subobject.
///
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
/// or a direct or indirect base of a virtual base.
- void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
uint64_t OffsetInLayoutClass);
/// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
@@ -1277,19 +1271,19 @@ private:
uint64_t OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases);
- /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the
+ /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the
/// given base (excluding any primary bases).
- void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
+ void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases);
- /// isBuildingConstructionVtable - Return whether this vtable builder is
+ /// isBuildingConstructionVTable - Return whether this vtable builder is
/// building a construction vtable.
- bool isBuildingConstructorVtable() const {
+ bool isBuildingConstructorVTable() const {
return MostDerivedClass != LayoutClass;
}
public:
- VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
+ VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass)
: VTables(VTables), MostDerivedClass(MostDerivedClass),
@@ -1298,7 +1292,7 @@ public:
LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
- LayoutVtable();
+ LayoutVTable();
}
ThunksMapTy::const_iterator thunks_begin() const {
@@ -1335,11 +1329,11 @@ public:
return AddressPoints.end();
}
- VtableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
return VTableThunks.begin();
}
- VtableThunksMapTy::const_iterator vtable_thunks_end() const {
+ VTableThunksMapTy::const_iterator vtable_thunks_end() const {
return VTableThunks.end();
}
@@ -1347,8 +1341,8 @@ public:
void dumpLayout(llvm::raw_ostream&);
};
-void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
- assert(!isBuildingConstructorVtable() &&
+void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ assert(!isBuildingConstructorVTable() &&
"Can't add thunks for construction vtable");
llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
@@ -1361,27 +1355,26 @@ void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
ThunksVector.push_back(Thunk);
}
-/// OverridesMethodInBases - Checks whether whether this virtual member
-/// function overrides a member function in any of the given bases.
-/// Returns the overridden member function, or null if none was found.
-static const CXXMethodDecl *
-OverridesMethodInBases(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
+
+/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
+/// the overridden methods that the function decl overrides.
+static void
+ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
+ OverriddenMethodsSetTy& OverriddenMethods) {
+ assert(MD->isVirtual() && "Method is not virtual!");
+
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 (Bases.count(OverriddenRD))
- return OverriddenMD;
+ OverriddenMethods.insert(OverriddenMD);
+
+ ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
}
-
- return 0;
}
-void VtableBuilder::ComputeThisAdjustments() {
+void VTableBuilder::ComputeThisAdjustments() {
// Now go through the method info map and see if any of the methods need
// 'this' pointer adjustments.
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -1390,9 +1383,9 @@ void VtableBuilder::ComputeThisAdjustments() {
const MethodInfo &MethodInfo = I->second;
// Ignore adjustments for unused function pointers.
- uint64_t VtableIndex = MethodInfo.VtableIndex;
- if (Components[VtableIndex].getKind() ==
- VtableComponent::CK_UnusedFunctionPointer)
+ uint64_t VTableIndex = MethodInfo.VTableIndex;
+ if (Components[VTableIndex].getKind() ==
+ VTableComponent::CK_UnusedFunctionPointer)
continue;
// Get the final overrider for this method.
@@ -1407,7 +1400,7 @@ void VtableBuilder::ComputeThisAdjustments() {
// While the thunk itself might be needed by vtables in subclasses or
// in construction vtables, there doesn't seem to be a reason for using
// the thunk in this vtable. Still, we do so to match gcc.
- if (VTableThunks.lookup(VtableIndex).Return.isEmpty())
+ if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
continue;
}
@@ -1418,38 +1411,38 @@ void VtableBuilder::ComputeThisAdjustments() {
continue;
// Add it.
- VTableThunks[VtableIndex].This = ThisAdjustment;
+ VTableThunks[VTableIndex].This = ThisAdjustment;
if (isa<CXXDestructorDecl>(MD)) {
// Add an adjustment for the deleting destructor as well.
- VTableThunks[VtableIndex + 1].This = ThisAdjustment;
+ VTableThunks[VTableIndex + 1].This = ThisAdjustment;
}
}
/// Clear the method info map.
MethodInfoMap.clear();
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// We don't need to store thunk information for construction vtables.
return;
}
- for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(),
+ for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(),
E = VTableThunks.end(); I != E; ++I) {
- const VtableComponent &Component = Components[I->first];
+ const VTableComponent &Component = Components[I->first];
const ThunkInfo &Thunk = I->second;
const CXXMethodDecl *MD;
switch (Component.getKind()) {
default:
llvm_unreachable("Unexpected vtable component kind!");
- case VtableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_FunctionPointer:
MD = Component.getFunctionDecl();
break;
- case VtableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
MD = Component.getDestructorDecl();
break;
- case VtableComponent::CK_DeletingDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
continue;
}
@@ -1459,7 +1452,7 @@ void VtableBuilder::ComputeThisAdjustments() {
}
}
-ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1474,11 +1467,6 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
Offset.VirtualBase);
}
-
- // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again,
- // we can get rid of this assert.
- assert(Adjustment.VBaseOffsetOffset != 0 &&
- "Invalid vbase offset offset!");
}
Adjustment.NonVirtual = Offset.NonVirtualOffset;
@@ -1488,7 +1476,7 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
}
BaseOffset
-VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
+VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
BaseSubobject Derived) const {
const CXXRecordDecl *BaseRD = Base.getBase();
const CXXRecordDecl *DerivedRD = Derived.getBase();
@@ -1540,7 +1528,7 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
}
ThisAdjustment
-VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
+VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
uint64_t BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider) {
// Ignore adjustments for pure virtual member functions.
@@ -1587,22 +1575,22 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
}
void
-VtableBuilder::AddMethod(const CXXMethodDecl *MD,
+VTableBuilder::AddMethod(const CXXMethodDecl *MD,
ReturnAdjustment ReturnAdjustment) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
// Add both the complete destructor and the deleting destructor.
- Components.push_back(VtableComponent::MakeCompleteDtor(DD));
- Components.push_back(VtableComponent::MakeDeletingDtor(DD));
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
VTableThunks[Components.size()].Return = ReturnAdjustment;
// Add the function.
- Components.push_back(VtableComponent::MakeFunction(MD));
+ Components.push_back(VTableComponent::MakeFunction(MD));
}
}
@@ -1616,19 +1604,16 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
/// struct C : B { virtual void f(); }
///
/// OverridesIndirectMethodInBase will return true if given C::f as the method
-/// and { A } as the set of bases.
+/// and { A } as the set of bases.
static bool
OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ if (Bases.count(MD->getParent()))
+ return true;
+
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 (Bases.count(OverriddenRD))
- return true;
// Check "indirect overriders".
if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
@@ -1639,7 +1624,7 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
}
bool
-VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
+VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
uint64_t BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
uint64_t FirstBaseOffsetInLayoutClass) const {
@@ -1657,7 +1642,7 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
return true;
- VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
PrimaryBases.insert(RD);
@@ -1705,15 +1690,18 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
/// from the nearest base. Returns null if no method was found.
static const CXXMethodDecl *
FindNearestOverriddenMethod(const CXXMethodDecl *MD,
- VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ OverriddenMethodsSetTy OverriddenMethods;
+ ComputeAllOverriddenMethods(MD, OverriddenMethods);
+
for (int I = Bases.size(), E = 0; I != E; --I) {
const CXXRecordDecl *PrimaryBase = Bases[I - 1];
// Now check the overriden methods.
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
+ for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
+ E = OverriddenMethods.end(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
-
+
// We found our overridden method.
if (OverriddenMD->getParent() == PrimaryBase)
return OverriddenMD;
@@ -1724,7 +1712,7 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
}
void
-VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
+VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
uint64_t FirstBaseOffsetInLayoutClass,
PrimaryBasesSetVectorTy &PrimaryBases) {
@@ -1792,7 +1780,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
MethodInfo MethodInfo(Base.getBaseOffset(),
BaseOffsetInLayoutClass,
- OverriddenMethodInfo.VtableIndex);
+ OverriddenMethodInfo.VTableIndex);
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
@@ -1804,7 +1792,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
// or indirect base class of a virtual base class, we need to emit a
// thunk if we ever have a class hierarchy where the base class is not
// a primary base in the complete object.
- if (!isBuildingConstructorVtable() && OverriddenMD != MD) {
+ if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
// Compute the this adjustment.
ThisAdjustment ThisAdjustment =
ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
@@ -1835,7 +1823,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
FirstBaseInPrimaryBaseChain,
FirstBaseOffsetInLayoutClass)) {
- Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD));
+ Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
continue;
}
@@ -1850,8 +1838,9 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
}
}
-void VtableBuilder::LayoutVtable() {
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0),
+void VTableBuilder::LayoutVTable() {
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0),
+ /*BaseIsMorallyVirtual=*/false,
MostDerivedClassIsVirtual,
MostDerivedClassOffset);
@@ -1862,22 +1851,24 @@ void VtableBuilder::LayoutVtable() {
VBases);
VBases.clear();
- LayoutVtablesForVirtualBases(MostDerivedClass, VBases);
+ LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
}
void
-VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
- bool BaseIsVirtual,
+VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass,
uint64_t OffsetInLayoutClass) {
assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
// Add vcall and vbase offsets for this vtable.
VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders,
- Base, BaseIsVirtual, OffsetInLayoutClass);
+ Base, BaseIsVirtualInLayoutClass,
+ OffsetInLayoutClass);
Components.append(Builder.components_begin(), Builder.components_end());
// Check if we need to add these vcall offsets.
- if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) {
+ if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
if (VCallOffsets.empty())
@@ -1893,10 +1884,10 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
// FIXME: We should not use / 8 here.
int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass -
MostDerivedClassOffset) / 8;
- Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop));
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
// Next, add the RTTI.
- Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass));
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
uint64_t AddressPoint = Components.size();
@@ -1936,15 +1927,11 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
RD = PrimaryBase;
}
- bool BaseIsMorallyVirtual = BaseIsVirtual;
- if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass)
- BaseIsMorallyVirtual = false;
-
// Layout secondary vtables.
- LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
+ LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
}
-void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
+void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
bool BaseIsMorallyVirtual,
uint64_t OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
@@ -1969,7 +1956,7 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
if (!BaseDecl->isDynamicClass())
continue;
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// Itanium C++ ABI 2.6.4:
// Some of the base class subobjects may not need construction virtual
// tables, which will therefore not be present in the construction
@@ -1988,20 +1975,21 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base,
// Don't emit a secondary vtable for a primary base. We might however want
// to emit secondary vtables for other bases of this base.
if (BaseDecl == PrimaryBase) {
- LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
+ LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
continue;
}
// Layout the primary vtable (and any secondary vtables) for this base.
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsVirtual=*/false,
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
+ BaseIsMorallyVirtual,
+ /*BaseIsVirtualInLayoutClass=*/false,
BaseOffsetInLayoutClass);
}
}
void
-VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
+VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
uint64_t OffsetInLayoutClass,
VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -2013,7 +2001,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
if (Layout.getPrimaryBaseWasVirtual()) {
bool IsPrimaryVirtualBase = true;
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
// Check if the base is actually a primary base in the class we use for
// layout.
const ASTRecordLayout &LayoutClassLayout =
@@ -2059,7 +2047,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
}
void
-VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
+VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
// Itanium C++ ABI 2.5.2:
// Then come the virtual base virtual tables, also in inheritance graph
@@ -2084,22 +2072,23 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
uint64_t BaseOffsetInLayoutClass =
LayoutClassLayout.getVBaseClassOffset(BaseDecl);
- LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset),
- /*BaseIsVirtual=*/true,
+ LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
+ /*BaseIsMorallyVirtual=*/true,
+ /*BaseIsVirtualInLayoutClass=*/true,
BaseOffsetInLayoutClass);
}
// We only need to check the base for virtual base vtables if it actually
// has virtual bases.
if (BaseDecl->getNumVBases())
- LayoutVtablesForVirtualBases(BaseDecl, VBases);
+ LayoutVTablesForVirtualBases(BaseDecl, VBases);
}
}
/// dumpLayout - Dump the vtable layout.
-void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
+void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) {
- if (isBuildingConstructorVtable()) {
+ if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
// FIXME: Don't use / 8 .
@@ -2129,28 +2118,28 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << llvm::format("%4d | ", I);
- const VtableComponent &Component = Components[I];
+ const VTableComponent &Component = Components[I];
// Dump the component.
switch (Component.getKind()) {
- case VtableComponent::CK_VCallOffset:
+ case VTableComponent::CK_VCallOffset:
Out << "vcall_offset (" << Component.getVCallOffset() << ")";
break;
- case VtableComponent::CK_VBaseOffset:
+ case VTableComponent::CK_VBaseOffset:
Out << "vbase_offset (" << Component.getVBaseOffset() << ")";
break;
- case VtableComponent::CK_OffsetToTop:
+ case VTableComponent::CK_OffsetToTop:
Out << "offset_to_top (" << Component.getOffsetToTop() << ")";
break;
- case VtableComponent::CK_RTTI:
+ case VTableComponent::CK_RTTI:
Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
break;
- case VtableComponent::CK_FunctionPointer: {
+ case VTableComponent::CK_FunctionPointer: {
const CXXMethodDecl *MD = Component.getFunctionDecl();
std::string Str =
@@ -2192,10 +2181,10 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
break;
}
- case VtableComponent::CK_CompleteDtorPointer:
- case VtableComponent::CK_DeletingDtorPointer: {
+ case VTableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer: {
bool IsComplete =
- Component.getKind() == VtableComponent::CK_CompleteDtorPointer;
+ Component.getKind() == VTableComponent::CK_CompleteDtorPointer;
const CXXDestructorDecl *DD = Component.getDestructorDecl();
@@ -2227,7 +2216,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
break;
}
- case VtableComponent::CK_UnusedFunctionPointer: {
+ case VTableComponent::CK_UnusedFunctionPointer: {
const CXXMethodDecl *MD = Component.getUnusedFunctionDecl();
std::string Str =
@@ -2279,7 +2268,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << '\n';
- if (isBuildingConstructorVtable())
+ if (isBuildingConstructorVTable())
return;
if (MostDerivedClass->getNumVBases()) {
@@ -2373,7 +2362,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
}
-void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
+void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
// The order of the virtual function pointers in a virtual table is the
@@ -2400,7 +2389,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Collect all the primary bases, so we can check whether methods override
// a method from the base.
- VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+ VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
for (ASTRecordLayout::primary_base_info_iterator
I = Layout.primary_base_begin(), E = Layout.primary_base_end();
I != E; ++I)
@@ -2418,7 +2407,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Check if this method overrides a method in the primary base.
if (const CXXMethodDecl *OverriddenMD =
- OverridesMethodInBases(MD, PrimaryBases)) {
+ FindNearestOverriddenMethod(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,
@@ -2430,12 +2419,12 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
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));
+ 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);
+ MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
}
// We don't need to add an entry for this method.
@@ -2452,13 +2441,13 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
}
// Add the complete dtor.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
// Add the deleting dtor.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
} else {
// Add the entry.
- MethodVtableIndices[MD] = CurrentIndex++;
+ MethodVTableIndices[MD] = CurrentIndex++;
}
}
@@ -2468,11 +2457,11 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// its entries come after the declared virtual function pointers.
// Add the complete dtor.
- MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++;
// Add the deleting dtor.
- MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
CurrentIndex++;
}
@@ -2485,24 +2474,24 @@ uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD)
if (I != NumVirtualFunctionPointers.end())
return I->second;
- ComputeMethodVtableIndices(RD);
+ ComputeMethodVTableIndices(RD);
I = NumVirtualFunctionPointers.find(RD);
assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
return I->second;
}
-uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) {
- MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
- if (I != MethodVtableIndices.end())
+uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) {
+ MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
+ if (I != MethodVTableIndices.end())
return I->second;
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
- ComputeMethodVtableIndices(RD);
+ ComputeMethodVTableIndices(RD);
- I = MethodVtableIndices.find(GD);
- assert(I != MethodVtableIndices.end() && "Did not find index!");
+ I = MethodVTableIndices.find(GD);
+ assert(I != MethodVTableIndices.end() && "Did not find index!");
return I->second;
}
@@ -2530,13 +2519,6 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
}
I = VirtualBaseClassOffsetOffsets.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 == VirtualBaseClassOffsetOffsets.end())
- return 0;
-
assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
return I->second;
@@ -2544,6 +2526,9 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
uint64_t
CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) {
+ assert(AddressPoints.count(std::make_pair(RD, Base)) &&
+ "Did not find address point!");
+
uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base));
assert(AddressPoint && "Address point must not be zero!");
@@ -2562,7 +2547,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
else
getMangleContext().mangleThunk(MD, Thunk, Name);
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD);
return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
}
@@ -2745,7 +2730,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
// There's already a declaration with the same name, check if it has the same
// type or if we need to replace it.
if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() !=
- CGM.getTypes().GetFunctionTypeForVtable(MD)) {
+ CGM.getTypes().GetFunctionTypeForVTable(MD)) {
llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry);
// If the types mismatch then we have to rewrite the definition.
@@ -2804,7 +2789,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (LayoutData)
return;
- VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
// Add the VTable layout.
uint64_t NumVTableComponents = Builder.getNumVTableComponents();
@@ -2833,7 +2818,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
std::sort(VTableThunks.begin(), VTableThunks.end());
// Add the address points.
- for (VtableBuilder::AddressPointsMapTy::const_iterator I =
+ for (VTableBuilder::AddressPointsMapTy::const_iterator I =
Builder.address_points_begin(), E = Builder.address_points_end();
I != E; ++I) {
@@ -2858,7 +2843,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
return;
- for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
Builder.getVBaseOffsetOffsets().begin(),
E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
// Insert all types.
@@ -2888,43 +2873,43 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
llvm::Constant* PureVirtualFn = 0;
for (unsigned I = 0; I != NumComponents; ++I) {
- VtableComponent Component =
- VtableComponent::getFromOpaqueInteger(Components[I]);
+ VTableComponent Component =
+ VTableComponent::getFromOpaqueInteger(Components[I]);
llvm::Constant *Init = 0;
switch (Component.getKind()) {
- case VtableComponent::CK_VCallOffset:
+ case VTableComponent::CK_VCallOffset:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_VBaseOffset:
+ case VTableComponent::CK_VBaseOffset:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_OffsetToTop:
+ case VTableComponent::CK_OffsetToTop:
Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop());
Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
break;
- case VtableComponent::CK_RTTI:
+ case VTableComponent::CK_RTTI:
Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy);
break;
- case VtableComponent::CK_FunctionPointer:
- case VtableComponent::CK_CompleteDtorPointer:
- case VtableComponent::CK_DeletingDtorPointer: {
+ case VTableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer: {
GlobalDecl GD;
// Get the right global decl.
switch (Component.getKind()) {
default:
llvm_unreachable("Unexpected vtable component kind");
- case VtableComponent::CK_FunctionPointer:
+ case VTableComponent::CK_FunctionPointer:
GD = Component.getFunctionDecl();
break;
- case VtableComponent::CK_CompleteDtorPointer:
+ case VTableComponent::CK_CompleteDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
break;
- case VtableComponent::CK_DeletingDtorPointer:
+ case VTableComponent::CK_DeletingDtorPointer:
GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
break;
}
@@ -2953,7 +2938,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
NextVTableThunkIndex++;
} else {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD);
Init = CGM.GetAddrOfFunction(GD, Ty);
}
@@ -2963,7 +2948,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
break;
}
- case VtableComponent::CK_UnusedFunctionPointer:
+ case VTableComponent::CK_UnusedFunctionPointer:
Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
break;
};
@@ -3020,7 +3005,7 @@ GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name,
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXVtable(RD, OutName);
+ CGM.getMangleContext().mangleCXXVTable(RD, OutName);
llvm::StringRef Name = OutName.str();
ComputeVTableRelatedInformation(RD);
@@ -3038,8 +3023,8 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
// Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVtableLayouts) {
- VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+ if (CGM.getLangOptions().DumpVTableLayouts) {
+ VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
Builder.dumpLayout(llvm::errs());
}
@@ -3064,11 +3049,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
const BaseSubobject &Base,
bool BaseIsVirtual,
VTableAddressPointsMapTy& AddressPoints) {
- VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
+ VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
/*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
// Dump the vtable layout if necessary.
- if (CGM.getLangOptions().DumpVtableLayouts)
+ if (CGM.getLangOptions().DumpVTableLayouts)
Builder.dumpLayout(llvm::errs());
// Add the address points.
@@ -3077,7 +3062,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// Get the mangled construction vtable name.
llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8,
+ CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8,
Base.getBase(), OutName);
llvm::StringRef Name = OutName.str();
@@ -3111,9 +3096,9 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
void
CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&VTable = Vtables[RD];
+ llvm::GlobalVariable *&VTable = VTables[RD];
if (VTable) {
- assert(VTable->getInitializer() && "Vtable doesn't have a definition!");
+ assert(VTable->getInitializer() && "VTable doesn't have a definition!");
return;
}
@@ -3121,6 +3106,18 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
EmitVTableDefinition(VTable, Linkage, RD);
GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+
+ // If this is the magic class __cxxabiv1::__fundamental_type_info,
+ // we will emit the typeinfo for the fundamental types. This is the
+ // same behaviour as GCC.
+ const DeclContext *DC = RD->getDeclContext();
+ if (RD->getIdentifier() &&
+ RD->getIdentifier()->isStr("__fundamental_type_info") &&
+ isa<NamespaceDecl>(DC) &&
+ cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
+ DC->getParent()->isTranslationUnit())
+ CGM.EmitFundamentalRTTIDescriptors();
}
void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
@@ -3160,11 +3157,11 @@ void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
return;
}
- if (Vtables.count(RD))
+ if (VTables.count(RD))
return;
if (RDKind == TSK_ImplicitInstantiation)
- CGM.DeferredVtables.push_back(RD);
+ CGM.DeferredVTables.push_back(RD);
else
- GenerateClassData(CGM.getVtableLinkage(RD), RD);
+ GenerateClassData(CGM.getVTableLinkage(RD), RD);
}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVTables.h
index 60735554d56e..6c18ca83f091 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVTables.h
@@ -1,4 +1,4 @@
-//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===//
+//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -180,10 +180,10 @@ namespace CodeGen {
class CodeGenVTables {
CodeGenModule &CGM;
- /// MethodVtableIndices - Contains the index (relative to the vtable address
+ /// MethodVTableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
- typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
- MethodVtableIndicesTy MethodVtableIndices;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
+ MethodVTableIndicesTy MethodVTableIndices;
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
@@ -195,8 +195,8 @@ class CodeGenVTables {
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
- /// Vtables - All the vtables which have been defined.
- llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables;
+ /// VTables - All the vtables which have been defined.
+ llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
/// NumVirtualFunctionPointers - Contains the number of virtual function
/// pointers in the vtable for a given record decl.
@@ -216,8 +216,8 @@ class CodeGenVTables {
/// integers are the vtable components.
VTableLayoutMapTy VTableLayoutMap;
- typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
- BaseSubobject>, uint64_t> AddressPointsMapTy;
+ typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy;
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> AddressPointsMapTy;
/// Address points - Address points for all vtables.
AddressPointsMapTy AddressPoints;
@@ -247,14 +247,12 @@ class CodeGenVTables {
return &Components[1];
}
- typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy;
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy;
/// SubVTTIndicies - Contains indices into the various sub-VTTs.
SubVTTIndiciesMapTy SubVTTIndicies;
-
- typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
- BaseSubobject>, uint64_t>
+ typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t>
SecondaryVirtualPointerIndicesMapTy;
/// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
@@ -265,7 +263,7 @@ class CodeGenVTables {
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
- void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
+ void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
@@ -295,6 +293,15 @@ public:
CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM) { }
+ // isKeyFunctionInAnotherTU - True if this record has a key function and it is
+ // in another translation unit.
+ static bool isKeyFunctionInAnotherTU(ASTContext &Context,
+ const CXXRecordDecl *RD) {
+ assert (RD->isDynamicClass() && "Non dynamic classes have no key.");
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
+ return KeyFunction && !KeyFunction->getBody();
+ }
+
/// needsVTTParameter - Return whether the given global decl needs a VTT
/// parameter, which it does if it's a base constructor or destructor with
/// virtual bases.
@@ -302,17 +309,17 @@ public:
/// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
/// given record decl.
- uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base);
+ uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base);
/// getSecondaryVirtualPointerIndex - Return the index in the VTT where the
/// virtual pointer for the given subobject is located.
uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
BaseSubobject Base);
- /// getMethodVtableIndex - Return the index (relative to the vtable address
+ /// getMethodVTableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
- uint64_t getMethodVtableIndex(GlobalDecl GD);
+ uint64_t getMethodVTableIndex(GlobalDecl GD);
/// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the
/// vtable address point) where the offset of the virtual base that contains
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 91fb714315fc..92ef9dc4a11f 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -34,69 +34,64 @@ namespace CodeGen {
/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
/// address of an aggregate value in memory.
class RValue {
- llvm::Value *V1, *V2;
- // TODO: Encode this into the low bit of pointer for more efficient
- // return-by-value.
- enum { Scalar, Complex, Aggregate } Flavor;
+ enum Flavor { Scalar, Complex, Aggregate };
- bool Volatile:1;
-public:
+ // Stores first value and flavor.
+ llvm::PointerIntPair<llvm::Value *, 2, Flavor> V1;
+ // Stores second value and volatility.
+ llvm::PointerIntPair<llvm::Value *, 1, bool> V2;
- bool isScalar() const { return Flavor == Scalar; }
- bool isComplex() const { return Flavor == Complex; }
- bool isAggregate() const { return Flavor == Aggregate; }
+public:
+ bool isScalar() const { return V1.getInt() == Scalar; }
+ bool isComplex() const { return V1.getInt() == Complex; }
+ bool isAggregate() const { return V1.getInt() == Aggregate; }
- bool isVolatileQualified() const { return Volatile; }
+ bool isVolatileQualified() const { return V2.getInt(); }
/// getScalarVal() - Return the Value* of this scalar value.
llvm::Value *getScalarVal() const {
assert(isScalar() && "Not a scalar!");
- return V1;
+ return V1.getPointer();
}
/// getComplexVal - Return the real/imag components of this complex value.
///
std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
- return std::pair<llvm::Value *, llvm::Value *>(V1, V2);
+ return std::make_pair(V1.getPointer(), V2.getPointer());
}
/// getAggregateAddr() - Return the Value* of the address of the aggregate.
llvm::Value *getAggregateAddr() const {
assert(isAggregate() && "Not an aggregate!");
- return V1;
+ return V1.getPointer();
}
static RValue get(llvm::Value *V) {
RValue ER;
- ER.V1 = V;
- ER.Flavor = Scalar;
- ER.Volatile = false;
+ ER.V1.setPointer(V);
+ ER.V1.setInt(Scalar);
+ ER.V2.setInt(false);
return ER;
}
static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
RValue ER;
- ER.V1 = V1;
- ER.V2 = V2;
- ER.Flavor = Complex;
- ER.Volatile = false;
+ ER.V1.setPointer(V1);
+ ER.V2.setPointer(V2);
+ ER.V1.setInt(Complex);
+ ER.V2.setInt(false);
return ER;
}
static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
- RValue ER;
- ER.V1 = C.first;
- ER.V2 = C.second;
- ER.Flavor = Complex;
- ER.Volatile = false;
- return ER;
+ return getComplex(C.first, C.second);
}
// FIXME: Aggregate rvalues need to retain information about whether they are
// volatile or not. Remove default to find all places that probably get this
// wrong.
- static RValue getAggregate(llvm::Value *V, bool Vol = false) {
+ static RValue getAggregate(llvm::Value *V, bool Volatile = false) {
RValue ER;
- ER.V1 = V;
- ER.Flavor = Aggregate;
- ER.Volatile = Vol;
+ ER.V1.setPointer(V);
+ ER.V1.setInt(Aggregate);
+ ER.V2.setInt(Volatile);
return ER;
}
};
@@ -220,7 +215,7 @@ public:
}
// bitfield lvalue
- llvm::Value *getBitFieldAddr() const {
+ llvm::Value *getBitFieldBaseAddr() const {
assert(isBitField());
return V;
}
@@ -269,11 +264,17 @@ public:
return R;
}
- static LValue MakeBitfield(llvm::Value *V, const CGBitFieldInfo &Info,
+ /// \brief Create a new object to represent a bit-field access.
+ ///
+ /// \param BaseValue - The base address of the structure containing the
+ /// bit-field.
+ /// \param Info - The information describing how to perform the bit-field
+ /// access.
+ static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info,
unsigned CVR) {
LValue R;
R.LVType = BitField;
- R.V = V;
+ R.V = BaseValue;
R.BitFieldInfo = &Info;
R.SetQualifiers(Qualifiers::fromCVRMask(CVR));
return R;
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index e72a1d9e0946..dfd2a391a4cf 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -23,7 +23,7 @@ add_clang_library(clangCodeGen
CGRTTI.cpp
CGStmt.cpp
CGTemporaries.cpp
- CGVtable.cpp
+ CGVTables.cpp
CGVTT.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f38d8a132f02..d3bf1645a026 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -246,15 +246,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
-
- Stmt *Body = FD->getBody();
- if (Body)
- EmitStmt(Body);
- else {
- assert(FD->isImplicit() && "non-implicit function def has no body");
- assert(FD->isCopyAssignment() && "implicit function not copy assignment");
- SynthesizeCXXCopyAssignment(Args);
- }
+ assert(FD->getBody());
+ EmitStmt(FD->getBody());
}
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
@@ -480,6 +473,14 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
}
void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
+ // Ignore empty classes in C++.
+ if (getContext().getLangOptions().CPlusPlus) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty())
+ return;
+ }
+ }
+
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (DestPtr->getType() != BP)
DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp");
@@ -749,6 +750,11 @@ void CodeGenFunction::EmitCleanupBlock() {
return;
}
+ // Scrub debug location info.
+ for (llvm::BasicBlock::iterator LBI = Info.CleanupBlock->begin(),
+ LBE = Info.CleanupBlock->end(); LBI != LBE; ++LBI)
+ Builder.SetInstDebugLocation(LBI);
+
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
if (CurBB && !CurBB->getTerminator() &&
Info.CleanupBlock->getNumUses() == 0) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index f21350d0f2d9..90a3ec4a4b10 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -32,6 +32,7 @@
namespace llvm {
class BasicBlock;
class LLVMContext;
+ class MDNode;
class Module;
class SwitchInst;
class Twine;
@@ -148,19 +149,17 @@ public:
/// block.
class EHCleanupBlock {
CodeGenFunction& CGF;
- llvm::BasicBlock *Cont;
+ llvm::BasicBlock *PreviousInsertionBlock;
llvm::BasicBlock *CleanupHandler;
- llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *PreviousInvokeDest;
public:
EHCleanupBlock(CodeGenFunction &cgf)
- : CGF(cgf), Cont(CGF.createBasicBlock("cont")),
- CleanupHandler(CGF.createBasicBlock("ehcleanup")),
- CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")),
+ : CGF(cgf),
+ PreviousInsertionBlock(CGF.Builder.GetInsertBlock()),
+ CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)),
PreviousInvokeDest(CGF.getInvokeDest()) {
- CGF.EmitBranch(Cont);
llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- CGF.Builder.SetInsertPoint(CleanupEntryBB);
+ CGF.Builder.SetInsertPoint(CleanupHandler);
CGF.setInvokeDest(TerminateHandler);
}
~EHCleanupBlock();
@@ -186,7 +185,8 @@ public:
public:
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
- CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
+ CleanupEntryBB(CGF.createBasicBlock("cleanup")),
+ CleanupExitBB(0),
CurInvokeDest(CGF.getInvokeDest()),
EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
@@ -474,11 +474,15 @@ public:
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
+ void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
+ ObjCMethodDecl *MD, bool ctor);
/// GenerateObjCSetter - Synthesize an Objective-C property setter function
/// for the given property.
void GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID);
+ bool IndirectObjCSetterArg(const CGFunctionInfo &FI);
+ bool IvarTypeWithAggrGCObjects(QualType Ty);
//===--------------------------------------------------------------------===//
// Block Bits
@@ -532,14 +536,16 @@ public:
/// InitializeVTablePointer - Initialize the vtable pointer of the given
/// subobject.
///
- /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base
- /// or a direct or indirect base of a virtual base.
- void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void InitializeVTablePointer(BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass);
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
- void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ void InitializeVTablePointers(BaseSubobject Base,
+ const CXXRecordDecl *NearestVBase,
+ uint64_t OffsetFromNearestVBase,
bool BaseIsNonVirtualPrimaryBase,
llvm::Constant *VTable,
const CXXRecordDecl *VTableClass,
@@ -549,7 +555,6 @@ public:
void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
- void SynthesizeCXXCopyAssignment(const FunctionArgList &Args);
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes in
@@ -670,6 +675,9 @@ public:
llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty,
const llvm::Twine &Name = "tmp");
+ /// InitTempAlloca - Provide an initial value for the given alloca.
+ void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value);
+
/// CreateIRTemp - Create a temporary IR object of the given type, with
/// appropriate alignment. This routine should only be used when an temporary
/// value needs to be stored into an alloca (for example, to avoid explicit
@@ -704,6 +712,12 @@ public:
RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false,
bool IsInitializer = false);
+ /// EmitsAnyExprToMem - Emits the code necessary to evaluate an
+ /// arbitrary expression into the given memory location.
+ void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
+ bool IsLocationVolatile = false,
+ bool IsInitializer = false);
+
/// EmitAggregateCopy - Emit an aggrate copy.
///
/// \param isVolatile - True iff either the source or the destination is
@@ -765,22 +779,23 @@ public:
}
/// 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);
-
+ /// complete class to the given direct base.
+ llvm::Value *
+ GetAddressOfDirectBaseInCompleteClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Base,
+ bool BaseIsVirtual);
+
/// GetAddressOfBaseClass - This function will add the necessary delta to the
/// load of 'this' and returns address of the base class.
- llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue);
-
+
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *DerivedClassDecl,
+ const CXXRecordDecl *Derived,
+ const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue);
llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This,
@@ -789,31 +804,17 @@ public:
void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
llvm::Value *SrcValue,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
-
- void EmitClassAggrCopyAssignment(llvm::Value *DestValue,
- llvm::Value *SrcValue,
- const ArrayType *Array,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
+ const ConstantArrayType *Array,
+ const CXXRecordDecl *ClassDecl);
void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
-
- void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- QualType Ty);
+ const CXXRecordDecl *ClassDecl);
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- llvm::Value *This,
+ bool ForVirtualBase, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
@@ -842,7 +843,7 @@ public:
llvm::Value *This);
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
- llvm::Value *This);
+ bool ForVirtualBase, llvm::Value *This);
void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr);
void PopCXXTemporary();
@@ -1033,6 +1034,7 @@ public:
// Note: only availabe for agg return types
LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
+ LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E);
// Note: only available for agg return types
LValue EmitCallExprLValue(const CallExpr *E);
// Note: only available for agg return types
@@ -1100,7 +1102,8 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &Args,
- const Decl *TargetDecl = 0);
+ const Decl *TargetDecl = 0,
+ llvm::Instruction **callOrInvoke = 0);
RValue EmitCall(QualType FnType, llvm::Value *Callee,
ReturnValueSlot ReturnValue,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index a2ad31e85a80..cc90a2855dee 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -35,6 +35,7 @@
#include "llvm/LLVMContext.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace CodeGen;
@@ -47,7 +48,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()),
- MangleCtx(C), VTables(*this), Runtime(0), CFConstantStringClassRef(0),
+ MangleCtx(C, diags), VTables(*this), Runtime(0),
+ CFConstantStringClassRef(0),
+ NSConstantStringClassRef(0),
VMContext(M.getContext()) {
if (!Features.ObjC1)
@@ -78,7 +81,6 @@ void CodeGenModule::createObjCRuntime() {
}
void CodeGenModule::Release() {
- EmitFundamentalRTTIDescriptors();
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
@@ -313,7 +315,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
if (FD->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration)
return CodeGenModule::GVA_C99Inline;
-
+
+ // If this is a virtual method and its class has a key method in another
+ // translation unit, we know that this method will be present in that
+ // translation unit. In this translation unit we will use this method
+ // only for inlining and analysis. This is the semantics of c99 inline.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isVirtual() &&
+ CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD))
+ return CodeGenModule::GVA_C99Inline;
+ }
+
return CodeGenModule::GVA_CXXInline;
}
@@ -491,11 +504,11 @@ void CodeGenModule::EmitDeferred() {
// previously unused static decl may become used during the generation of code
// for a static function, iterate until no changes are made.
- while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) {
- if (!DeferredVtables.empty()) {
- const CXXRecordDecl *RD = DeferredVtables.back();
- DeferredVtables.pop_back();
- getVTables().GenerateClassData(getVtableLinkage(RD), RD);
+ while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
+ if (!DeferredVTables.empty()) {
+ const CXXRecordDecl *RD = DeferredVTables.back();
+ DeferredVTables.pop_back();
+ getVTables().GenerateClassData(getVTableLinkage(RD), RD);
continue;
}
@@ -687,30 +700,30 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// Defer code generation when possible if this is a static definition, inline
// function etc. These we only want to emit if they are used.
- if (MayDeferGeneration(Global)) {
- // If the value has already been used, add it directly to the
- // DeferredDeclsToEmit list.
- MangleBuffer MangledName;
- getMangledName(MangledName, GD);
- if (GetGlobalValue(MangledName))
- DeferredDeclsToEmit.push_back(GD);
- else {
- // Otherwise, remember that we saw a deferred decl with this name. The
- // first use of the mangled name will cause it to move into
- // DeferredDeclsToEmit.
- DeferredDecls[MangledName] = GD;
- }
+ if (!MayDeferGeneration(Global)) {
+ // Emit the definition if it can't be deferred.
+ EmitGlobalDefinition(GD);
return;
}
-
- // Otherwise emit the definition.
- EmitGlobalDefinition(GD);
+
+ // If the value has already been used, add it directly to the
+ // DeferredDeclsToEmit list.
+ MangleBuffer MangledName;
+ getMangledName(MangledName, GD);
+ if (GetGlobalValue(MangledName))
+ DeferredDeclsToEmit.push_back(GD);
+ else {
+ // Otherwise, remember that we saw a deferred decl with this name. The
+ // first use of the mangled name will cause it to move into
+ // DeferredDeclsToEmit.
+ DeferredDecls[MangledName] = GD;
+ }
}
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
- PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(),
+ PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(),
Context.getSourceManager(),
"Generating code for declaration");
@@ -718,16 +731,18 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
getVTables().EmitVTableRelatedData(GD);
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
- EmitCXXConstructor(CD, GD.getCtorType());
- else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
- EmitCXXDestructor(DD, GD.getDtorType());
- else if (isa<FunctionDecl>(D))
- EmitGlobalFunctionDefinition(GD);
- else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
- EmitGlobalVarDefinition(VD);
- else {
- assert(0 && "Invalid argument to EmitGlobalDefinition()");
- }
+ return EmitCXXConstructor(CD, GD.getCtorType());
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
+ return EmitCXXDestructor(DD, GD.getDtorType());
+
+ if (isa<FunctionDecl>(D))
+ return EmitGlobalFunctionDefinition(GD);
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return EmitGlobalVarDefinition(VD);
+
+ assert(0 && "Invalid argument to EmitGlobalDefinition()");
}
/// GetOrCreateLLVMFunction - If the specified mangled name is not in the
@@ -764,12 +779,16 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
// type is an incomplete struct). Use a fake type instead, and make
// sure not to try to set attributes.
bool IsIncompleteFunction = false;
- if (!isa<llvm::FunctionType>(Ty)) {
- Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- std::vector<const llvm::Type*>(), false);
+
+ const llvm::FunctionType *FTy;
+ if (isa<llvm::FunctionType>(Ty)) {
+ FTy = cast<llvm::FunctionType>(Ty);
+ } else {
+ FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ std::vector<const llvm::Type*>(), false);
IsIncompleteFunction = true;
}
- llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function *F = llvm::Function::Create(FTy,
llvm::Function::ExternalLinkage,
MangledName, &getModule());
assert(F->getName() == MangledName && "name was uniqued!");
@@ -811,7 +830,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
}
}
- return F;
+ // Make sure the result is of the requested type.
+ if (!IsIncompleteFunction) {
+ assert(F->getType()->getElementType() == Ty);
+ return F;
+ }
+
+ const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ return llvm::ConstantExpr::getBitCast(F, PTy);
}
/// GetAddrOfFunction - Return the address of the given function. If Ty is
@@ -959,7 +985,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
}
llvm::GlobalVariable::LinkageTypes
-CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
+CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
return llvm::GlobalVariable::InternalLinkage;
@@ -1204,9 +1230,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
UI != E; ) {
// TODO: Do invokes ever occur in C code? If so, we should handle them too.
- unsigned OpNo = UI.getOperandNo();
- llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++);
- if (!CI || OpNo != 0) continue;
+ llvm::Value::use_iterator I = UI++; // Increment before the CI is erased.
+ llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*I);
+ llvm::CallSite CS(CI);
+ if (!CI || !CS.isCallee(I)) continue;
// If the return types don't match exactly, and if the call isn't dead, then
// we can't transform this call.
@@ -1220,8 +1247,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
bool DontTransform = false;
for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
- if (CI->getNumOperands()-1 == ArgNo ||
- CI->getOperand(ArgNo+1)->getType() != AI->getType()) {
+ if (CS.arg_size() == ArgNo ||
+ CS.getArgument(ArgNo)->getType() != AI->getType()) {
DontTransform = true;
break;
}
@@ -1231,7 +1258,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
- ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo);
+ ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo);
llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(),
ArgList.end(), "", CI);
ArgList.clear();
@@ -1578,6 +1605,90 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
return GV;
}
+llvm::Constant *
+CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) {
+ unsigned StringLength = 0;
+ bool isUTF16 = false;
+ llvm::StringMapEntry<llvm::Constant*> &Entry =
+ GetConstantCFStringEntry(CFConstantStringMap, Literal,
+ getTargetData().isLittleEndian(),
+ isUTF16, StringLength);
+
+ if (llvm::Constant *C = Entry.getValue())
+ return C;
+
+ llvm::Constant *Zero =
+ llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext));
+ llvm::Constant *Zeros[] = { Zero, Zero };
+
+ // If we don't already have it, get _NSConstantStringClassReference.
+ if (!NSConstantStringClassRef) {
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
+ Ty = llvm::ArrayType::get(Ty, 0);
+ llvm::Constant *GV = CreateRuntimeVariable(Ty,
+ Features.ObjCNonFragileABI ?
+ "OBJC_CLASS_$_NSConstantString" :
+ "_NSConstantStringClassReference");
+ // Decay array -> ptr
+ NSConstantStringClassRef =
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+ }
+
+ QualType NSTy = getContext().getNSConstantStringType();
+
+ const llvm::StructType *STy =
+ cast<llvm::StructType>(getTypes().ConvertType(NSTy));
+
+ std::vector<llvm::Constant*> Fields(3);
+
+ // Class pointer.
+ Fields[0] = NSConstantStringClassRef;
+
+ // String pointer.
+ llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str());
+
+ llvm::GlobalValue::LinkageTypes Linkage;
+ bool isConstant;
+ if (isUTF16) {
+ // FIXME: why do utf strings get "_" labels instead of "L" labels?
+ Linkage = llvm::GlobalValue::InternalLinkage;
+ // Note: -fwritable-strings doesn't make unicode NSStrings writable, but
+ // does make plain ascii ones writable.
+ isConstant = true;
+ } else {
+ Linkage = llvm::GlobalValue::PrivateLinkage;
+ isConstant = !Features.WritableStrings;
+ }
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
+ ".str");
+ if (isUTF16) {
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
+ GV->setAlignment(Align.getQuantity());
+ }
+ Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
+
+ // String length.
+ const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy);
+ Fields[2] = llvm::ConstantInt::get(Ty, StringLength);
+
+ // The struct.
+ C = llvm::ConstantStruct::get(STy, Fields);
+ GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
+ llvm::GlobalVariable::PrivateLinkage, C,
+ "_unnamed_nsstring_");
+ // FIXME. Fix section.
+ if (const char *Sect =
+ Features.ObjCNonFragileABI
+ ? getContext().Target.getNSStringNonFragileABISection()
+ : getContext().Target.getNSStringSection())
+ GV->setSection(Sect);
+ Entry.setValue(GV);
+
+ return GV;
+}
+
/// GetStringForStringLiteral - Return the appropriate bytes for a
/// string literal, properly padded to match the literal type.
std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
@@ -1709,6 +1820,39 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
}
}
+/// EmitObjCIvarInitializations - Emit information for ivar initialization
+/// for an implementation.
+void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
+ if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0)
+ return;
+ DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D));
+ assert(DC && "EmitObjCIvarInitializations - null DeclContext");
+ IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct");
+ Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
+ ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(),
+ D->getLocation(),
+ D->getLocation(), cxxSelector,
+ getContext().VoidTy, 0,
+ DC, true, false, true,
+ ObjCMethodDecl::Required);
+ D->addInstanceMethod(DTORMethod);
+ CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
+
+ II = &getContext().Idents.get(".cxx_construct");
+ cxxSelector = getContext().Selectors.getSelector(0, &II);
+ // The constructor returns 'self'.
+ ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(),
+ D->getLocation(),
+ D->getLocation(), cxxSelector,
+ getContext().getObjCIdType(), 0,
+ DC, true, false, true,
+ ObjCMethodDecl::Required);
+ D->addInstanceMethod(CTORMethod);
+ CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
+
+
+}
+
/// EmitNamespace - Emit all declarations in a namespace.
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end();
@@ -1805,6 +1949,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::ObjCImplementation: {
ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
EmitObjCPropertyImplementations(OMD);
+ EmitObjCIvarInitializations(OMD);
Runtime->GenerateClass(OMD);
break;
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index e9f78bcdb0a5..93d8ddf3e485 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -21,7 +21,7 @@
#include "CGBlocks.h"
#include "CGCall.h"
#include "CGCXX.h"
-#include "CGVtable.h"
+#include "CGVTables.h"
#include "CodeGenTypes.h"
#include "GlobalDecl.h"
#include "Mangle.h"
@@ -94,7 +94,8 @@ class CodeGenModule : public BlockModule {
/// VTables - Holds information about C++ vtables.
CodeGenVTables VTables;
-
+ friend class CodeGenVTables;
+
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
@@ -132,6 +133,7 @@ class CodeGenModule : public BlockModule {
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
llvm::StringMap<llvm::Constant*> ConstantStringMap;
+ llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap;
/// CXXGlobalInits - Global variables with initializers that need to run
/// before main.
@@ -145,6 +147,10 @@ class CodeGenModule : public BlockModule {
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
+ /// NSConstantStringClassRef - Cached reference to the class for constant
+ /// strings. This value has type int * but is actually an Obj-C class pointer.
+ llvm::Constant *NSConstantStringClassRef;
+
/// Lazily create the Objective-C runtime
void createObjCRuntime();
@@ -169,6 +175,14 @@ public:
/// been configured.
bool hasObjCRuntime() { return !!Runtime; }
+ llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
+ return StaticLocalDeclMap[VD];
+ }
+ void setStaticLocalDeclAddress(const VarDecl *D,
+ llvm::GlobalVariable *GV) {
+ StaticLocalDeclMap[D] = GV;
+ }
+
CGDebugInfo *getDebugInfo() { return DebugInfo; }
ASTContext &getContext() const { return Context; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
@@ -218,7 +232,7 @@ public:
/// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor
/// for the given type.
- llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty);
+ llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
/// GetAddrOfThunk - Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
@@ -227,11 +241,11 @@ public:
llvm::Constant *GetWeakRefReference(const ValueDecl *VD);
/// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
- /// its base class. Returns null if the offset is 0.
+ /// a class. Returns null if the offset is 0.
llvm::Constant *
GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
-
+ const CXXBaseSpecifierArray &BasePath);
+
/// GetStringForStringLiteral - Return the appropriate bytes for a string
/// literal, properly padded to match the literal type. If only the address of
/// a constant is needed consider using GetAddrOfConstantStringLiteral.
@@ -240,6 +254,10 @@ public:
/// GetAddrOfConstantCFString - Return a pointer to a constant CFString object
/// for the given string.
llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal);
+
+ /// GetAddrOfConstantNSString - Return a pointer to a constant NSString object
+ /// for the given string.
+ llvm::Constant *GetAddrOfConstantNSString(const StringLiteral *Literal);
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array
/// for the given string literal.
@@ -416,16 +434,16 @@ public:
llvm::GlobalVariable::LinkageTypes
getFunctionLinkage(const FunctionDecl *FD);
- /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT,
+ /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT,
/// and type information of the given class.
static llvm::GlobalVariable::LinkageTypes
- getVtableLinkage(const CXXRecordDecl *RD);
+ getVTableLinkage(const CXXRecordDecl *RD);
/// GetTargetTypeStoreSize - Return the store size, in character units, of
/// the given LLVM type.
CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const;
- std::vector<const CXXRecordDecl*> DeferredVtables;
+ std::vector<const CXXRecordDecl*> DeferredVTables;
private:
llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref);
@@ -464,6 +482,7 @@ private:
void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
+ void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
// C++ related functions.
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 9b74106d61ce..10e71e2a03fa 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -52,7 +52,6 @@ namespace clang {
namespace CodeGen {
class CGRecordLayout;
- class CodeGenTypes;
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
@@ -124,10 +123,10 @@ public:
const llvm::FunctionType *GetFunctionType(GlobalDecl GD);
- /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
+ /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable,
/// given a CXXMethodDecl. If the method to has an incomplete return type,
/// and/or incomplete argument types, this will return the opaque type.
- const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
+ const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD);
const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const;
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 077db7c26852..8658cfb0282c 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -25,7 +25,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include "CGVtable.h"
+#include "CGVTables.h"
#define MANGLE_CHECKER 0
@@ -111,6 +111,7 @@ public:
private:
bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(TemplateName Template);
bool mangleSubstitution(uintptr_t Ptr);
bool mangleStandardSubstitution(const NamedDecl *ND);
@@ -121,6 +122,7 @@ private:
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
void addSubstitution(QualType T);
+ void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
@@ -138,6 +140,7 @@ private:
unsigned KnownArity);
void mangleUnscopedName(const NamedDecl *ND);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
@@ -147,6 +150,7 @@ private:
unsigned NumTemplateArgs);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
@@ -172,6 +176,9 @@ private:
void mangleCXXCtorType(CXXCtorType T);
void mangleCXXDtorType(CXXDtorType T);
+ void mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
void mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
@@ -306,8 +313,6 @@ static bool isStd(const NamespaceDecl *NS) {
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC)) {
- assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
- LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
@@ -429,6 +434,31 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
addSubstitution(ND);
}
+void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleUnscopedTemplateName(TD);
+
+ if (mangleSubstitution(Template))
+ return;
+
+ // FIXME: How to cope with operators here?
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Not a dependent template name?");
+ if (!Dependent->isIdentifier()) {
+ // FIXME: We can't possibly know the arity of the operator here!
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot mangle dependent operator name");
+ Diags.Report(FullSourceLoc(), DiagID);
+ return;
+ }
+
+ mangleSourceName(Dependent->getIdentifier());
+ addSubstitution(Template);
+}
+
void CXXNameMangler::mangleNumber(int64_t Number) {
// <number> ::= [n] <non-negative decimal integer>
if (Number < 0) {
@@ -475,11 +505,12 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
- TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
- assert(TD && "FIXME: Support dependent template names");
- mangleTemplatePrefix(TD);
- TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
- mangleTemplateArgs(*TemplateParameters, TST->getArgs(),
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
@@ -741,6 +772,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
addSubstitution(cast<NamedDecl>(DC));
}
+void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplatePrefix(TD);
+
+ if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
+ mangleUnresolvedScope(Qualified->getQualifier());
+
+ if (OverloadedTemplateStorage *Overloaded
+ = Template.getAsOverloadedTemplate()) {
+ mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
+ UnknownArity);
+ return;
+ }
+
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Unknown template name kind?");
+ mangleUnresolvedScope(Dependent->getQualifier());
+ mangleUnscopedTemplateName(Template);
+}
+
void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
@@ -896,7 +950,7 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
assert (CD && "Missing container decl in GetNameForMethod");
OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
- OS << '(' << CID->getNameAsString() << ')';
+ OS << '(' << CID << ')';
OS << ' ' << MD->getSelector().getAsString() << ']';
Out << OS.str().size() << OS.str();
@@ -1157,18 +1211,50 @@ void CXXNameMangler::mangleType(const BlockPointerType *T) {
mangleType(T->getPointeeType());
}
-void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
- TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
- assert(TD && "FIXME: Support dependent template names!");
+void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
+ // Mangle injected class name types as if the user had written the
+ // specialization out fully. It may not actually be possible to see
+ // this mangling, though.
+ mangleType(T->getInjectedSpecializationType());
+}
- mangleName(TD, T->getArgs(), T->getNumArgs());
+void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
+ mangleName(TD, T->getArgs(), T->getNumArgs());
+ } else {
+ if (mangleSubstitution(QualType(T, 0)))
+ return;
+
+ mangleTemplatePrefix(T->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ addSubstitution(QualType(T, 0));
+ }
}
void CXXNameMangler::mangleType(const DependentNameType *T) {
// Typename types are always nested
Out << 'N';
- mangleUnresolvedScope(T->getQualifier());
- mangleSourceName(T->getIdentifier());
+ if (T->getIdentifier()) {
+ mangleUnresolvedScope(T->getQualifier());
+ mangleSourceName(T->getIdentifier());
+ } else {
+ const TemplateSpecializationType *TST = T->getTemplateId();
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
+ TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ }
+
Out << 'E';
}
@@ -1279,17 +1365,33 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// ::= L <type <value float> E # floating literal
// ::= L <mangled-name> E # external name
switch (E->getStmtClass()) {
- default:
+ case Expr::NoStmtClass:
+#define EXPR(Type, Base)
+#define STMT(Type, Base) \
+ case Expr::Type##Class:
+#include "clang/AST/StmtNodes.def"
llvm_unreachable("unexpected statement kind");
break;
+ default: {
+ // As bad as this diagnostic is, it's better than crashing.
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(FullSourceLoc(E->getExprLoc(),
+ getASTContext().getSourceManager()),
+ DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ 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";
+ Out << 'E';
break;
}
@@ -1333,9 +1435,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
Out << "cv";
mangleType(CE->getType());
- if (N != 1) Out << "_";
+ if (N != 1) Out << '_';
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << "E";
+ if (N != 1) Out << 'E';
break;
}
@@ -1346,21 +1448,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
Out << "cv";
mangleType(CE->getType());
- if (N != 1) Out << "_";
+ if (N != 1) Out << '_';
for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
- if (N != 1) Out << "E";
+ 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->isSizeOf()) Out << 's';
+ else Out << 'a';
if (SAE->isArgumentType()) {
- Out << "t";
+ Out << 't';
mangleType(SAE->getArgumentType());
} else {
- Out << "z";
+ Out << 'z';
mangleExpression(SAE->getArgumentExpr());
}
break;
@@ -1474,9 +1576,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
break;
}
+ case Expr::CXXBindReferenceExprClass:
+ mangleExpression(cast<CXXBindReferenceExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::CXXBindTemporaryExprClass:
+ mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::CXXExprWithTemporariesClass:
+ mangleExpression(cast<CXXExprWithTemporaries>(E)->getSubExpr());
+ break;
+
case Expr::FloatingLiteralClass: {
const FloatingLiteral *FL = cast<FloatingLiteral>(E);
- Out << "L";
+ Out << 'L';
mangleType(FL->getType());
// TODO: avoid this copy with careful stream management.
@@ -1484,10 +1598,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
Out.write(Buffer.data(), Buffer.size());
- Out << "E";
+ Out << 'E';
break;
}
+ case Expr::CharacterLiteralClass:
+ Out << 'L';
+ mangleType(E->getType());
+ Out << cast<CharacterLiteral>(E)->getValue();
+ Out << 'E';
+ break;
+
+ case Expr::CXXBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
case Expr::IntegerLiteralClass:
mangleIntegerLiteral(E->getType(),
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
@@ -1535,23 +1662,37 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
}
+void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
+ NumTemplateArgs);
+
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(0, TemplateArgs[i]);
+ Out << 'E';
+}
+
void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgumentList &AL) {
// <template-args> ::= I <template-arg>+ E
- Out << "I";
+ Out << 'I';
for (unsigned i = 0, e = AL.size(); i != e; ++i)
mangleTemplateArg(PL.getParam(i), AL[i]);
- Out << "E";
+ Out << 'E';
}
void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
- Out << "I";
+ Out << 'I';
for (unsigned i = 0; i != NumTemplateArgs; ++i)
mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
- Out << "E";
+ Out << 'E';
}
void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
@@ -1569,7 +1710,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
break;
case TemplateArgument::Template:
assert(A.getAsTemplate().getAsTemplateDecl() &&
- "FIXME: Support dependent template names");
+ "Can't get dependent template names here");
mangleName(A.getAsTemplate().getAsTemplateDecl());
break;
case TemplateArgument::Expression:
@@ -1581,6 +1722,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
break;
case TemplateArgument::Declaration: {
+ assert(P && "Missing template parameter for declaration argument");
// <expr-primary> ::= L <mangled-name> E # external name
// Clang produces AST's where pointer-to-member-function expressions
@@ -1646,9 +1788,17 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
return mangleSubstitution(TypePtr);
}
+bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ return mangleSubstitution(
+ reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I =
- Substitutions.find(Ptr);
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr);
if (I == Substitutions.end())
return false;
@@ -1660,9 +1810,8 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
// <seq-id> is encoded in base-36, using digits and upper case letters.
char Buffer[10];
- char *BufferPtr = Buffer + 9;
+ char *BufferPtr = llvm::array_endof(Buffer);
- *BufferPtr = 0;
if (SeqID == 0) *--BufferPtr = '0';
while (SeqID) {
@@ -1674,7 +1823,9 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
SeqID /= 36;
}
- Out << 'S' << BufferPtr << '_';
+ Out << 'S'
+ << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
+ << '_';
}
return true;
@@ -1824,6 +1975,14 @@ void CXXNameMangler::addSubstitution(QualType T) {
addSubstitution(TypePtr);
}
+void CXXNameMangler::addSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return addSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
unsigned SeqID = Substitutions.size();
@@ -1925,7 +2084,7 @@ void MangleContext::mangleGuardVariable(const VarDecl *D,
Mangler.mangleName(D);
}
-void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD,
+void MangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Res);
@@ -1941,7 +2100,7 @@ void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
Mangler.mangleName(RD);
}
-void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= TC <type> <offset number> _ <base type>
@@ -1949,7 +2108,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
Mangler.getStream() << "_ZTC";
Mangler.mangleName(RD);
Mangler.getStream() << Offset;
- Mangler.getStream() << "_";
+ Mangler.getStream() << '_';
Mangler.mangleName(Type);
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 91a5e97b69c9..da3626fc5d37 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -68,17 +68,21 @@ private:
/// calls to the C++ name mangler.
class MangleContext {
ASTContext &Context;
+ Diagnostic &Diags;
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
unsigned Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
public:
- explicit MangleContext(ASTContext &Context)
- : Context(Context) { }
+ explicit MangleContext(ASTContext &Context,
+ Diagnostic &Diags)
+ : Context(Context), Diags(Diags) { }
ASTContext &getASTContext() const { return Context; }
+ Diagnostic &getDiags() const { return Diags; }
+
uint64_t getAnonymousStructId(const TagDecl *TD) {
std::pair<llvm::DenseMap<const TagDecl *,
uint64_t>::iterator, bool> Result =
@@ -99,9 +103,9 @@ public:
const ThisAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &);
void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
- void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
- void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,
llvm::SmallVectorImpl<char> &);
void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 59e8e77756cd..e1fdf86eb026 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -43,7 +43,8 @@ void ABIArgInfo::dump() const {
getCoerceToType()->print(OS);
break;
case Indirect:
- OS << "Indirect Align=" << getIndirectAlign();
+ OS << "Indirect Align=" << getIndirectAlign()
+ << " Byal=" << getIndirectByVal();
break;
case Expand:
OS << "Expand";
@@ -270,7 +271,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
llvm::LLVMContext &VMContext) const {
if (CodeGenFunction::hasAggregateLLVMType(Ty))
return ABIArgInfo::getIndirect(0);
-
+
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
@@ -291,8 +292,10 @@ class X86_32ABIInfo : public ABIInfo {
static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
- static unsigned getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context);
+ /// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be passed in memory.
+ ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context,
+ bool ByVal = true) const;
public:
ABIArgInfo classifyReturnType(QualType RetTy,
@@ -490,14 +493,19 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
}
}
-unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context) {
- unsigned Align = Context.getTypeAlign(Ty);
- if (Align < 128) return 0;
- if (const RecordType* RT = Ty->getAs<RecordType>())
- if (typeContainsSSEVector(RT->getDecl(), Context))
- return 16;
- return 0;
+ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty,
+ ASTContext &Context,
+ bool ByVal) const {
+ if (!ByVal)
+ return ABIArgInfo::getIndirect(0, false);
+
+ // Compute the byval alignment. We trust the back-end to honor the
+ // minimum ABI alignment for byval, to make cleaner IR.
+ const unsigned MinABIAlign = 4;
+ unsigned Align = Context.getTypeAlign(Ty) / 8;
+ if (Align > MinABIAlign)
+ return ABIArgInfo::getIndirect(Align);
+ return ABIArgInfo::getIndirect(0);
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
@@ -510,11 +518,10 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// 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);
-
+ return getIndirectResult(Ty, Context, /*ByVal=*/false);
+
if (RT->getDecl()->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
- Context));
+ return getIndirectResult(Ty, Context);
}
// Ignore empty structs.
@@ -529,7 +536,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
canExpandIndirectArgument(Ty, Context))
return ABIArgInfo::getExpand();
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
+ return getIndirectResult(Ty, Context);
} else {
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
@@ -685,9 +692,12 @@ class X86_64ABIInfo : public ABIInfo {
ASTContext &Context) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be returned in memory.
+ ABIArgInfo getIndirectReturnResult(QualType Ty, ASTContext &Context) const;
+
+ /// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty,
- ASTContext &Context) const;
+ ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context) const;
ABIArgInfo classifyReturnType(QualType RetTy,
ASTContext &Context,
@@ -1060,6 +1070,22 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
return ABIArgInfo::getCoerce(CoerceTo);
}
+ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(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)) {
+ // 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());
+ }
+
+ return ABIArgInfo::getIndirect(0);
+}
+
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
@@ -1073,10 +1099,16 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- // FIXME: Set alignment correctly.
- return ABIArgInfo::getIndirect(0, ByVal);
+ // Compute the byval alignment. We trust the back-end to honor the
+ // minimum ABI alignment for byval, to make cleaner IR.
+ const unsigned MinABIAlign = 8;
+ unsigned Align = Context.getTypeAlign(Ty) / 8;
+ if (Align > MinABIAlign)
+ return ABIArgInfo::getIndirect(Align);
+ return ABIArgInfo::getIndirect(0);
}
ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
@@ -1104,7 +1136,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
// hidden argument.
case Memory:
- return getIndirectResult(RetTy, Context);
+ return getIndirectReturnResult(RetTy, Context);
// AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
// available register of the sequence %rax, %rdx is used.
@@ -1126,7 +1158,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
// %st1.
case ComplexX87:
assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
- ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
+ ResType = llvm::StructType::get(VMContext,
+ llvm::Type::getX86_FP80Ty(VMContext),
llvm::Type::getX86_FP80Ty(VMContext),
NULL);
break;
@@ -1574,7 +1607,7 @@ ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(CGF.getLLVMContext()));
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
CGBuilderTy &Builder = CGF.Builder;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 921147f7a09b..7371a930c337 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -239,12 +239,8 @@ int Driver::ExecuteCompilation(const Compilation &C) const {
// other tools are less common, and they generally have worse diagnostics,
// so always print the diagnostic there.
const Action &Source = FailingCommand->getSource();
- bool IsFriendlyTool = (isa<PreprocessJobAction>(Source) ||
- isa<PrecompileJobAction>(Source) ||
- isa<AnalyzeJobAction>(Source) ||
- isa<CompileJobAction>(Source));
- if (!IsFriendlyTool || Res != 1) {
+ if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
// FIXME: See FIXME above regarding result code interpretation.
if (Res < 0)
Diag(clang::diag::err_drv_command_signalled)
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 105eab06af5f..1cd8ee186cae 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -217,6 +217,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const {
void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ std::string Tmp;
+
// FIXME: Derive these correctly.
if (getArchName() == "x86_64") {
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
@@ -225,10 +227,24 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
"/x86_64"));
}
+
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir));
+
+ Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir;
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
+ Tmp = getDriver().Dir + "/../lib/gcc";
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
// Intentionally duplicated for (temporary) gcc bug compatibility.
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir));
+ Tmp = getDriver().Dir + "/../lib/" + ToolChainDir;
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
+ Tmp = getDriver().Dir + "/../lib";
+ if (llvm::sys::Path(Tmp).exists())
+ CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
"/../../../" + ToolChainDir));
CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +
@@ -656,6 +672,11 @@ const char *Darwin::GetForcedPicModel() const {
return 0;
}
+bool Darwin::SupportsObjCGC() const {
+ // Garbage collection is supported everywhere except on iPhone OS.
+ return !isTargetIPhoneOS();
+}
+
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 0d5b2a3f4747..9acc950879d5 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -160,13 +160,20 @@ public:
return !isMacosxVersionLT(10, 6);
}
virtual bool IsObjCNonFragileABIDefault() const {
- // Non-fragile ABI default to on for iPhoneOS and x86-64.
- return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64;
+ // Non-fragile ABI is default for everything but i386.
+ return getTriple().getArch() != llvm::Triple::x86;
}
virtual bool IsObjCLegacyDispatchDefault() const {
// This is only used with the non-fragile ABI.
- return (getTriple().getArch() == llvm::Triple::arm ||
- getTriple().getArch() == llvm::Triple::thumb);
+
+ // Legacy dispatch is used everywhere except on x86_64.
+ return getTriple().getArch() != llvm::Triple::x86_64;
+ }
+ virtual bool UseObjCMixedDispatch() const {
+ // This is only used with the non-fragile ABI and non-legacy dispatch.
+
+ // Mixed dispatch is used everywhere except OS X before 10.6.
+ return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6));
}
virtual bool IsUnwindTablesDefault() const;
virtual unsigned GetDefaultStackProtectorLevel() const {
@@ -176,6 +183,8 @@ public:
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
+ virtual bool SupportsObjCGC() const;
+
virtual bool UseDwarfDebugFlags() const;
virtual bool UseSjLjExceptions() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 2a3799152ac8..176d491bc0ce 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -566,13 +566,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
- switch (getToolChain().getTriple().getOS()) {
- default:
- // Assume "soft", but warn the user we are guessing.
- FloatABI = "soft";
- D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
- break;
- }
+ // Assume "soft", but warn the user we are guessing.
+ FloatABI = "soft";
+ D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft";
}
if (FloatABI == "soft") {
@@ -623,6 +619,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
CPUName = "yonah";
+ } else if (getToolChain().getOS().startswith("haiku")) {
+ if (getToolChain().getArchName() == "x86_64")
+ CPUName = "x86-64";
+ else if (getToolChain().getArchName() == "i386")
+ CPUName = "i586";
} else {
if (getToolChain().getArchName() == "x86_64")
CPUName = "x86-64";
@@ -826,7 +827,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Add default argument set.
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-check-dead-stores");
- CmdArgs.push_back("-analyzer-check-security-syntactic");
+ // Do not enable the security-syntatic check since it
+ // it needs to be refined (known issues).
+ // CmdArgs.push_back("-analyzer-check-security-syntactic");
CmdArgs.push_back("-analyzer-check-objc-mem");
CmdArgs.push_back("-analyzer-eagerly-assume");
CmdArgs.push_back("-analyzer-check-objc-methodsigs");
@@ -1073,6 +1076,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ CmdArgs.push_back("-ferror-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("19");
+
+ CmdArgs.push_back("-ftemplate-backtrace-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("10");
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -1105,10 +1120,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
+ // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
+ // takes precedence.
+ const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
+ if (!GCArg)
+ GCArg = Args.getLastArg(options::OPT_fobjc_gc);
+ if (GCArg) {
+ if (getToolChain().SupportsObjCGC()) {
+ GCArg->render(Args, CmdArgs);
+ } else {
+ // FIXME: We should move this to a hard error.
+ D.Diag(clang::diag::warn_drv_objc_gc_unsupported)
+ << GCArg->getAsString(Args);
+ }
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
@@ -1150,11 +1178,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
- // -fno-access-control is default (for now).
- if (Args.hasFlag(options::OPT_faccess_control,
- options::OPT_fno_access_control,
+ // -faccess-control is default.
+ if (Args.hasFlag(options::OPT_fno_access_control,
+ options::OPT_faccess_control,
false))
- CmdArgs.push_back("-faccess-control");
+ CmdArgs.push_back("-fno-access-control");
// -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
@@ -1188,6 +1216,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
+ // -fgnu-keywords default varies depending on language; only pass if
+ // specified.
+ if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
+ options::OPT_fno_gnu_keywords))
+ A->render(Args, CmdArgs);
+
// -fnext-runtime is default.
if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
@@ -1195,16 +1229,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fobjc-nonfragile-abi=0 is default.
if (types::isObjC(InputType)) {
+ unsigned Version = 1;
if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
- getToolChain().IsObjCNonFragileABIDefault()) {
+ getToolChain().IsObjCNonFragileABIDefault())
+ Version = 2;
+ if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) {
+ if (llvm::StringRef(A->getValue(Args)) == "1")
+ Version = 1;
+ else if (llvm::StringRef(A->getValue(Args)) == "2")
+ Version = 2;
+ else
+ D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
+ }
+
+ if (Version == 2) {
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");
+
+ // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
+ // legacy is the default.
+ if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
+ options::OPT_fno_objc_legacy_dispatch,
+ getToolChain().IsObjCLegacyDispatchDefault())) {
+ if (getToolChain().UseObjCMixedDispatch())
+ CmdArgs.push_back("-fobjc-dispatch-method=mixed");
+ else
+ CmdArgs.push_back("-fobjc-dispatch-method=non-legacy");
+ }
}
}
@@ -1212,12 +1262,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
+ // -fconstant-cfstrings is default, and may be subject to argument translation
+ // on Darwin.
+ if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
+ options::OPT_fno_constant_cfstrings) ||
+ !Args.hasFlag(options::OPT_mconstant_cfstrings,
+ options::OPT_mno_constant_cfstrings))
+ CmdArgs.push_back("-fno-constant-cfstrings");
+
// -fshort-wchar default varies depending on platform; only
// pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
- if (A->getOption().matches(options::OPT_fshort_wchar))
- CmdArgs.push_back("-fshort-wchar");
- }
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar))
+ A->render(Args, CmdArgs);
// -fno-pascal-strings is default, only pass non-default. If the tool chain
// happened to translate to -mpascal-strings, we want to back translate here.
@@ -1305,8 +1361,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
+ // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
+ // parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
- Args.AddAllArgValues(CmdArgs, options::OPT_mllvm);
+ for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ it->claim();
+
+ // We translate this by hand to the -cc1 argument, since nightly test uses
+ // it and developers have been trained to spell it with -mllvm.
+ if (llvm::StringRef(it->getValue(Args, 0)) == "-disable-llvm-optzns")
+ CmdArgs.push_back("-disable-llvm-optzns");
+ else
+ it->render(Args, CmdArgs);
+ }
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
@@ -1363,10 +1431,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Claim some arguments which clang supports automatically.
- // -fpch-preprocess is used with gcc to add a special marker in the
- // -output to include the PCH file. Clang's PTH solution is
- // -completely transparent, so we do not need to deal with it at
- // -all.
+ // -fpch-preprocess is used with gcc to add a special marker in the output to
+ // include the PCH file. Clang's PTH solution is completely transparent, so we
+ // do not need to deal with it at all.
Args.ClaimAllArgs(options::OPT_fpch_preprocess);
// Claim some arguments which clang doesn't support, but we don't
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 7a8f1b7cb703..091fec380622 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -42,6 +42,7 @@ namespace tools {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedAssembler() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
@@ -79,6 +80,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return false; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -91,6 +93,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return false; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -103,6 +106,7 @@ namespace gcc {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
@@ -176,6 +180,7 @@ namespace darwin {
virtual bool acceptsPipedInput() const { return true; }
virtual bool canPipeOutput() const { return true; }
+ virtual bool hasGoodDiagnostics() const { return true; }
virtual bool hasIntegratedCPP() const { return true; }
};
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index ebbd720ceb63..7b8ebf92032e 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -24,7 +24,6 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "llvm/Module.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -165,7 +164,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
case Decl::Namespace: {
Out << "[namespace] ";
const NamespaceDecl* ND = cast<NamespaceDecl>(DC);
- Out << ND->getNameAsString();
+ Out << ND;
break;
}
case Decl::Enum: {
@@ -174,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[enum] ";
else
Out << "<enum> ";
- Out << ED->getNameAsString();
+ Out << ED;
break;
}
case Decl::Record: {
@@ -183,7 +182,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[struct] ";
else
Out << "<struct> ";
- Out << RD->getNameAsString();
+ Out << RD;
break;
}
case Decl::CXXRecord: {
@@ -192,7 +191,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[class] ";
else
Out << "<class> ";
- Out << RD->getNameAsString() << " " << DC;
+ Out << RD << ' ' << DC;
break;
}
case Decl::ObjCMethod:
@@ -225,7 +224,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "[function] ";
else
Out << "<function> ";
- Out << FD->getNameAsString();
+ Out << FD;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -235,7 +234,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
break;
@@ -248,7 +247,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ method) ";
else
Out << "<c++ method> ";
- Out << D->getNameAsString();
+ Out << D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -258,7 +257,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
@@ -278,7 +277,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ ctor) ";
else
Out << "<c++ ctor> ";
- Out << D->getNameAsString();
+ Out << D;
// Print the parameters.
Out << "(";
bool PrintComma = false;
@@ -288,7 +287,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << ", ";
else
PrintComma = true;
- Out << (*I)->getNameAsString();
+ Out << *I;
}
Out << ")";
@@ -307,7 +306,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ dtor) ";
else
Out << "<c++ dtor> ";
- Out << D->getNameAsString();
+ Out << D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -323,7 +322,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "(c++ conversion) ";
else
Out << "<c++ conversion> ";
- Out << D->getNameAsString();
+ Out << D;
// Check the semantic DC.
const DeclContext* SemaDC = D->getDeclContext();
const DeclContext* LexicalDC = D->getLexicalDeclContext();
@@ -370,42 +369,42 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::Field: {
FieldDecl* FD = cast<FieldDecl>(*I);
- Out << "<field> " << FD->getNameAsString() << "\n";
+ Out << "<field> " << FD << '\n';
break;
}
case Decl::Typedef: {
TypedefDecl* TD = cast<TypedefDecl>(*I);
- Out << "<typedef> " << TD->getNameAsString() << "\n";
+ Out << "<typedef> " << TD << '\n';
break;
}
case Decl::EnumConstant: {
EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
- Out << "<enum constant> " << ECD->getNameAsString() << "\n";
+ Out << "<enum constant> " << ECD << '\n';
break;
}
case Decl::Var: {
VarDecl* VD = cast<VarDecl>(*I);
- Out << "<var> " << VD->getNameAsString() << "\n";
+ Out << "<var> " << VD << '\n';
break;
}
case Decl::ImplicitParam: {
ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
- Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
+ Out << "<implicit parameter> " << IPD << '\n';
break;
}
case Decl::ParmVar: {
ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
- Out << "<parameter> " << PVD->getNameAsString() << "\n";
+ Out << "<parameter> " << PVD << '\n';
break;
}
case Decl::ObjCProperty: {
ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
- Out << "<objc property> " << OPD->getNameAsString() << "\n";
+ Out << "<objc property> " << OPD << '\n';
break;
}
case Decl::FunctionTemplate: {
FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
- Out << "<function template> " << FTD->getNameAsString() << "\n";
+ Out << "<function template> " << FTD << '\n';
break;
}
case Decl::FileScopeAsm: {
@@ -418,16 +417,16 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
}
case Decl::NamespaceAlias: {
NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
- Out << "<namespace alias> " << NAD->getNameAsString() << "\n";
+ Out << "<namespace alias> " << NAD << '\n';
break;
}
case Decl::ClassTemplate: {
ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
- Out << "<class template> " << CTD->getNameAsString() << '\n';
+ Out << "<class template> " << CTD << '\n';
break;
}
default:
- Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
+ Out << "DeclKind: " << DK << '"' << *I << "\"\n";
assert(0 && "decl unhandled");
}
}
@@ -437,150 +436,6 @@ ASTConsumer *clang::CreateDeclContextPrinter() {
}
//===----------------------------------------------------------------------===//
-/// RecordLayoutDumper - C++ Record Layout Dumping.
-namespace {
-class RecordLayoutDumper : public ASTConsumer {
- llvm::raw_ostream& Out;
-
- void PrintOffset(uint64_t Offset, unsigned IndentLevel) {
- Out << llvm::format("%4d | ", Offset);
- for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' ';
- }
-
- void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C,
- uint64_t Offset,
- unsigned IndentLevel, const char* Description,
- bool IncludeVirtualBases) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
-
- PrintOffset(Offset, IndentLevel);
- Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString();
- if (Description)
- Out << ' ' << Description;
- if (RD->isEmpty())
- Out << " (empty)";
- Out << '\n';
-
- IndentLevel++;
-
- const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
-
- // Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase) {
- PrintOffset(Offset, IndentLevel);
- Out << '(' << RD->getNameAsString() << " vtable pointer)\n";
- }
- // Dump (non-virtual) bases
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
-
- DumpRecordLayoutOffsets(Base, C, BaseOffset, IndentLevel,
- Base == PrimaryBase ? "(primary base)" : "(base)",
- /*IncludeVirtualBases=*/false);
- }
-
- // Dump fields.
- uint64_t FieldNo = 0;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I, ++FieldNo) {
- const FieldDecl *Field = *I;
- uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
-
- if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel,
- Field->getNameAsCString(),
- /*IncludeVirtualBases=*/true);
- continue;
- }
- }
-
- PrintOffset(FieldOffset, IndentLevel);
- Out << Field->getType().getAsString() << ' ';
- Out << Field->getNameAsString() << '\n';
- }
-
- if (!IncludeVirtualBases)
- return;
-
- // Dump virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- assert(I->isVirtual() && "Found non-virtual class!");
- const CXXRecordDecl *VBase =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
- DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel,
- VBase == PrimaryBase ?
- "(primary virtual base)" : "(virtual base)",
- /*IncludeVirtualBases=*/false);
- }
- }
-
- // FIXME: Maybe this could be useful in ASTContext.cpp.
- void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
-
- DumpRecordLayoutOffsets(RD, C, 0, 0, 0,
- /*IncludeVirtualBases=*/true);
- Out << " sizeof=" << Info.getSize() / 8;
- Out << ", dsize=" << Info.getDataSize() / 8;
- Out << ", align=" << Info.getAlignment() / 8 << '\n';
- Out << " nvsize=" << Info.getNonVirtualSize() / 8;
- Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
- Out << '\n';
- }
-
-public:
- RecordLayoutDumper() : Out(llvm::errs()) {}
-
- void HandleTranslationUnit(ASTContext &C) {
- for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
- I != E; ++I) {
- const RecordType *RT = dyn_cast<RecordType>(*I);
- if (!RT)
- continue;
-
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- continue;
-
- if (RD->isImplicit())
- continue;
-
- if (RD->isDependentType())
- continue;
-
- if (RD->isInvalidDecl())
- continue;
-
- if (!RD->getDefinition())
- continue;
-
- // FIXME: Do we really need to hard code this?
- if (RD->getQualifiedNameAsString() == "__va_list_tag")
- continue;
-
- DumpRecordLayout(RD, C);
- }
- }
-};
-} // end anonymous namespace
-ASTConsumer *clang::CreateRecordLayoutDumper() {
- return new RecordLayoutDumper();
-}
-
-//===----------------------------------------------------------------------===//
/// InheritanceViewer - C++ Inheritance Visualization
namespace {
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 427bd6a9b803..4730bdc2f161 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -265,8 +265,16 @@ public:
TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
- Unit.getTopLevelDecls().push_back(*it);
+ for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
+ Decl *D = *it;
+ // FIXME: Currently ObjC method declarations are incorrectly being
+ // reported as top-level declarations, even though their DeclContext
+ // is the containing ObjC @interface/@implementation. This is a
+ // fundamental problem in the parser right now.
+ if (isa<ObjCMethodDecl>(D))
+ continue;
+ Unit.getTopLevelDecls().push_back(D);
+ }
}
};
@@ -431,8 +439,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
const driver::ArgStringList &CCArgs = Cmd->getArguments();
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
- (const char**) CCArgs.data()+CCArgs.size(),
+ CompilerInvocation::CreateFromArgs(*CI,
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) +
+ CCArgs.size(),
*Diags);
// Override any files that need remapping
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index d764fd078968..87c3fca24962 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -41,10 +41,6 @@ using namespace clang;
static ExplodedNode::Auditor* CreateUbiViz();
//===----------------------------------------------------------------------===//
-// Basic type definitions.
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
// Special PathDiagnosticClients.
//===----------------------------------------------------------------------===//
@@ -62,20 +58,21 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class AnalysisConsumer : public ASTConsumer {
- public:
+class AnalysisConsumer : public ASTConsumer {
+public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
TranslationUnitDecl &TU);
- private:
+private:
typedef std::vector<CodeAction> Actions;
typedef std::vector<TUAction> TUActions;
Actions FunctionActions;
Actions ObjCMethodActions;
Actions ObjCImplementationActions;
- TUActions TranslationUnitActions;
+ Actions CXXMethodActions;
+ TUActions TranslationUnitActions; // Remove this.
public:
ASTContext* Ctx;
@@ -150,7 +147,7 @@ public:
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
- llvm::errs() << ' ' << ND->getNameAsString() << '\n';
+ llvm::errs() << ' ' << ND << '\n';
}
else if (isa<BlockDecl>(D)) {
llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
@@ -161,103 +158,100 @@ public:
void addCodeAction(CodeAction action) {
FunctionActions.push_back(action);
ObjCMethodActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
+ CXXMethodActions.push_back(action);
}
void addTranslationUnitAction(TUAction action) {
TranslationUnitActions.push_back(action);
}
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
+
virtual void Initialize(ASTContext &Context) {
Ctx = &Context;
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
PP.getLangOptions(), PD,
CreateStoreMgr, CreateConstraintMgr,
+ Opts.MaxNodes,
Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
Opts.PurgeDead, Opts.EagerlyAssume,
Opts.TrimGraph));
}
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
- declDisplayed = false;
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
- HandleTopLevelSingleDecl(*I);
- }
-
- void HandleTopLevelSingleDecl(Decl *D);
virtual void HandleTranslationUnit(ASTContext &C);
-
- void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+ void HandleCode(Decl *D, Stmt* Body, Actions& actions);
};
} // end anonymous namespace
-namespace llvm {
- template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
- static inline void Profile(AnalysisConsumer::CodeAction X,
- FoldingSetNodeID& ID) {
- ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
- }
- };
-}
-
//===----------------------------------------------------------------------===//
// AnalysisConsumer implementation.
//===----------------------------------------------------------------------===//
-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() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
-
- if (Stmt *Body = FD->getBody())
- HandleCode(FD, Body, FunctionActions);
- break;
- }
-
- case Decl::ObjCMethod: {
- ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
- return;
+ TranslationUnitDecl *TU = C.getTranslationUnitDecl();
- if (Stmt* Body = MD->getBody())
- HandleCode(MD, Body, ObjCMethodActions);
- break;
- }
+ for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
+ I != E; ++I) {
+ Decl *D = *I;
+
+ switch (D->getKind()) {
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod:
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
+
+ if (FD->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+ break;
+ HandleCode(FD, FD->getBody(), FunctionActions);
+ }
+ break;
+ }
- default:
- break;
- }
-}
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+
+ if (MD->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ break;
+ HandleCode(MD, MD->getBody(), ObjCMethodActions);
+ }
+ break;
+ }
-void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+ case Decl::ObjCImplementation: {
+ ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
+ HandleCode(ID, 0, ObjCImplementationActions);
+
+ for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
+ ME = ID->meth_end(); MI != ME; ++MI) {
+ if ((*MI)->isThisDeclarationADefinition()) {
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
+ break;
+ HandleCode(*MI, (*MI)->getBody(), ObjCMethodActions);
+ }
+ }
+ break;
+ }
- TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+ default:
+ break;
+ }
+ }
for (TUActions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I) {
(*I)(*this, *Mgr, *TU);
}
- if (!ObjCImplementationActions.empty()) {
- for (DeclContext::decl_iterator I = TU->decls_begin(),
- E = TU->decls_end();
- I != E; ++I)
- if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
- HandleCode(ID, 0, ObjCImplementationActions);
- }
-
// Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when
@@ -278,7 +272,8 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Don't run the actions if an error has occured with parsing the file.
- if (PP.getDiagnostics().hasErrorOccurred())
+ Diagnostic &Diags = PP.getDiagnostics();
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
// Don't run the actions on declarations in header files unless
@@ -310,7 +305,6 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (LiveVariables *L = mgr.getLiveVariables(D)) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
}
@@ -319,7 +313,6 @@ static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (CFG* c = mgr.getCFG(D)) {
- C.DisplayFunction(D);
CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
}
}
@@ -331,15 +324,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
llvm::OwningPtr<GRTransferFuncs> TF(tf);
- // Display progress.
- C.DisplayFunction(D);
-
// Construct the analysis engine. We first query for the LiveVariables
// information to see if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
if (!mgr.getLiveVariables(D))
return;
-
GRExprEngine Eng(mgr, TF.take());
if (C.Opts.EnableExperimentalInternalChecks)
@@ -358,7 +347,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
}
// Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
+ Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes());
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
@@ -406,28 +395,24 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
static void ActionDisplayLiveVariables(AnalysisConsumer &C,
AnalysisManager& mgr, Decl *D) {
if (LiveVariables* L = mgr.getLiveVariables(D)) {
- C.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) {
- C.DisplayFunction(D);
cfg->dump(mgr.getLangOptions());
}
}
static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
if (CFG *cfg = mgr.getCFG(D)) {
- C.DisplayFunction(D);
cfg->viewCFG(mgr.getLangOptions());
}
}
static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
AnalysisManager &mgr, Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSecuritySyntaxOnly(D, BR);
}
@@ -443,86 +428,28 @@ static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return;
-
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
}
static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
}
static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
Decl *D) {
- C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSizeofPointer(D, BR);
}
-static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
- 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);
-
- // FIXME: Make a fake transfer function. The GRTransferFunc interface
- // eventually will be removed.
- GRExprEngine Eng(mgr, new GRTransferFuncs());
-
- if (C.Opts.EnableExperimentalInternalChecks)
- RegisterExperimentalInternalChecks(Eng);
-
- RegisterAppleChecks(Eng, *D);
-
- if (C.Opts.EnableExperimentalChecks)
- RegisterExperimentalChecks(Eng);
-
- // Register call inliner as the last checker.
- RegisterCallInliner(Eng);
-
- // Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
-
- // Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
-
- // Display warnings.
- Eng.getBugReporter().FlushReports();
-}
-
//===----------------------------------------------------------------------===//
// AnalysisConsumer creation.
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index d069e8f42f26..a5fcebe99411 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -475,7 +475,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) {
if (!P.isAbsolute())
continue;
- const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics());
+ const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM);
if (!B) continue;
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
@@ -550,8 +550,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
// Lex through the entire file. This will populate SourceManager with
// all of the header information.
Token Tok;
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
// Generate the PTH file.
diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp
index b1795a3aa3b5..79d7d5f4c241 100644
--- a/lib/Frontend/CodeGenAction.cpp
+++ b/lib/Frontend/CodeGenAction.cpp
@@ -8,16 +8,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CodeGenAction.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TargetOptions.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
@@ -28,6 +30,8 @@
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
#include "llvm/Target/SubtargetFeature.h"
@@ -87,7 +91,7 @@ namespace {
const LangOptions &langopts, const CodeGenOptions &compopts,
const TargetOptions &targetopts, bool TimePasses,
const std::string &infile, llvm::raw_ostream *OS,
- LLVMContext& C) :
+ LLVMContext &C) :
Diags(_Diags),
Action(action),
CodeGenOpts(compopts),
@@ -175,6 +179,15 @@ namespace {
virtual void CompleteTentativeDefinition(VarDecl *D) {
Gen->CompleteTentativeDefinition(D);
}
+
+ static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
+ unsigned LocCookie) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);
+ ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
+ }
+
+ void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
+ SourceLocation LocCookie);
};
}
@@ -211,127 +224,122 @@ bool BackendConsumer::AddEmitPasses() {
if (Action == Backend_EmitBC) {
getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream));
- } else if (Action == Backend_EmitLL) {
+ return true;
+ }
+
+ if (Action == Backend_EmitLL) {
getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
+ return true;
+ }
+
+ bool Fast = CodeGenOpts.OptimizationLevel == 0;
+
+ // Create the TargetMachine for generating code.
+ std::string Error;
+ std::string Triple = TheModule->getTargetTriple();
+ const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
+ if (!TheTarget) {
+ Diags.Report(diag::err_fe_unable_to_create_target) << Error;
+ return false;
+ }
+
+ // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
+ // being gross, this is also totally broken if we ever care about
+ // concurrency.
+ llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim;
+ if (CodeGenOpts.FloatABI == "soft")
+ llvm::FloatABIType = llvm::FloatABI::Soft;
+ else if (CodeGenOpts.FloatABI == "hard")
+ llvm::FloatABIType = llvm::FloatABI::Hard;
+ else {
+ assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
+ llvm::FloatABIType = llvm::FloatABI::Default;
+ }
+ NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
+ llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
+ UnwindTablesMandatory = CodeGenOpts.UnwindTables;
+
+ TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
+
+ TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections);
+ TargetMachine::setDataSections (CodeGenOpts.DataSections);
+
+ // FIXME: Parse this earlier.
+ if (CodeGenOpts.RelocationModel == "static") {
+ TargetMachine::setRelocationModel(llvm::Reloc::Static);
+ } else if (CodeGenOpts.RelocationModel == "pic") {
+ TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
} else {
- bool Fast = CodeGenOpts.OptimizationLevel == 0;
-
- // Create the TargetMachine for generating code.
- std::string Error;
- std::string Triple = TheModule->getTargetTriple();
- const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
- if (!TheTarget) {
- Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return false;
- }
+ assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
+ "Invalid PIC model!");
+ TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
+ }
+ // FIXME: Parse this earlier.
+ if (CodeGenOpts.CodeModel == "small") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Small);
+ } else if (CodeGenOpts.CodeModel == "kernel") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
+ } else if (CodeGenOpts.CodeModel == "medium") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Medium);
+ } else if (CodeGenOpts.CodeModel == "large") {
+ TargetMachine::setCodeModel(llvm::CodeModel::Large);
+ } else {
+ assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
+ TargetMachine::setCodeModel(llvm::CodeModel::Default);
+ }
- // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
- // being gross, this is also totally broken if we ever care about
- // concurrency.
- llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim;
- if (CodeGenOpts.FloatABI == "soft")
- llvm::FloatABIType = llvm::FloatABI::Soft;
- else if (CodeGenOpts.FloatABI == "hard")
- llvm::FloatABIType = llvm::FloatABI::Hard;
- else {
- assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!");
- llvm::FloatABIType = llvm::FloatABI::Default;
- }
- NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
- UnwindTablesMandatory = CodeGenOpts.UnwindTables;
-
- TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
-
- // FIXME: Parse this earlier.
- if (CodeGenOpts.RelocationModel == "static") {
- TargetMachine::setRelocationModel(llvm::Reloc::Static);
- } else if (CodeGenOpts.RelocationModel == "pic") {
- TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
- } else {
- assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" &&
- "Invalid PIC model!");
- TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC);
- }
- // FIXME: Parse this earlier.
- if (CodeGenOpts.CodeModel == "small") {
- TargetMachine::setCodeModel(llvm::CodeModel::Small);
- } else if (CodeGenOpts.CodeModel == "kernel") {
- TargetMachine::setCodeModel(llvm::CodeModel::Kernel);
- } else if (CodeGenOpts.CodeModel == "medium") {
- TargetMachine::setCodeModel(llvm::CodeModel::Medium);
- } else if (CodeGenOpts.CodeModel == "large") {
- TargetMachine::setCodeModel(llvm::CodeModel::Large);
- } else {
- assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
- TargetMachine::setCodeModel(llvm::CodeModel::Default);
- }
+ std::vector<const char *> BackendArgs;
+ BackendArgs.push_back("clang"); // Fake program name.
+ if (!CodeGenOpts.DebugPass.empty()) {
+ BackendArgs.push_back("-debug-pass");
+ BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
+ }
+ if (!CodeGenOpts.LimitFloatPrecision.empty()) {
+ BackendArgs.push_back("-limit-float-precision");
+ BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
+ }
+ if (llvm::TimePassesIsEnabled)
+ BackendArgs.push_back("-time-passes");
+ BackendArgs.push_back(0);
+ llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
+ const_cast<char **>(&BackendArgs[0]));
+
+ std::string FeaturesStr;
+ if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
+ SubtargetFeatures Features;
+ Features.setCPU(TargetOpts.CPU);
+ for (std::vector<std::string>::const_iterator
+ it = TargetOpts.Features.begin(),
+ ie = TargetOpts.Features.end(); it != ie; ++it)
+ Features.AddFeature(*it);
+ FeaturesStr = Features.getString();
+ }
+ TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
- std::vector<const char *> BackendArgs;
- BackendArgs.push_back("clang"); // Fake program name.
- if (!CodeGenOpts.DebugPass.empty()) {
- BackendArgs.push_back("-debug-pass");
- BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
- }
- if (!CodeGenOpts.LimitFloatPrecision.empty()) {
- BackendArgs.push_back("-limit-float-precision");
- BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
- }
- if (llvm::TimePassesIsEnabled)
- BackendArgs.push_back("-time-passes");
- BackendArgs.push_back(0);
- llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
- (char**) &BackendArgs[0]);
-
- std::string FeaturesStr;
- if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
- SubtargetFeatures Features;
- Features.setCPU(TargetOpts.CPU);
- for (std::vector<std::string>::const_iterator
- it = TargetOpts.Features.begin(),
- ie = TargetOpts.Features.end(); it != ie; ++it)
- Features.AddFeature(*it);
- FeaturesStr = Features.getString();
- }
- TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr);
-
- // Set register scheduler & allocation policy.
- RegisterScheduler::setDefault(createDefaultScheduler);
- RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
- createLinearScanRegisterAllocator);
-
- // From llvm-gcc:
- // If there are passes we have to run on the entire module, we do codegen
- // as a separate "pass" after that happens.
- // FIXME: This is disabled right now until bugs can be worked out. Reenable
- // this for fast -O0 compiles!
- FunctionPassManager *PM = getCodeGenPasses();
- CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
-
- switch (CodeGenOpts.OptimizationLevel) {
- default: break;
- case 0: OptLevel = CodeGenOpt::None; break;
- case 3: OptLevel = CodeGenOpt::Aggressive; break;
- }
+ // Set register scheduler & allocation policy.
+ RegisterScheduler::setDefault(createDefaultScheduler);
+ RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
+ createLinearScanRegisterAllocator);
- // Request that addPassesToEmitFile run the Verifier after running
- // passes which modify the IR.
-#ifndef NDEBUG
- bool DisableVerify = false;
-#else
- bool DisableVerify = true;
-#endif
-
- // 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,
- DisableVerify)) {
- Diags.Report(diag::err_fe_unable_to_interface_with_target);
- return false;
- }
+ // Create the code generator passes.
+ FunctionPassManager *PM = getCodeGenPasses();
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+
+ switch (CodeGenOpts.OptimizationLevel) {
+ default: break;
+ case 0: OptLevel = CodeGenOpt::None; break;
+ case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ }
+
+ // 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,
+ /*DisableVerify=*/!CodeGenOpts.VerifyModule)) {
+ Diags.Report(diag::err_fe_unable_to_interface_with_target);
+ return false;
}
return true;
@@ -432,14 +440,81 @@ void BackendConsumer::EmitAssembly() {
if (CodeGenPasses) {
PrettyStackTraceString CrashInfo("Code generation");
+
+ // Install an inline asm handler so that diagnostics get printed through our
+ // diagnostics hooks.
+ LLVMContext &Ctx = TheModule->getContext();
+ void *OldHandler = Ctx.getInlineAsmDiagnosticHandler();
+ void *OldContext = Ctx.getInlineAsmDiagnosticContext();
+ Ctx.setInlineAsmDiagnosticHandler((void*)(intptr_t)InlineAsmDiagHandler,
+ this);
+
CodeGenPasses->doInitialization();
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
if (!I->isDeclaration())
CodeGenPasses->run(*I);
CodeGenPasses->doFinalization();
+
+ Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
}
}
+/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr
+/// buffer to be a valid FullSourceLoc.
+static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
+ SourceManager &CSM) {
+ // Get both the clang and llvm source managers. The location is relative to
+ // a memory buffer that the LLVM Source Manager is handling, we need to add
+ // a copy to the Clang source manager.
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+
+ // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr
+ // already owns its one and clang::SourceManager wants to own its one.
+ const MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+
+ // Create the copy and transfer ownership to clang::SourceManager.
+ llvm::MemoryBuffer *CBuf =
+ llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
+ LBuf->getBufferIdentifier());
+ FileID FID = CSM.createFileIDForMemBuffer(CBuf);
+
+ // Translate the offset into the file.
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+ SourceLocation NewLoc =
+ CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset);
+ return FullSourceLoc(NewLoc, CSM);
+}
+
+
+/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an
+/// error parsing inline asm. The SMDiagnostic indicates the error relative to
+/// the temporary memory buffer that the inline asm parser has set up.
+void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
+ SourceLocation LocCookie) {
+ // There are a couple of different kinds of errors we could get here. First,
+ // we re-format the SMDiagnostic in terms of a clang diagnostic.
+
+ // Strip "error: " off the start of the message string.
+ llvm::StringRef Message = D.getMessage();
+ if (Message.startswith("error: "))
+ Message = Message.substr(7);
+
+ // There are two cases: the SMDiagnostic could have a inline asm source
+ // location or it might not. If it does, translate the location.
+ FullSourceLoc Loc;
+ if (D.getLoc() != SMLoc())
+ Loc = ConvertBackendLocation(D, Context->getSourceManager());
+ Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message);
+
+ // This could be a problem with no clang-level source location information.
+ // In this case, LocCookie is invalid. If there is source level information,
+ // print an "generated from" note.
+ if (LocCookie.isValid())
+ Diags.Report(FullSourceLoc(LocCookie, Context->getSourceManager()),
+ diag::note_fe_inline_asm_here);
+}
+
//
CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 1f915e3713d3..5ed9c409a3dc 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -513,11 +513,20 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
}
}
- if (getDiagnosticOpts().ShowCarets)
- if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics())
- OS << NumDiagnostics << " diagnostic"
- << (NumDiagnostics == 1 ? "" : "s")
- << " generated.\n";
+ if (getDiagnosticOpts().ShowCarets) {
+ unsigned NumWarnings = getDiagnostics().getNumWarnings();
+ unsigned NumErrors = getDiagnostics().getNumErrors() -
+ getDiagnostics().getNumErrorsSuppressed();
+
+ if (NumWarnings)
+ OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s");
+ if (NumWarnings && NumErrors)
+ OS << " and ";
+ if (NumErrors)
+ OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s");
+ if (NumWarnings || NumErrors)
+ OS << " generated.\n";
+ }
if (getFrontendOpts().ShowStats) {
getFileManager().PrintStats();
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index dc2c6bf3614a..8ffdde2aa9b5 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -145,9 +145,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
// TimePasses is only derived.
// UnitAtATime is unused.
// UnrollLoops is only derived.
- // VerifyModule is only derived.
// Inlining is only derived.
+ if (Opts.DataSections)
+ Res.push_back("-fdata-sections");
+ if (Opts.FunctionSections)
+ Res.push_back("-ffunction-sections");
if (Opts.AsmVerbose)
Res.push_back("-masm-verbose");
if (!Opts.CodeModel.empty()) {
@@ -174,8 +177,16 @@ 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");
+ switch (Opts.getObjCDispatchMethod()) {
+ case CodeGenOptions::Legacy:
+ break;
+ case CodeGenOptions::Mixed:
+ Res.push_back("-fobjc-dispatch-method=mixed");
+ break;
+ case CodeGenOptions::NonLegacy:
+ Res.push_back("-fobjc-dispatch-method=non-legacy");
+ break;
+ }
if (Opts.SoftFloat)
Res.push_back("-msoft-float");
if (Opts.UnwindTables)
@@ -232,6 +243,15 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fdiagnostics-binary");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
+ if (Opts.ErrorLimit) {
+ Res.push_back("-ferror-limit");
+ Res.push_back(llvm::utostr(Opts.ErrorLimit));
+ }
+ if (Opts.TemplateBacktraceLimit != 10) {
+ Res.push_back("-ftemplate-backtrace-limit");
+ Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
+ }
+
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
Res.push_back("-ftabstop");
Res.push_back(llvm::utostr(Opts.TabStop));
@@ -279,7 +299,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
case frontend::ASTPrintXML: return "-ast-print-xml";
case frontend::ASTView: return "-ast-view";
case frontend::DumpRawTokens: return "-dump-raw-tokens";
- case frontend::DumpRecordLayouts: return "-dump-record-layouts";
case frontend::DumpTokens: return "-dump-tokens";
case frontend::EmitAssembly: return "-S";
case frontend::EmitBC: return "-emit-llvm-bc";
@@ -349,12 +368,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-cxx-inheritance-view");
Res.push_back(Opts.ViewClassInheritance);
}
- for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) {
- Res.push_back("-fixit-at");
- Res.push_back(Opts.FixItLocations[i].FileName + ":" +
- llvm::utostr(Opts.FixItLocations[i].Line) + ":" +
- llvm::utostr(Opts.FixItLocations[i].Column));
- }
if (!Opts.CodeCompletionAt.FileName.empty()) {
Res.push_back("-code-completion-at");
Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
@@ -376,6 +389,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
Res.push_back("-ast-merge");
Res.push_back(Opts.ASTMergeFiles[i]);
}
+ for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) {
+ Res.push_back("-mllvm");
+ Res.push_back(Opts.LLVMArgs[i]);
+ }
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
@@ -389,7 +406,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied))
- llvm::llvm_report_error("Invalid option set!");
+ llvm::report_fatal_error("Invalid option set!");
if (E.IsUserSupplied) {
if (E.Group == frontend::After) {
Res.push_back("-idirafter");
@@ -403,7 +420,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
}
} else {
if (E.Group != frontend::Angled && E.Group != frontend::System)
- llvm::llvm_report_error("Invalid option set!");
+ llvm::report_fatal_error("Invalid option set!");
Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
"-iwithprefix");
}
@@ -412,23 +429,23 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
if (!Opts.EnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.CEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ObjCEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.CXXEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ObjCXXEnvIncPath.empty()) {
// FIXME: Provide an option for this, and move env detection to driver.
- llvm::llvm_report_error("Not yet implemented!");
+ llvm::report_fatal_error("Not yet implemented!");
}
if (!Opts.ResourceDir.empty()) {
Res.push_back("-resource-dir");
@@ -462,6 +479,10 @@ static void LangOptsToArgs(const LangOptions &Opts,
// BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
if (Opts.DollarIdents)
Res.push_back("-fdollars-in-identifiers");
+ if (Opts.GNUMode && !Opts.GNUKeywords)
+ Res.push_back("-fno-gnu-keywords");
+ if (!Opts.GNUMode && Opts.GNUKeywords)
+ Res.push_back("-fgnu-keywords");
if (Opts.Microsoft)
Res.push_back("-fms-extensions");
if (Opts.ObjCNonFragileABI)
@@ -515,15 +536,24 @@ static void LangOptsToArgs(const LangOptions &Opts,
// OptimizeSize is implicit.
if (Opts.Static)
Res.push_back("-static-define");
+ if (Opts.DumpRecordLayouts)
+ Res.push_back("-fdump-record-layouts");
+ if (Opts.DumpVTableLayouts)
+ Res.push_back("-fdump-vtable-layouts");
+ if (Opts.NoBitFieldTypeAlign)
+ Res.push_back("-fno-bitfield-type-alignment");
+ if (Opts.SjLjExceptions)
+ Res.push_back("-fsjlj-exceptions");
if (Opts.PICLevel) {
Res.push_back("-pic-level");
Res.push_back(llvm::utostr(Opts.PICLevel));
}
if (Opts.ObjCGCBitmapPrint)
Res.push_back("-print-ivar-layout");
- // FIXME: Don't forget to update when the default changes!
- if (Opts.AccessControl)
- Res.push_back("-faccess-control");
+ if (Opts.NoConstantCFStrings)
+ Res.push_back("-fno-constant-cfstrings");
+ if (!Opts.AccessControl)
+ Res.push_back("-fno-access-control");
if (!Opts.CharIsSigned)
Res.push_back("-fno-signed-char");
if (Opts.ShortWChar)
@@ -606,7 +636,7 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
std::vector<std::string> &Res) {
if (!Opts.ShowCPP && !Opts.ShowMacros)
- llvm::llvm_report_error("Invalid option combination!");
+ llvm::report_fatal_error("Invalid option combination!");
if (Opts.ShowCPP && Opts.ShowMacros)
Res.push_back("-dD");
@@ -756,6 +786,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.EnableExperimentalInternalChecks =
Args.hasArg(OPT_analyzer_experimental_internal_checks);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
+ Opts.MaxNodes = getLastArgIntValue(Args, OPT_analyzer_max_nodes,150000,Diags);
}
static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
@@ -796,13 +827,28 @@ 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.FunctionSections = Args.hasArg(OPT_ffunction_sections);
+ Opts.DataSections = Args.hasArg(OPT_fdata_sections);
+
Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+
+ if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
+ llvm::StringRef Name = A->getValue(Args);
+ unsigned Method = llvm::StringSwitch<unsigned>(Name)
+ .Case("legacy", CodeGenOptions::Legacy)
+ .Case("non-legacy", CodeGenOptions::NonLegacy)
+ .Case("mixed", CodeGenOptions::Mixed)
+ .Default(~0U);
+ if (Method == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ else
+ Opts.ObjCDispatchMethod = Method;
+ }
}
static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
@@ -830,6 +876,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
+ Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
+ Opts.TemplateBacktraceLimit
+ = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, 0, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
@@ -860,8 +909,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::ASTView; break;
case OPT_dump_raw_tokens:
Opts.ProgramAction = frontend::DumpRawTokens; break;
- case OPT_dump_record_layouts:
- Opts.ProgramAction = frontend::DumpRecordLayouts; break;
case OPT_dump_tokens:
Opts.ProgramAction = frontend::DumpTokens; break;
case OPT_S:
@@ -876,6 +923,9 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ProgramAction = frontend::EmitLLVMOnly; break;
case OPT_emit_obj:
Opts.ProgramAction = frontend::EmitObj; break;
+ case OPT_fixit_EQ:
+ Opts.FixItSuffix = A->getValue(Args);
+ // fall-through!
case OPT_fixit:
Opts.ProgramAction = frontend::FixIt; break;
case OPT_emit_pch:
@@ -922,20 +972,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
!Args.hasArg(OPT_no_code_completion_debug_printer);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
- Opts.FixItLocations.clear();
- for (arg_iterator it = Args.filtered_begin(OPT_fixit_at),
- ie = Args.filtered_end(); it != ie; ++it) {
- const char *Loc = it->getValue(Args);
- ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc);
-
- if (PSL.FileName.empty()) {
- Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc;
- continue;
- }
-
- Opts.FixItLocations.push_back(PSL);
- }
-
Opts.OutputFile = getLastArgValue(Args, OPT_o);
Opts.Plugins = getAllArgValues(Args, OPT_load);
Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch);
@@ -946,6 +982,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) {
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view);
Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge);
+ Opts.LLVMArgs = getAllArgValues(Args, OPT_mllvm);
FrontendOptions::InputKind DashX = FrontendOptions::IK_None;
if (const Arg *A = Args.getLastArg(OPT_x)) {
@@ -1129,6 +1166,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension
+ // keywords. This behavior is provided by GCC's poorly named '-fasm' flag,
+ // while a subset (the non-C++ GNU keywords) is provided by GCC's
+ // '-fgnu-keywords'. Clang conflates the two for simplicity under the single
+ // name, as it doesn't seem a useful distinction.
+ Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
+ Opts.GNUMode);
+
if (Opts.CPlusPlus)
Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
@@ -1139,6 +1184,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_print_ivar_layout))
Opts.ObjCGCBitmapPrint = 1;
+ if (Args.hasArg(OPT_fno_constant_cfstrings))
+ Opts.NoConstantCFStrings = 1;
if (Args.hasArg(OPT_faltivec))
Opts.AltiVec = 1;
@@ -1186,10 +1233,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
- Opts.AccessControl = Args.hasArg(OPT_faccess_control);
+ Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
Opts.MathErrno = Args.hasArg(OPT_fmath_errno);
- Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
+ Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 1024,
Diags);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
Opts.ObjCConstantStringClass = getLastArgValue(Args,
@@ -1203,7 +1250,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
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.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
+ Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
+ Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
Opts.OptimizeSize = 0;
// FIXME: Eliminate this dependency.
@@ -1268,6 +1317,10 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.Includes.push_back(it->getValue(Args));
}
+ // Include 'altivec.h' if -faltivec option present
+ if (Args.hasArg(OPT_faltivec))
+ Opts.Includes.push_back("altivec.h");
+
for (arg_iterator it = Args.filtered_begin(OPT_remap_file),
ie = Args.filtered_end(); it != ie; ++it) {
std::pair<llvm::StringRef,llvm::StringRef> Split =
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 20d452e76a64..7c9a566b6f7f 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -14,6 +14,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
@@ -24,8 +26,12 @@
using namespace clang;
FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
- const LangOptions &LangOpts)
- : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) {
+ const LangOptions &LangOpts,
+ FixItPathRewriter *PathRewriter)
+ : Diags(Diags),
+ Rewrite(SourceMgr, LangOpts),
+ PathRewriter(PathRewriter),
+ NumFailures(0) {
Client = Diags.getClient();
Diags.setClient(this);
}
@@ -34,92 +40,53 @@ FixItRewriter::~FixItRewriter() {
Diags.setClient(Client);
}
-bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
- const std::string &OutFileName) {
+bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) {
+ const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID);
+ if (!RewriteBuf) return true;
+ RewriteBuf->write(OS);
+ OS.flush();
+ return false;
+}
+
+bool FixItRewriter::WriteFixedFiles() {
if (NumFailures > 0) {
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
return true;
}
- llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
- llvm::raw_ostream *OutFile;
- if (!OutFileName.empty()) {
- std::string Err;
- OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary);
- OwnedStream.reset(OutFile);
- } else if (InFileName == "-") {
- OutFile = &llvm::outs();
- } else {
- llvm::sys::Path Path(InFileName);
- std::string Suffix = Path.getSuffix();
- Path.eraseSuffix();
- Path.appendSuffix("fixit." + Suffix);
+ for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
+ const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
+ std::string Filename = Entry->getName();
+ if (PathRewriter)
+ Filename = PathRewriter->RewriteFilename(Filename);
std::string Err;
- OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err,
- llvm::raw_fd_ostream::F_Binary);
- OwnedStream.reset(OutFile);
- }
-
- FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
- if (const RewriteBuffer *RewriteBuf =
- Rewrite.getRewriteBufferFor(MainFileID)) {
- *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
- } else {
- Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged);
+ llvm::raw_fd_ostream OS(Filename.c_str(), Err,
+ llvm::raw_fd_ostream::F_Binary);
+ if (!Err.empty()) {
+ Diags.Report(clang::diag::err_fe_unable_to_open_output)
+ << Filename << Err;
+ continue;
+ }
+ RewriteBuffer &RewriteBuf = I->second;
+ RewriteBuf.write(OS);
+ OS.flush();
}
- OutFile->flush();
return false;
}
bool FixItRewriter::IncludeInDiagnosticCounts() const {
- return Client? Client->IncludeInDiagnosticCounts() : true;
+ return Client ? Client->IncludeInDiagnosticCounts() : true;
}
void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
Client->HandleDiagnostic(DiagLevel, Info);
- // Skip over any diagnostics that are ignored.
- if (DiagLevel == Diagnostic::Ignored)
+ // Skip over any diagnostics that are ignored or notes.
+ if (DiagLevel <= Diagnostic::Note)
return;
- if (!FixItLocations.empty()) {
- // The user has specified the locations where we should perform
- // the various fix-it modifications.
-
- // If this diagnostic does not have any code modifications,
- // completely ignore it, even if it's an error: fix-it locations
- // are meant to perform specific fix-ups even in the presence of
- // other errors.
- if (Info.getNumFixItHints() == 0)
- return;
-
- // See if the location of the error is one that matches what the
- // user requested.
- bool AcceptableLocation = false;
- const FileEntry *File
- = Rewrite.getSourceMgr().getFileEntryForID(
- Info.getLocation().getFileID());
- unsigned Line = Info.getLocation().getSpellingLineNumber();
- unsigned Column = Info.getLocation().getSpellingColumnNumber();
- for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
- Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
- Loc != LocEnd; ++Loc) {
- if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
- AcceptableLocation = true;
- break;
- }
- }
-
- if (!AcceptableLocation)
- return;
- } else if (DiagLevel == Diagnostic::Note) {
- // Don't apply fix-it modifications in notes.
- return;
- }
-
// Make sure that we can perform all of the modifications we
// in this diagnostic.
bool CanRewrite = Info.getNumFixItHints() > 0;
@@ -196,3 +163,5 @@ void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) {
Diags.Report(Loc, DiagID);
Diags.setClient(this);
}
+
+FixItPathRewriter::~FixItPathRewriter() {}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 251b8e4cb738..6cd960be20d5 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -19,6 +19,7 @@
#include "clang/Frontend/FixItRewriter.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -74,11 +75,6 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
return CreateDeclContextPrinter();
}
-ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return CreateRecordLayoutDumper();
-}
-
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
@@ -118,43 +114,38 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
return new ASTConsumer();
}
-/// AddFixItLocations - Add any individual user specified "fix-it" locations,
-/// and return true on success.
-static bool AddFixItLocations(CompilerInstance &CI,
- FixItRewriter &FixItRewrite) {
- const std::vector<ParsedSourceLocation> &Locs =
- CI.getFrontendOpts().FixItLocations;
- for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
- const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
- if (!File) {
- CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
- << Locs[i].FileName;
- return false;
- }
-
- RequestedSourceLocation Requested;
- Requested.File = File;
- Requested.Line = Locs[i].Line;
- Requested.Column = Locs[i].Column;
- FixItRewrite.addFixItLocation(Requested);
- }
+class FixItActionSuffixInserter : public FixItPathRewriter {
+ std::string NewSuffix;
- return true;
-}
+public:
+ explicit FixItActionSuffixInserter(std::string NewSuffix)
+ : NewSuffix(NewSuffix) {}
+
+ std::string RewriteFilename(const std::string &Filename) {
+ llvm::sys::Path Path(Filename);
+ std::string Suffix = Path.getSuffix();
+ Path.eraseSuffix();
+ Path.appendSuffix(NewSuffix + "." + Suffix);
+ return Path.c_str();
+ }
+};
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
llvm::StringRef Filename) {
+ const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
+ if (!FEOpts.FixItSuffix.empty()) {
+ PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix));
+ } else {
+ PathRewriter.reset();
+ }
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
- CI.getLangOpts()));
- if (!AddFixItLocations(CI, *Rewriter))
- return false;
-
+ CI.getLangOpts(), PathRewriter.get()));
return true;
}
void FixItAction::EndSourceFileAction() {
- const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
- Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile);
+ // Otherwise rewrite all files.
+ Rewriter->WriteFixedFiles();
}
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
@@ -197,8 +188,7 @@ void DumpTokensAction::ExecuteAction() {
Preprocessor &PP = getCompilerInstance().getPreprocessor();
// Start preprocessing the specified input file.
Token Tok;
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do {
PP.Lex(Tok);
PP.DumpToken(Tok, true);
@@ -212,7 +202,7 @@ void GeneratePTHAction::ExecuteAction() {
CI.getFrontendOpts().OutputFile == "-") {
// FIXME: Don't fail this way.
// FIXME: Verify that we can actually seek in the given file.
- llvm::llvm_report_error("PTH requires a seekable file for output!");
+ llvm::report_fatal_error("PTH requires a seekable file for output!");
}
llvm::raw_fd_ostream *OS =
CI.createDefaultOutputFile(true, getCurrentFile());
@@ -226,8 +216,7 @@ void ParseOnlyAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(new MinimalAction(PP));
Parser P(PP, *PA);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
P.ParseTranslationUnit();
}
@@ -236,8 +225,7 @@ void PreprocessOnlyAction::ExecuteAction() {
Token Tok;
// Start parsing the specified input file.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
do {
PP.Lex(Tok);
} while (Tok.isNot(tok::eof));
@@ -252,8 +240,7 @@ void PrintParseAction::ExecuteAction() {
llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
Parser P(PP, *PA);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
P.ParseTranslationUnit();
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 9f5bced0d485..12a4d4dbd094 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -355,7 +355,7 @@ static bool getVisualStudioDir(std::string &path) {
else if (vs80comntools)
vscomntools = vs80comntools;
if (vscomntools && *vscomntools) {
- char *p = (char*)strstr(vscomntools, "\\Common7\\Tools");
+ char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools"));
if (p)
*p = '\0';
path = vscomntools;
@@ -429,6 +429,49 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) {
}
}
break;
+ case llvm::Triple::Haiku:
+ AddPath("/boot/common/include", System, true, false, false);
+ AddPath("/boot/develop/headers/os", System, true, false, false);
+ AddPath("/boot/develop/headers/os/app", System, true, false, false);
+ AddPath("/boot/develop/headers/os/arch", System, true, false, false);
+ AddPath("/boot/develop/headers/os/device", System, true, false, false);
+ AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
+ AddPath("/boot/develop/headers/os/game", System, true, false, false);
+ AddPath("/boot/develop/headers/os/interface", System, true, false, false);
+ AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
+ AddPath("/boot/develop/headers/os/locale", System, true, false, false);
+ AddPath("/boot/develop/headers/os/mail", System, true, false, false);
+ AddPath("/boot/develop/headers/os/media", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi", System, true, false, false);
+ AddPath("/boot/develop/headers/os/midi2", System, true, false, false);
+ AddPath("/boot/develop/headers/os/net", System, true, false, false);
+ AddPath("/boot/develop/headers/os/storage", System, true, false, false);
+ AddPath("/boot/develop/headers/os/support", System, true, false, false);
+ AddPath("/boot/develop/headers/os/translation",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/graphics",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/input_server",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/add-ons/tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Deskbar",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/NetPositive",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/os/be_apps/Tracker",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/cpp", System, true, false, false);
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
+ System, true, false, false);
+ AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
+ AddPath("/boot/develop/headers/bsd", System, true, false, false);
+ AddPath("/boot/develop/headers/glibc", System, true, false, false);
+ AddPath("/boot/develop/headers/posix", System, true, false, false);
+ AddPath("/boot/develop/headers", System, true, false, false);
+ break;
case llvm::Triple::MinGW64:
case llvm::Triple::MinGW32:
AddPath("c:/mingw/include", System, true, false, false);
@@ -521,14 +564,26 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
"i586-redhat-linux","", "", triple);
+ // Fedora 11 x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
+ "x86_64-redhat-linux", "32", "", triple);
+
// Fedora 12
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
"i686-redhat-linux","", "", triple);
+ // Fedora 12 x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
+ "x86_64-redhat-linux", "32", "", triple);
+
// Fedora 12 (February-2010+)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
"i686-redhat-linux","", "", triple);
-
+
+ // Fedora 12 (February-2010+) x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3",
+ "x86_64-redhat-linux", "32", "", 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 8bcd3a83c00e..f1e9819d83ca 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/Version.h"
#include "clang/Frontend/Utils.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetInfo.h"
@@ -212,7 +213,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Compiler version introspection macros.
Builder.defineMacro("__llvm__"); // LLVM Backend
Builder.defineMacro("__clang__"); // Clang Frontend
-
+#define TOSTR2(X) #X
+#define TOSTR(X) TOSTR2(X)
+ Builder.defineMacro("__clang_major__", TOSTR(CLANG_VERSION_MAJOR));
+ Builder.defineMacro("__clang_minor__", TOSTR(CLANG_VERSION_MINOR));
+#ifdef CLANG_VERSION_PATCHLEVEL
+ Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL));
+#else
+ Builder.defineMacro("__clang_patchlevel__", "0");
+#endif
+ Builder.defineMacro("__clang_version__",
+ "\"" CLANG_VERSION_STRING " ("
+ + getClangFullRepositoryVersion() + ")\"");
+#undef TOSTR
+#undef TOSTR2
// Currently claim to be compatible with GCC 4.2.1-5621.
Builder.defineMacro("__GNUC_MINOR__", "2");
Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
@@ -294,8 +308,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// C++ translation unit.
Builder.defineMacro("__cplusplus", "199711L");
Builder.defineMacro("__private_extern__", "extern");
- // Ugly hack to work with GNU libstdc++.
- Builder.defineMacro("_GNU_SOURCE");
}
if (LangOpts.Microsoft) {
@@ -503,7 +515,11 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- Builder.append("# 1 \"<built-in>\" 3");
+ // Emit line markers for various builtin sections of the file. We don't do
+ // this in asm preprocessor mode, because "# 4" is not a line marker directive
+ // in this mode.
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines)
@@ -512,7 +528,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
- Builder.append("# 1 \"<command line>\" 1");
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<command line>\" 1");
// Process #define's and #undef's in the order they are given.
for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) {
@@ -538,7 +555,8 @@ void clang::InitializePreprocessor(Preprocessor &PP,
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
- Builder.append("# 1 \"<built-in>\" 2");
+ if (!PP.getLangOptions().AsmPreprocessor)
+ Builder.append("# 1 \"<built-in>\" 2");
// Copy PredefinedBuffer into the Preprocessor.
PP.setPredefines(Predefines.str());
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index ed0ea1f45ef6..af1721d0f9ec 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -22,7 +22,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
default:
llvm_unreachable("Invalid language kind!");
case lang_unspecified:
- llvm::llvm_report_error("getLangStandardForKind() on unspecified kind");
+ llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, desc, features) \
case lang_##id: return Lang_##id;
#include "clang/Frontend/LangStandards.def"
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index b96c04d0a8e0..ae57ce581def 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -62,6 +62,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_BENIGN(DollarIdents);
PARSE_LANGOPT_BENIGN(AsmPreprocessor);
PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
+ PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords);
PARSE_LANGOPT_BENIGN(ImplicitInt);
PARSE_LANGOPT_BENIGN(Digraphs);
PARSE_LANGOPT_BENIGN(HexFloats);
@@ -74,6 +75,8 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
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_IMPORTANT(NoConstantCFStrings,
+ diag::warn_pch_no_constant_cfstrings);
PARSE_LANGOPT_BENIGN(PascalStrings);
PARSE_LANGOPT_BENIGN(WritableStrings);
PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
@@ -910,8 +913,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
- if ((off_t)Record[4] != File->getSize() ||
- (time_t)Record[5] != File->getModificationTime()) {
+ if ((off_t)Record[4] != File->getSize()
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != File->getModificationTime()
+#endif
+ ) {
Diag(diag::err_fe_pch_file_modified)
<< Filename;
return Failure;
@@ -1757,17 +1766,16 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
if (unsigned ObjCClassRedef
= SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION])
Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef);
-#if 0
- // FIXME. Accommodate for this in several PCH/Index tests
- if (unsigned ObjCSelRedef
- = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
- Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
-#endif
if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR])
Context->setBlockDescriptorType(GetType(String));
if (unsigned String
= SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR])
Context->setBlockDescriptorExtendedType(GetType(String));
+ if (unsigned ObjCSelRedef
+ = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION])
+ Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef);
+ if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING])
+ Context->setNSConstantStringType(GetType(String));
}
/// \brief Retrieve the name of the original source file name
@@ -1879,6 +1887,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(DollarIdents);
PARSE_LANGOPT(AsmPreprocessor);
PARSE_LANGOPT(GNUMode);
+ PARSE_LANGOPT(GNUKeywords);
PARSE_LANGOPT(ImplicitInt);
PARSE_LANGOPT(Digraphs);
PARSE_LANGOPT(HexFloats);
@@ -1891,6 +1900,7 @@ bool PCHReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjC2);
PARSE_LANGOPT(ObjCNonFragileABI);
PARSE_LANGOPT(ObjCNonFragileABI2);
+ PARSE_LANGOPT(NoConstantCFStrings);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
PARSE_LANGOPT(LaxVectorConversions);
@@ -2843,6 +2853,14 @@ Selector PCHReader::DecodeSelector(unsigned ID) {
return SelectorsLoaded[Index];
}
+Selector PCHReader::GetSelector(uint32_t ID) {
+ return DecodeSelector(ID);
+}
+
+uint32_t PCHReader::GetNumKnownSelectors() {
+ return TotalNumSelectors + 1;
+}
+
DeclarationName
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index f847becb15b8..14dd2e927c41 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -179,6 +179,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setPreviousDeclaration(
cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
+ FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
FD->setInlineSpecified(Record[Idx++]);
FD->setVirtualAsWritten(Record[Idx++]);
FD->setPure(Record[Idx++]);
@@ -196,6 +197,11 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
FD->setParams(Params.data(), NumParams);
+
+ // FIXME: order this properly w.r.t. friendness
+ // FIXME: this same thing needs to happen for function templates
+ if (FD->isOverloadedOperator() && !FD->getDeclContext()->isRecord())
+ FD->setNonMemberOperator();
}
void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
@@ -212,6 +218,7 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setSynthesized(Record[Idx++]);
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->setNumSelectorArgs(unsigned(Record[Idx++]));
MD->setResultType(Reader.GetType(Record[Idx++]));
MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -220,7 +227,8 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
Params.reserve(NumParams);
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
- MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams);
+ MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams,
+ NumParams);
}
void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
@@ -375,6 +383,7 @@ void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
D->setSuperClass(
cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ // FIXME. Add reading of IvarInitializers and NumIvarInitializers.
}
@@ -397,9 +406,11 @@ void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
VisitDeclaratorDecl(VD);
VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+ VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]);
VD->setThreadSpecified(Record[Idx++]);
VD->setCXXDirectInitializer(Record[Idx++]);
VD->setDeclaredInCondition(Record[Idx++]);
+ VD->setExceptionVariable(Record[Idx++]);
VD->setPreviousDeclaration(
cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
if (Record[Idx++])
@@ -744,7 +755,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
break;
case pch::DECL_VAR:
D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- VarDecl::None);
+ VarDecl::None, VarDecl::None);
break;
case pch::DECL_IMPLICIT_PARAM:
@@ -753,7 +764,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
case pch::DECL_PARM_VAR:
D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None, 0);
break;
case pch::DECL_FILE_SCOPE_ASM:
D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0);
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 7b94805d3999..ef6b77026d7f 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -71,6 +71,7 @@ namespace {
unsigned VisitCharacterLiteral(CharacterLiteral *E);
unsigned VisitParenExpr(ParenExpr *E);
unsigned VisitUnaryOperator(UnaryOperator *E);
+ unsigned VisitOffsetOfExpr(OffsetOfExpr *E);
unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E);
unsigned VisitCallExpr(CallExpr *E);
@@ -432,6 +433,49 @@ unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) {
return 1;
}
+unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ VisitExpr(E);
+ assert(E->getNumComponents() == Record[Idx]);
+ ++Idx;
+ assert(E->getNumExpressions() == Record[Idx]);
+ ++Idx;
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+ SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ switch (Kind) {
+ case Node::Array:
+ E->setComponent(I, Node(Start, Record[Idx++], End));
+ break;
+
+ case Node::Field:
+ E->setComponent(I,
+ Node(Start,
+ dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])),
+ End));
+ break;
+
+ case Node::Identifier:
+ E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
+ break;
+
+ case Node::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ E->setIndexExpr(I, cast_or_null<Expr>(StmtStack[StmtStack.size() - N + I]));
+
+ return E->getNumExpressions();
+}
+
unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
E->setSizeof(Record[Idx++]);
@@ -554,9 +598,9 @@ unsigned PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) {
unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) {
VisitExpr(E);
unsigned NumInits = Record[Idx++];
- E->reserveInits(NumInits);
+ E->reserveInits(*Reader.getContext(), NumInits);
for (unsigned I = 0; I != NumInits; ++I)
- E->updateInit(I,
+ E->updateInit(*Reader.getContext(), I,
cast<Expr>(StmtStack[StmtStack.size() - NumInits - 1 + I]));
E->setSyntacticForm(cast_or_null<InitListExpr>(StmtStack.back()));
E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -725,7 +769,7 @@ unsigned PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
- E->setEncodedType(Reader.GetType(Record[Idx++]));
+ E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
@@ -782,25 +826,42 @@ unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr(
unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
- E->setNumArgs(Record[Idx++]);
- E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- E->setSelector(Reader.GetSelector(Record, Idx));
- E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
-
- E->setReceiver(
+ assert(Record[Idx] == E->getNumArgs());
+ ++Idx;
+ ObjCMessageExpr::ReceiverKind Kind
+ = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
+ switch (Kind) {
+ case ObjCMessageExpr::Instance:
+ E->setInstanceReceiver(
cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
- if (!E->getReceiver()) {
- ObjCMessageExpr::ClassInfo CI;
- CI.Decl = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]));
- CI.Name = Reader.GetIdentifierInfo(Record, Idx);
- CI.Loc = SourceLocation::getFromRawEncoding(Record[Idx++]);
- E->setClassInfo(CI);
+ break;
+
+ case ObjCMessageExpr::Class:
+ E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx));
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance: {
+ QualType T = Reader.GetType(Record[Idx++]);
+ SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance);
+ break;
}
+ }
+
+ assert(Kind == E->getReceiverKind());
+
+ if (Record[Idx++])
+ E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ else
+ E->setSelector(Reader.GetSelector(Record, Idx));
+
+ E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
- return E->getNumArgs() + 1;
+ return E->getNumArgs() + (Kind == ObjCMessageExpr::Instance);
}
unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) {
@@ -821,12 +882,11 @@ unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
VisitStmt(S);
- S->setCatchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
- S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
- S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setCatchBody(cast_or_null<Stmt>(StmtStack.back()));
+ S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- return 2;
+ return 1;
}
unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
@@ -838,11 +898,21 @@ unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
VisitStmt(S);
- S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
- S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
- S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ assert(Record[Idx] == S->getNumCatchStmts());
+ ++Idx;
+ bool HasFinally = Record[Idx++];
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ unsigned Offset = StmtStack.size() - N - HasFinally + I;
+ S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(StmtStack[Offset]));
+ }
+
+ unsigned TryOffset
+ = StmtStack.size() - S->getNumCatchStmts() - HasFinally - 1;
+ S->setTryBody(cast_or_null<Stmt>(StmtStack[TryOffset]));
+ if (HasFinally)
+ S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
- return 3;
+ return 1 + S->getNumCatchStmts() + HasFinally;
}
unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
@@ -1079,6 +1149,12 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) UnaryOperator(Empty);
break;
+ case pch::EXPR_OFFSETOF:
+ S = OffsetOfExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields],
+ Record[PCHStmtReader::NumExprFields + 1]);
+ break;
+
case pch::EXPR_SIZEOF_ALIGN_OF:
S = new (Context) SizeOfAlignOfExpr(Empty);
break;
@@ -1124,7 +1200,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
break;
case pch::EXPR_INIT_LIST:
- S = new (Context) InitListExpr(Empty);
+ S = new (Context) InitListExpr(*getContext(), Empty);
break;
case pch::EXPR_DESIGNATED_INIT:
@@ -1195,7 +1271,8 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty);
break;
case pch::EXPR_OBJC_MESSAGE_EXPR:
- S = new (Context) ObjCMessageExpr(Empty);
+ S = ObjCMessageExpr::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumExprFields]);
break;
case pch::EXPR_OBJC_SUPER_EXPR:
S = new (Context) ObjCSuperExpr(Empty);
@@ -1213,7 +1290,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) ObjCAtFinallyStmt(Empty);
break;
case pch::STMT_OBJC_AT_TRY:
- S = new (Context) ObjCAtTryStmt(Empty);
+ S = ObjCAtTryStmt::CreateEmpty(*Context,
+ Record[PCHStmtReader::NumStmtFields],
+ Record[PCHStmtReader::NumStmtFields + 1]);
break;
case pch::STMT_OBJC_AT_SYNCHRONIZED:
S = new (Context) ObjCAtSynchronizedStmt(Empty);
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 4dd8dc36b760..e56dd3132224 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -1,4 +1,4 @@
-//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===//
+//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -63,6 +63,7 @@ namespace {
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
+ void VisitInjectedClassNameType(const InjectedClassNameType *T);
};
}
@@ -240,7 +241,7 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
Writer.AddDeclRef(T->getDecl(), Record);
- Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
Code = pch::TYPE_INJECTED_CLASS_NAME;
}
@@ -745,6 +746,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers.
Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode.
Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc)
+ Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords
Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'.
Record.push_back(LangOpts.Digraphs); // C94, C99 and C++
Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants.
@@ -760,6 +762,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
// modern abi enabled.
Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced
// modern abi enabled.
+ Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
Record.push_back(LangOpts.WritableStrings); // Allow writable strings
@@ -1103,7 +1106,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// that is required by llvm::MemoryBuffer::getMemBuffer (on
// the reader side).
const llvm::MemoryBuffer *Buffer
- = Content->getBuffer(PP.getDiagnostics());
+ = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
const char *Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
llvm::StringRef(Name, strlen(Name) + 1));
@@ -2093,12 +2096,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddTypeRef(Context.getsigjmp_bufType(), Record);
AddTypeRef(Context.ObjCIdRedefinitionType, Record);
AddTypeRef(Context.ObjCClassRedefinitionType, Record);
-#if 0
- // FIXME. Accommodate for this in several PCH/Indexer tests
- AddTypeRef(Context.ObjCSelRedefinitionType, Record);
-#endif
AddTypeRef(Context.getRawBlockdescriptorType(), Record);
AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
+ AddTypeRef(Context.ObjCSelRedefinitionType, Record);
+ AddTypeRef(Context.getRawNSConstantStringType(), Record);
Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
// Keep writing types and declarations until all types and
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 7917280295ad..7b7806239604 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -176,6 +176,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Writer.AddStmt(D->getBody());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isVirtualAsWritten());
Record.push_back(D->isPure());
@@ -211,6 +212,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->getNumSelectorArgs());
Writer.AddTypeRef(D->getResultType(), Record);
Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
@@ -359,6 +361,7 @@ void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
VisitObjCImplDecl(D);
Writer.AddDeclRef(D->getSuperClass(), Record);
+ // FIXME add writing of IvarInitializers and NumIvarInitializers.
Code = pch::DECL_OBJC_IMPLEMENTATION;
}
@@ -382,9 +385,11 @@ void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->isThreadSpecified());
Record.push_back(D->hasCXXDirectInitializer());
Record.push_back(D->isDeclaredInCondition());
+ Record.push_back(D->isExceptionVariable());
Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
Record.push_back(D->getInit()? 1 : 0);
if (D->getInit())
@@ -425,6 +430,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition");
+ assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
assert(D->getInit() == 0 && "PARM_VAR_DECL never has init");
}
@@ -493,9 +499,11 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
+ Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
// ParmVarDecl
@@ -608,7 +616,7 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {
if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
if (!W.Code)
- llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") +
+ llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") +
D->getDeclKindName() + "'");
Stream.EmitRecord(W.Code, Record, W.AbbrevToUse);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 9a5417ca6102..a1993d37f2dc 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -62,6 +62,7 @@ namespace {
void VisitCharacterLiteral(CharacterLiteral *E);
void VisitParenExpr(ParenExpr *E);
void VisitUnaryOperator(UnaryOperator *E);
+ void VisitOffsetOfExpr(OffsetOfExpr *E);
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
void VisitCallExpr(CallExpr *E);
@@ -393,6 +394,42 @@ void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
Code = pch::EXPR_UNARY_OPERATOR;
}
+void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumComponents());
+ Record.push_back(E->getNumExpressions());
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+ Record.push_back(ON.getKind()); // FIXME: Stable encoding
+ Writer.AddSourceLocation(ON.getRange().getBegin(), Record);
+ Writer.AddSourceLocation(ON.getRange().getEnd(), Record);
+ switch (ON.getKind()) {
+ case OffsetOfExpr::OffsetOfNode::Array:
+ Record.push_back(ON.getArrayExprIndex());
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Field:
+ Writer.AddDeclRef(ON.getField(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Identifier:
+ Writer.AddIdentifierRef(ON.getFieldName(), Record);
+ break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
+ }
+ }
+ for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+ Writer.WriteSubStmt(E->getIndexExpr(I));
+ Code = pch::EXPR_OFFSETOF;
+}
+
void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
VisitExpr(E);
Record.push_back(E->isSizeOf());
@@ -655,7 +692,7 @@ void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
VisitExpr(E);
- Writer.AddTypeRef(E->getEncodedType(), Record);
+ Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record);
Writer.AddSourceLocation(E->getAtLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Code = pch::EXPR_OBJC_ENCODE;
@@ -712,18 +749,33 @@ void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr(
void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumArgs());
+ Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
+ switch (E->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ Writer.WriteSubStmt(E->getInstanceReceiver());
+ break;
+
+ case ObjCMessageExpr::Class:
+ Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record);
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ case ObjCMessageExpr::SuperInstance:
+ Writer.AddTypeRef(E->getSuperType(), Record);
+ Writer.AddSourceLocation(E->getSuperLoc(), Record);
+ break;
+ }
+
+ if (E->getMethodDecl()) {
+ Record.push_back(1);
+ Writer.AddDeclRef(E->getMethodDecl(), Record);
+ } else {
+ Record.push_back(0);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ }
+
Writer.AddSourceLocation(E->getLeftLoc(), Record);
Writer.AddSourceLocation(E->getRightLoc(), Record);
- Writer.AddSelectorRef(E->getSelector(), Record);
- Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
- Writer.WriteSubStmt(E->getReceiver());
-
- if (!E->getReceiver()) {
- ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
- Writer.AddDeclRef(CI.Decl, Record);
- Writer.AddIdentifierRef(CI.Name, Record);
- Writer.AddSourceLocation(CI.Loc, Record);
- }
for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Arg != ArgEnd; ++Arg)
@@ -749,7 +801,6 @@ void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
Writer.WriteSubStmt(S->getCatchBody());
- Writer.WriteSubStmt(S->getNextCatchStmt());
Writer.AddDeclRef(S->getCatchParamDecl(), Record);
Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
Writer.AddSourceLocation(S->getRParenLoc(), Record);
@@ -763,9 +814,13 @@ void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
}
void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+ Record.push_back(S->getNumCatchStmts());
+ Record.push_back(S->getFinallyStmt() != 0);
Writer.WriteSubStmt(S->getTryBody());
- Writer.WriteSubStmt(S->getCatchStmts());
- Writer.WriteSubStmt(S->getFinallyStmt());
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+ Writer.WriteSubStmt(S->getCatchStmt(I));
+ if (S->getFinallyStmt())
+ Writer.WriteSubStmt(S->getFinallyStmt());
Writer.AddSourceLocation(S->getAtTryLoc(), Record);
Code = pch::STMT_OBJC_AT_TRY;
}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index 8d64a6413304..4df5c5263c7e 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -197,7 +197,7 @@ namespace {
}
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -405,8 +405,8 @@ namespace {
// Objective-c statements
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
- DeclPtrTy Parm, StmtArg Body,
- StmtArg CatchList) {
+ DeclPtrTy Parm,
+ StmtArg Body) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
@@ -418,7 +418,8 @@ namespace {
}
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
- StmtArg Try, StmtArg Catch,
+ StmtArg Try,
+ MultiStmtArg CatchStmts,
StmtArg Finally) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 02afd24c246e..b6c18b77316c 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -78,6 +78,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI,
namespace {
class PrintPPOutputPPCallbacks : public PPCallbacks {
Preprocessor &PP;
+ SourceManager &SM;
TokenConcatenation ConcatInfo;
public:
llvm::raw_ostream &OS;
@@ -94,7 +95,8 @@ private:
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
bool lineMarkers, bool defines)
- : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ : PP(pp), SM(PP.getSourceManager()),
+ ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
DumpDefines(defines) {
CurLine = 0;
CurFilename += "<uninit>";
@@ -118,9 +120,14 @@ public:
bool HandleFirstTokOnLine(Token &Tok);
- bool MoveToLine(SourceLocation Loc);
- bool AvoidConcat(const Token &PrevTok, const Token &Tok) {
- return ConcatInfo.AvoidConcat(PrevTok, Tok);
+ bool MoveToLine(SourceLocation Loc) {
+ return MoveToLine(SM.getPresumedLoc(Loc).getLine());
+ }
+ bool MoveToLine(unsigned LineNo);
+
+ bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,
+ const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
}
void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
@@ -166,9 +173,7 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
/// object. We can do this by emitting some number of \n's, or be emitting a
/// #line directive. This returns false if already at the specified line, true
/// if some newlines were emitted.
-bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) {
- unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
-
+bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
if (DisableLineMarkers) {
if (LineNo == CurLine) return false;
@@ -211,27 +216,29 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
SrcMgr::CharacteristicKind NewFileType) {
// Unless we are exiting a #include, make sure to skip ahead to the line the
// #include directive was at.
- SourceManager &SourceMgr = PP.getSourceManager();
+ SourceManager &SourceMgr = SM;
+
+ PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc);
+ unsigned NewLine = UserLoc.getLine();
+
if (Reason == PPCallbacks::EnterFile) {
SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
if (IncludeLoc.isValid())
MoveToLine(IncludeLoc);
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
- MoveToLine(Loc);
+ MoveToLine(NewLine);
// TODO GCC emits the # directive for this directive on the line AFTER the
// directive and emits a bunch of spaces that aren't needed. Emulate this
// strange behavior.
}
-
- Loc = SourceMgr.getInstantiationLoc(Loc);
- // FIXME: Should use presumed line #!
- CurLine = SourceMgr.getInstantiationLineNumber(Loc);
+
+ CurLine = NewLine;
if (DisableLineMarkers) return;
CurFilename.clear();
- CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename();
+ CurFilename += UserLoc.getFilename();
Lexer::Stringify(CurFilename);
FileType = NewFileType;
@@ -318,8 +325,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// Print out space characters so that the first token on a line is
// indented for easy reading.
- const SourceManager &SourceMgr = PP.getSourceManager();
- unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation());
+ unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation());
// This hack prevents stuff like:
// #define HASH #
@@ -391,6 +397,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
llvm::raw_ostream &OS) {
char Buffer[256];
+ Token PrevPrevTok;
Token PrevTok;
while (1) {
@@ -402,7 +409,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// useful to look at and no concatenation could happen anyway.
(Callbacks->hasEmittedTokensOnThisLine() &&
// Don't print "-" next to "-", it would form "--".
- Callbacks->AvoidConcat(PrevTok, Tok))) {
+ Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
OS << ' ';
}
@@ -433,6 +440,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
if (Tok.is(tok::eof)) break;
+ PrevPrevTok = PrevTok;
PrevTok = Tok;
PP.Lex(Tok);
}
@@ -448,8 +456,7 @@ static int MacroIDCompare(const void* a, const void* b) {
static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
Token Tok;
do PP.Lex(Tok);
@@ -484,8 +491,6 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
// to -C or -CC.
PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments);
- OS->SetBufferSize(64*1024);
-
PrintPPOutputPPCallbacks *Callbacks =
new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers,
Opts.ShowMacros);
@@ -496,8 +501,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS,
PP.addPPCallbacks(Callbacks);
// After we have configured the preprocessor, enter the main file.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
// Consume all of the tokens that come from the predefines buffer. Those
// should not be emitted into the output and are guaranteed to be at the
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
index 4ffb2978db7a..954e8e23cac7 100644
--- a/lib/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -101,8 +101,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) {
// Get the first preprocessing token.
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
Token PPTok;
PP.Lex(PPTok);
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index cba92987a3d6..11698325e9b1 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -444,7 +444,7 @@ namespace {
CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
CastExpr::CastKind Kind, Expr *E) {
TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
- return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo,
+ return new (Ctx) CStyleCastExpr(Ty, Kind, E, CXXBaseSpecifierArray(), TInfo,
SourceLocation(), SourceLocation());
}
}
@@ -640,7 +640,9 @@ void RewriteObjC::Initialize(ASTContext &context) {
if (LangOpts.Microsoft) {
Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests.
Preamble += "#define __attribute__(X)\n";
+ Preamble += "#endif\n";
Preamble += "#define __weak\n";
}
else {
@@ -1237,11 +1239,26 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
- PDecl->getSetterName(), PDecl->getType(),
- PDecl->getSetterMethodDecl(),
- SourceLocation(), SourceLocation(),
- &ExprVec[0], 1);
+ if (isa<ObjCSuperExpr>(Receiver))
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME?*/SourceLocation(),
+ Receiver->getLocStart(),
+ /*IsInstanceSuper=*/true,
+ cast<Expr>(Receiver)->getType(),
+ PDecl->getSetterName(),
+ PDecl->getSetterMethodDecl(),
+ &ExprVec[0], 1,
+ /*FIXME:*/SourceLocation());
+ else
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME: */SourceLocation(),
+ cast<Expr>(Receiver),
+ PDecl->getSetterName(),
+ PDecl->getSetterMethodDecl(),
+ &ExprVec[0], 1,
+ /*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
// Now do the actual rewrite.
@@ -1266,11 +1283,27 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
// This allows us to handle chain/nested property getters.
Receiver = PropGetters[PRE];
}
- MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver),
- PDecl->getGetterName(), PDecl->getType(),
- PDecl->getGetterMethodDecl(),
- SourceLocation(), SourceLocation(),
- 0, 0);
+
+ if (isa<ObjCSuperExpr>(Receiver))
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME:*/SourceLocation(),
+ Receiver->getLocStart(),
+ /*IsInstanceSuper=*/true,
+ cast<Expr>(Receiver)->getType(),
+ PDecl->getGetterName(),
+ PDecl->getGetterMethodDecl(),
+ 0, 0,
+ /*FIXME:*/SourceLocation());
+ else
+ MsgExpr = ObjCMessageExpr::Create(*Context,
+ PDecl->getType().getNonReferenceType(),
+ /*FIXME:*/SourceLocation(),
+ cast<Expr>(Receiver),
+ PDecl->getGetterName(),
+ PDecl->getGetterMethodDecl(),
+ 0, 0,
+ /*FIXME:*/SourceLocation());
Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
@@ -1828,8 +1861,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
assert((*startBuf == '}') && "bogus @try block");
SourceLocation lastCurlyLoc = startLoc;
- ObjCAtCatchStmt *catchList = S->getCatchStmts();
- if (catchList) {
+ if (S->getNumCatchStmts()) {
startLoc = startLoc.getFileLocWithOffset(1);
buf = " /* @catch begin */ else {\n";
buf += " id _caught = objc_exception_extract(&_stack);\n";
@@ -1847,26 +1879,27 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
bool sawIdTypedCatch = false;
Stmt *lastCatchBody = 0;
- while (catchList) {
- ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *Catch = S->getCatchStmt(I);
+ VarDecl *catchDecl = Catch->getCatchParamDecl();
- if (catchList == S->getCatchStmts())
+ if (I == 0)
buf = "if ("; // we are generating code for the first catch clause
else
buf = "else if (";
- startLoc = catchList->getLocStart();
+ startLoc = Catch->getLocStart();
startBuf = SM->getCharacterData(startLoc);
assert((*startBuf == '@') && "bogus @catch location");
const char *lParenLoc = strchr(startBuf, '(');
- if (catchList->hasEllipsis()) {
+ if (Catch->hasEllipsis()) {
// Now rewrite the body...
- lastCatchBody = catchList->getCatchBody();
+ lastCatchBody = Catch->getCatchBody();
SourceLocation bodyLoc = lastCatchBody->getLocStart();
const char *bodyBuf = SM->getCharacterData(bodyLoc);
- assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' &&
+ assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' &&
"bogus @catch paren location");
assert((*bodyBuf == '{') && "bogus @catch body location");
@@ -1890,8 +1923,8 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
}
// Now rewrite the body...
- lastCatchBody = catchList->getCatchBody();
- SourceLocation rParenLoc = catchList->getRParenLoc();
+ lastCatchBody = Catch->getCatchBody();
+ SourceLocation rParenLoc = Catch->getRParenLoc();
SourceLocation bodyLoc = lastCatchBody->getLocStart();
const char *bodyBuf = SM->getCharacterData(bodyLoc);
const char *rParenBuf = SM->getCharacterData(rParenLoc);
@@ -1904,8 +1937,6 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
} else {
assert(false && "@catch rewrite bug");
}
- // make sure all the catch bodies get rewritten!
- catchList = catchList->getNextCatchStmt();
}
// Complete the catch list...
if (lastCatchBody) {
@@ -2054,10 +2085,10 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
// Now, we cast the reference to a pointer to the objc_msgSend type.
QualType pToFunc = Context->getPointerType(msgSendType);
- ImplicitCastExpr *ICE = new (Context) ImplicitCastExpr(pToFunc,
- CastExpr::CK_Unknown,
- DRE,
- /*isLvalue=*/false);
+ ImplicitCastExpr *ICE =
+ new (Context) ImplicitCastExpr(pToFunc, CastExpr::CK_Unknown,
+ DRE, CXXBaseSpecifierArray(),
+ /*isLvalue=*/false);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
@@ -2267,7 +2298,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SelGetUidIdent, getFuncType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2364,7 +2396,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2385,7 +2418,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
@@ -2409,7 +2443,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2430,7 +2465,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2456,7 +2492,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2477,7 +2514,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
@@ -2493,7 +2531,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2508,9 +2547,12 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
false, false, 0, 0,
FunctionType::ExtInfo());
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- getSuperClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ SourceLocation(),
+ getSuperClassIdent,
+ getClassType, 0,
+ FunctionDecl::Extern,
+ FunctionDecl::None,
+ false);
}
// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name);
@@ -2526,7 +2568,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
- FunctionDecl::Extern, false);
+ FunctionDecl::Extern,
+ FunctionDecl::None, false);
}
Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2560,7 +2603,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
&Context->Idents.get(S), strType, 0,
- VarDecl::Static);
+ VarDecl::Static, VarDecl::None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
@@ -2665,7 +2708,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
FunctionDecl *MsgSendStretFlavor = 0;
if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
QualType resultType = mDecl->getResultType();
- if (resultType->isStructureType() || resultType->isUnionType())
+ if (resultType->isRecordType())
MsgSendStretFlavor = MsgSendStretFunctionDecl;
else if (resultType->isRealFloatingType())
MsgSendFlavor = MsgSendFpretFunctionDecl;
@@ -2673,203 +2716,211 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Synthesize a call to objc_msgSend().
llvm::SmallVector<Expr*, 8> MsgExprs;
- IdentifierInfo *clsName = Exp->getClassName();
-
- // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
- if (clsName) { // class message.
- // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle
- // the 'super' idiom within a class method.
- if (clsName->getName() == "super") {
- MsgSendFlavor = MsgSendSuperFunctionDecl;
- if (MsgSendStretFlavor)
- MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
- assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
-
- ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
-
- llvm::SmallVector<Expr*, 4> InitExprs;
-
- // set the receiver to self, the first argument to all methods.
- InitExprs.push_back(
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
- Context->getObjCIdType(),
- SourceLocation()))
- ); // set the 'receiver'.
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc,
- EndLoc);
- // (Class)objc_getClass("CurrentClass")
- CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCClassType(),
- CastExpr::CK_Unknown, Cls);
- ClsExprs.clear();
- ClsExprs.push_back(ArgExpr);
- Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
- &ClsExprs[0], ClsExprs.size(),
- StartLoc, EndLoc);
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- // To turn off a warning, type-cast to 'id'
- InitExprs.push_back( // set 'super class', using class_getSuperclass().
- NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCIdType(),
- CastExpr::CK_Unknown, Cls));
- // struct objc_super
- QualType superType = getSuperStructType();
- Expr *SuperRep;
-
- if (LangOpts.Microsoft) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
- superType, SourceLocation());
- // The code for super is a little tricky to prevent collision with
- // the structure definition in the header. The rewriter has it's own
- // internal definition (__rw_objc_super) that is uses. This is why
- // we need the cast below. For example:
- // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
- //
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- SuperRep = NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(superType),
- CastExpr::CK_Unknown, SuperRep);
- } else {
- // (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
- SourceLocation());
- TypeSourceInfo *superTInfo
- = Context->getTrivialTypeSourceInfo(superType);
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
- superType, ILE, false);
- // struct objc_super *
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- }
- MsgExprs.push_back(SuperRep);
+ switch (Exp->getReceiverKind()) {
+ case ObjCMessageExpr::SuperClass: {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ // set the receiver to self, the first argument to all methods.
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc,
+ EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back( // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getNameStart(),
- clsName->getLength(),
- false, argType,
- SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc, EndLoc);
- MsgExprs.push_back(Cls);
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
+ // struct objc_super *
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
}
- } else { // instance message.
- Expr *recExpr = Exp->getReceiver();
-
- if (isSuperReceiver(recExpr)) {
- MsgSendFlavor = MsgSendSuperFunctionDecl;
- if (MsgSendStretFlavor)
- MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
- assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
- ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
- llvm::SmallVector<Expr*, 4> InitExprs;
-
- InitExprs.push_back(
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
- Context->getObjCIdType(),
- SourceLocation()))
- ); // set the 'receiver'.
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- llvm::SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getNameStart(),
- ClassDecl->getIdentifier()->getLength(),
- false, argType, SourceLocation()));
- CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
- &ClsExprs[0],
- ClsExprs.size(),
- StartLoc, EndLoc);
- // (Class)objc_getClass("CurrentClass")
- CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
- Context->getObjCClassType(),
- CastExpr::CK_Unknown, Cls);
- ClsExprs.clear();
- ClsExprs.push_back(ArgExpr);
- Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
- &ClsExprs[0], ClsExprs.size(),
- StartLoc, EndLoc);
-
- // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
- // To turn off a warning, type-cast to 'id'
- InitExprs.push_back(
- // set 'super class', using class_getSuperclass().
- NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown, Cls));
- // struct objc_super
- QualType superType = getSuperStructType();
- Expr *SuperRep;
-
- if (LangOpts.Microsoft) {
- SynthSuperContructorFunctionDecl();
- // Simulate a contructor call...
- DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
- superType, SourceLocation());
- SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
- InitExprs.size(),
- superType, SourceLocation());
- // The code for super is a little tricky to prevent collision with
- // the structure definition in the header. The rewriter has it's own
- // internal definition (__rw_objc_super) that is uses. This is why
- // we need the cast below. For example:
- // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
- //
- SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
- Context->getPointerType(SuperRep->getType()),
- SourceLocation());
- SuperRep = NoTypeInfoCStyleCastExpr(Context,
- Context->getPointerType(superType),
- CastExpr::CK_Unknown, SuperRep);
- } else {
- // (struct objc_super) { <exprs from above> }
- InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
- &InitExprs[0], InitExprs.size(),
- SourceLocation());
- TypeSourceInfo *superTInfo
- = Context->getTrivialTypeSourceInfo(superType);
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
- superType, ILE, false);
- }
- MsgExprs.push_back(SuperRep);
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Class: {
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ObjCInterfaceDecl *Class
+ = Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ IdentifierInfo *clsName = Class->getIdentifier();
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getNameStart(),
+ clsName->getLength(),
+ false, argType,
+ SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ MsgExprs.push_back(Cls);
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:{
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+ ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface();
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ InitExprs.push_back(
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()))
+ ); // set the 'receiver'.
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ ClassDecl->getIdentifier()->getNameStart(),
+ ClassDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size(),
+ StartLoc, EndLoc);
+ // (Class)objc_getClass("CurrentClass")
+ CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCClassType(),
+ CastExpr::CK_Unknown, Cls);
+ ClsExprs.clear();
+ ClsExprs.push_back(ArgExpr);
+ Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl,
+ &ClsExprs[0], ClsExprs.size(),
+ StartLoc, EndLoc);
+
+ // (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back(
+ // set 'super class', using class_getSuperclass().
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
+ // struct objc_super
+ QualType superType = getSuperStructType();
+ Expr *SuperRep;
+
+ if (LangOpts.Microsoft) {
+ SynthSuperContructorFunctionDecl();
+ // Simulate a contructor call...
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl,
+ superType, SourceLocation());
+ SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0],
+ InitExprs.size(),
+ superType, SourceLocation());
+ // The code for super is a little tricky to prevent collision with
+ // the structure definition in the header. The rewriter has it's own
+ // internal definition (__rw_objc_super) that is uses. This is why
+ // we need the cast below. For example:
+ // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER"))
+ //
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
- // Remove all type-casts because it may contain objc-style types; e.g.
- // Foo<Proto> *.
- while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
- recExpr = CE->getSubExpr();
- recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
- CastExpr::CK_Unknown, recExpr);
- MsgExprs.push_back(recExpr);
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE =
+ new (Context) InitListExpr(*Context, SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
}
+ MsgExprs.push_back(SuperRep);
+ break;
+ }
+
+ case ObjCMessageExpr::Instance: {
+ // Remove all type-casts because it may contain objc-style types; e.g.
+ // Foo<Proto> *.
+ Expr *recExpr = Exp->getInstanceReceiver();
+ while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
+ recExpr = CE->getSubExpr();
+ recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, recExpr);
+ MsgExprs.push_back(recExpr);
+ break;
}
+ }
+
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
llvm::SmallVector<Expr*, 8> SelExprs;
QualType argType = Context->getPointerType(Context->CharTy);
@@ -3070,7 +3121,8 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- ID, getProtocolType(), 0, VarDecl::Extern);
+ ID, getProtocolType(), 0,
+ VarDecl::Extern, VarDecl::None);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
@@ -5066,8 +5118,8 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
- ID, FType, 0, FunctionDecl::Extern, false,
- false);
+ ID, FType, 0, FunctionDecl::Extern,
+ FunctionDecl::None, false, false);
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -5147,7 +5199,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- VarDecl::Static);
+ VarDecl::Static, VarDecl::None);
UnaryOperator *DescRefExpr = new (Context) UnaryOperator(
new (Context) DeclRefExpr(NewVD,
Context->VoidPtrTy, SourceLocation()),
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index ce474d365390..21dc0ba0a188 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -125,6 +125,7 @@ namespace {
void VisitFloatingLiteral(FloatingLiteral *Node);
void VisitStringLiteral(StringLiteral *Str);
void VisitUnaryOperator(UnaryOperator *Node);
+ void VisitOffsetOfExpr(OffsetOfExpr *Node);
void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
@@ -308,6 +309,10 @@ void StmtXML::VisitUnaryOperator(UnaryOperator *Node) {
Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
}
+void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) {
+ DumpExpr(Node);
+}
+
void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
DumpExpr(Node);
Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 4e91f8d4c221..28bb17ac3efa 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -148,9 +148,16 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
std::string &FixItInsertionLine,
unsigned EndOfCaretToken,
unsigned Columns) {
- if (CaretLine.size() > SourceLine.size())
- SourceLine.resize(CaretLine.size(), ' ');
-
+ unsigned MaxSize = std::max(SourceLine.size(),
+ std::max(CaretLine.size(),
+ FixItInsertionLine.size()));
+ if (MaxSize > SourceLine.size())
+ SourceLine.resize(MaxSize, ' ');
+ if (MaxSize > CaretLine.size())
+ CaretLine.resize(MaxSize, ' ');
+ if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size())
+ FixItInsertionLine.resize(MaxSize, ' ');
+
// Find the slice that we need to display the full caret line
// correctly.
unsigned CaretStart = 0, CaretEnd = CaretLine.size();
@@ -275,7 +282,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine,
void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges,
unsigned NumRanges,
- SourceManager &SM,
+ const SourceManager &SM,
const FixItHint *Hints,
unsigned NumHints,
unsigned Columns) {
@@ -796,8 +803,13 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OutStr += " [-W";
OutStr += Opt;
OutStr += ']';
- } else if (Diagnostic::isBuiltinExtensionDiag(Info.getID())) {
- OutStr += " [-pedantic]";
+ } else {
+ // If the diagnostic is an extension diagnostic and not enabled by default
+ // then it must have been turned on with -pedantic.
+ bool EnabledByDefault;
+ if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) &&
+ !EnabledByDefault)
+ OutStr += " [-pedantic]";
}
}
diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp
index 99ec910be0af..ae36481444da 100644
--- a/lib/Frontend/VerifyDiagnosticsClient.cpp
+++ b/lib/Frontend/VerifyDiagnosticsClient.cpp
@@ -16,6 +16,7 @@
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -71,97 +72,267 @@ bool VerifyDiagnosticsClient::HadErrors() {
typedef TextDiagnosticBuffer::DiagList DiagList;
typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
-/// FindDiagnostics - Go through the comment and see if it indicates expected
-/// diagnostics. If so, then put them in a diagnostic list.
+namespace {
+
+/// Directive - Abstract class representing a parsed verify directive.
///
-static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
- DiagList &ExpectedDiags,
- Preprocessor &PP, SourceLocation Pos,
- const char *ExpectedStr) {
- const char *CommentEnd = CommentStart+CommentLen;
- unsigned ExpectedStrLen = strlen(ExpectedStr);
-
- // Find all expected-foo diagnostics in the string and add them to
- // ExpectedDiags.
- while (CommentStart != CommentEnd) {
- CommentStart = std::find(CommentStart, CommentEnd, 'e');
- if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
-
- // If this isn't expected-foo, ignore it.
- if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
- ++CommentStart;
- continue;
- }
+class Directive {
+public:
+ static Directive* Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count);
+public:
+ SourceLocation Location;
+ const std::string Text;
+ unsigned Count;
+
+ virtual ~Directive() { }
+
+ // Returns true if directive text is valid.
+ // Otherwise returns false and populates E.
+ virtual bool isValid(std::string &Error) = 0;
+
+ // Returns true on match.
+ virtual bool Match(const std::string &S) = 0;
+
+protected:
+ Directive(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Location(Location), Text(Text), Count(Count) { }
+
+private:
+ Directive(const Directive&); // DO NOT IMPLEMENT
+ void operator=(const Directive&); // DO NOT IMPLEMENT
+};
+
+/// StandardDirective - Directive with string matching.
+///
+class StandardDirective : public Directive {
+public:
+ StandardDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count) { }
+
+ virtual bool isValid(std::string &Error) {
+ // all strings are considered valid; even empty ones
+ return true;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return S.find(Text) != std::string::npos ||
+ Text.find(S) != std::string::npos;
+ }
+};
+
+/// RegexDirective - Directive with regular-expression matching.
+///
+class RegexDirective : public Directive {
+public:
+ RegexDirective(const SourceLocation &Location, const std::string &Text,
+ unsigned Count)
+ : Directive(Location, Text, Count), Regex(Text) { }
+
+ virtual bool isValid(std::string &Error) {
+ if (Regex.isValid(Error))
+ return true;
+ return false;
+ }
+
+ virtual bool Match(const std::string &S) {
+ return Regex.match(S);
+ }
- CommentStart += ExpectedStrLen;
-
- // Skip whitespace.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // Default, if we find the '{' now, is 1 time.
- int Times = 1;
- int Temp = 0;
- // In extended syntax, there could be a digit now.
- while (CommentStart != CommentEnd &&
- CommentStart[0] >= '0' && CommentStart[0] <= '9') {
- Temp *= 10;
- Temp += CommentStart[0] - '0';
- ++CommentStart;
+private:
+ llvm::Regex Regex;
+};
+
+typedef std::vector<Directive*> DirectiveList;
+
+/// ExpectedData - owns directive objects and deletes on destructor.
+///
+struct ExpectedData {
+ DirectiveList Errors;
+ DirectiveList Warnings;
+ DirectiveList Notes;
+
+ ~ExpectedData() {
+ DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 };
+ for (DirectiveList **PL = Lists; *PL; ++PL) {
+ DirectiveList * const L = *PL;
+ for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I)
+ delete *I;
}
- if (Temp > 0)
- Times = Temp;
-
- // Skip whitespace again.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // We should have a {{ now.
- if (CommentEnd-CommentStart < 2 ||
- CommentStart[0] != '{' || CommentStart[1] != '{') {
- if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
- PP.Diag(Pos, diag::err_verify_bogus_characters);
- else
- PP.Diag(Pos, diag::err_verify_missing_start);
- return;
+ }
+};
+
+class ParseHelper
+{
+public:
+ ParseHelper(const char *Begin, const char *End)
+ : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
+
+ // Return true if string literal is next.
+ bool Next(const std::string &S) {
+ std::string::size_type LEN = S.length();
+ P = C;
+ PEnd = C + LEN;
+ if (PEnd > End)
+ return false;
+ return !memcmp(P, S.c_str(), LEN);
+ }
+
+ // Return true if number is next.
+ // Output N only if number is next.
+ bool Next(unsigned &N) {
+ unsigned TMP = 0;
+ P = C;
+ for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
+ TMP *= 10;
+ TMP += P[0] - '0';
}
- CommentStart += 2;
-
- // Find the }}.
- const char *ExpectedEnd = CommentStart;
- while (1) {
- ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
- if (CommentEnd-ExpectedEnd < 2) {
- PP.Diag(Pos, diag::err_verify_missing_end);
- return;
- }
+ if (P == C)
+ return false;
+ PEnd = P;
+ N = TMP;
+ return true;
+ }
+
+ // Return true if string literal is found.
+ // When true, P marks begin-position of S in content.
+ bool Search(const std::string &S) {
+ P = std::search(C, End, S.begin(), S.end());
+ PEnd = P + S.length();
+ return P != End;
+ }
+
+ // Advance 1-past previous next/search.
+ // Behavior is undefined if previous next/search failed.
+ bool Advance() {
+ C = PEnd;
+ return C < End;
+ }
+
+ // Skip zero or more whitespace.
+ void SkipWhitespace() {
+ for (; C < End && isspace(*C); ++C)
+ ;
+ }
+
+ // Return true if EOF reached.
+ bool Done() {
+ return !(C < End);
+ }
+
+ const char * const Begin; // beginning of expected content
+ const char * const End; // end of expected content (1-past)
+ const char *C; // position of next char in content
+ const char *P;
+
+private:
+ const char *PEnd; // previous next/search subject end (1-past)
+};
+
+} // namespace anonymous
+
+/// ParseDirective - Go through the comment and see if it indicates expected
+/// diagnostics. If so, then put them in the appropriate directive list.
+///
+static void ParseDirective(const char *CommentStart, unsigned CommentLen,
+ ExpectedData &ED, Preprocessor &PP,
+ SourceLocation Pos) {
+ // A single comment may contain multiple directives.
+ for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
+ // search for token: expected
+ if (!PH.Search("expected"))
+ break;
+ PH.Advance();
+
+ // next token: -
+ if (!PH.Next("-"))
+ continue;
+ PH.Advance();
+
+ // next token: { error | warning | note }
+ DirectiveList* DL = NULL;
+ if (PH.Next("error"))
+ DL = &ED.Errors;
+ else if (PH.Next("warning"))
+ DL = &ED.Warnings;
+ else if (PH.Next("note"))
+ DL = &ED.Notes;
+ else
+ continue;
+ PH.Advance();
- if (ExpectedEnd[1] == '}')
- break;
+ // default directive kind
+ bool RegexKind = false;
+ const char* KindStr = "string";
- ++ExpectedEnd; // Skip over singular }'s
+ // next optional token: -
+ if (PH.Next("-re")) {
+ PH.Advance();
+ RegexKind = true;
+ KindStr = "regex";
}
- std::string Msg(CommentStart, ExpectedEnd);
- std::string::size_type FindPos;
- while ((FindPos = Msg.find("\\n")) != std::string::npos)
- Msg.replace(FindPos, 2, "\n");
- // Add is possibly multiple times.
- for (int i = 0; i < Times; ++i)
- ExpectedDiags.push_back(std::make_pair(Pos, Msg));
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next optional token: positive integer
+ unsigned Count = 1;
+ if (PH.Next(Count))
+ PH.Advance();
+
+ // skip optional whitespace
+ PH.SkipWhitespace();
+
+ // next token: {{
+ if (!PH.Next("{{")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_start) << KindStr;
+ continue;
+ }
+ PH.Advance();
+ const char* const ContentBegin = PH.C; // mark content begin
- CommentStart = ExpectedEnd;
+ // search for token: }}
+ if (!PH.Search("}}")) {
+ PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
+ diag::err_verify_missing_end) << KindStr;
+ continue;
+ }
+ const char* const ContentEnd = PH.P; // mark content end
+ PH.Advance();
+
+ // build directive text; convert \n to newlines
+ std::string Text;
+ llvm::StringRef NewlineStr = "\\n";
+ llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin);
+ size_t CPos = 0;
+ size_t FPos;
+ while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) {
+ Text += Content.substr(CPos, FPos-CPos);
+ Text += '\n';
+ CPos = FPos + NewlineStr.size();
+ }
+ if (Text.empty())
+ Text.assign(ContentBegin, ContentEnd);
+
+ // construct new directive
+ Directive *D = Directive::Create(RegexKind, Pos, Text, Count);
+ std::string Error;
+ if (D->isValid(Error))
+ DL->push_back(D);
+ else {
+ PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_invalid_content)
+ << KindStr << Error;
+ }
}
}
/// FindExpectedDiags - Lex the main source file to find all of the
// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP,
- DiagList &ExpectedErrors,
- DiagList &ExpectedWarnings,
- DiagList &ExpectedNotes) {
+static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) {
// Create a raw lexer to pull all the comments out of the main file. We don't
// want to look in #include'd headers for expected-error strings.
SourceManager &SM = PP.getSourceManager();
@@ -185,17 +356,8 @@ static void FindExpectedDiags(Preprocessor &PP,
std::string Comment = PP.getSpelling(Tok);
if (Comment.empty()) continue;
- // Find all expected errors.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
- Tok.getLocation(), "expected-error");
-
- // Find all expected warnings.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
- Tok.getLocation(), "expected-warning");
-
- // Find all expected notes.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
- Tok.getLocation(), "expected-note");
+ // Find all expected errors/warnings/notes.
+ ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation());
};
}
@@ -225,49 +387,68 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
return std::distance(diag_begin, diag_end);
}
-/// CompareDiagLists - Compare two diagnostic lists and return the difference
-/// between them.
+static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
+ DirectiveList &DL, const char *Kind,
+ bool Expected) {
+ if (DL.empty())
+ return 0;
+
+ llvm::SmallString<256> Fmt;
+ llvm::raw_svector_ostream OS(Fmt);
+ for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
+ Directive& D = **I;
+ if (D.Location.isInvalid() || !SourceMgr)
+ OS << "\n (frontend)";
+ else
+ OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location);
+ OS << ": " << D.Text;
+ }
+
+ Diags.Report(diag::err_verify_inconsistent_diags)
+ << Kind << !Expected << OS.str();
+ return DL.size();
+}
+
+/// CheckLists - Compare expected to seen diagnostic lists and return the
+/// the difference between them.
///
-static unsigned CompareDiagLists(Diagnostic &Diags,
- SourceManager &SourceMgr,
- const_diag_iterator d1_begin,
- const_diag_iterator d1_end,
- const_diag_iterator d2_begin,
- const_diag_iterator d2_end,
- const char *Label) {
- DiagList LeftOnly;
- DiagList Left(d1_begin, d1_end);
+static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
+ const char *Label,
+ DirectiveList &Left,
+ const_diag_iterator d2_begin,
+ const_diag_iterator d2_end) {
+ DirectiveList LeftOnly;
DiagList Right(d2_begin, d2_end);
- for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
- unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
- const std::string &Diag1 = I->second;
+ for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
+ Directive& D = **I;
+ unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location);
- DiagList::iterator II, IE;
- for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
- if (LineNo1 != LineNo2) continue;
+ for (unsigned i = 0; i < D.Count; ++i) {
+ DiagList::iterator II, IE;
+ for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
+ unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
+ if (LineNo1 != LineNo2)
+ continue;
- const std::string &Diag2 = II->second;
- if (Diag2.find(Diag1) != std::string::npos ||
- Diag1.find(Diag2) != std::string::npos) {
- break;
+ const std::string &RightText = II->second;
+ if (D.Match(RightText))
+ break;
+ }
+ if (II == IE) {
+ // Not found.
+ LeftOnly.push_back(*I);
+ } else {
+ // Found. The same cannot be found twice.
+ Right.erase(II);
}
- }
- if (II == IE) {
- // Not found.
- LeftOnly.push_back(*I);
- } else {
- // Found. The same cannot be found twice.
- Right.erase(II);
}
}
// Now all that's left in Right are those that were not matched.
- return (PrintProblem(Diags, &SourceMgr,
- LeftOnly.begin(), LeftOnly.end(), Label, true) +
- PrintProblem(Diags, &SourceMgr,
- Right.begin(), Right.end(), Label, false));
+ return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
+ PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
+ Label, false));
}
/// CheckResults - This compares the expected results to those that
@@ -276,9 +457,7 @@ static unsigned CompareDiagLists(Diagnostic &Diags,
///
static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
const TextDiagnosticBuffer &Buffer,
- const DiagList &ExpectedErrors,
- const DiagList &ExpectedWarnings,
- const DiagList &ExpectedNotes) {
+ ExpectedData &ED) {
// We want to capture the delta between what was expected and what was
// seen.
//
@@ -287,31 +466,22 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
unsigned NumProblems = 0;
// See if there are error mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedErrors.begin(), ExpectedErrors.end(),
- Buffer.err_begin(), Buffer.err_end(),
- "error");
+ NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
+ Buffer.err_begin(), Buffer.err_end());
// See if there are warning mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedWarnings.begin(),
- ExpectedWarnings.end(),
- Buffer.warn_begin(), Buffer.warn_end(),
- "warning");
+ NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
+ Buffer.warn_begin(), Buffer.warn_end());
// See if there are note mismatches.
- NumProblems += CompareDiagLists(Diags, SourceMgr,
- ExpectedNotes.begin(),
- ExpectedNotes.end(),
- Buffer.note_begin(), Buffer.note_end(),
- "note");
+ NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
+ Buffer.note_begin(), Buffer.note_end());
return NumProblems;
}
-
void VerifyDiagnosticsClient::CheckDiagnostics() {
- DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
+ ExpectedData ED;
// Ensure any diagnostics go to the primary client.
DiagnosticClient *CurClient = Diags.getClient();
@@ -320,13 +490,11 @@ void VerifyDiagnosticsClient::CheckDiagnostics() {
// If we have a preprocessor, scan the source for expected diagnostic
// markers. If not then any diagnostics are unexpected.
if (CurrentPreprocessor) {
- FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings,
- ExpectedNotes);
+ FindExpectedDiags(*CurrentPreprocessor, ED);
// Check that the expected diagnostics occurred.
NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(),
- *Buffer,
- ExpectedErrors, ExpectedWarnings, ExpectedNotes);
+ *Buffer, ED);
} else {
NumErrors += (PrintProblem(Diags, 0,
Buffer->err_begin(), Buffer->err_end(),
@@ -344,3 +512,10 @@ void VerifyDiagnosticsClient::CheckDiagnostics() {
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
}
+
+Directive* Directive::Create(bool RegexKind, const SourceLocation &Location,
+ const std::string &Text, unsigned Count) {
+ if (RegexKind)
+ return new RegexDirective(Location, Text, Count);
+ return new StandardDirective(Location, Text, Count);
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index ea9635e79849..84c4f5d40faf 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -35,6 +35,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
const DiagnosticOptions &Opts) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
+
+ // Handle -ferror-limit
+ if (Opts.ErrorLimit)
+ Diags.setErrorLimit(Opts.ErrorLimit);
+ if (Opts.TemplateBacktraceLimit)
+ Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
// If -pedantic or -pedantic-errors was specified, then we want to map all
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index e63291b2af90..047fdb30ce21 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,4 +1,6 @@
set(files
+ altivec.h
+ arm_neon.h
emmintrin.h
float.h
iso646.h
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
new file mode 100644
index 000000000000..1cd0db8e4b84
--- /dev/null
+++ b/lib/Headers/altivec.h
@@ -0,0 +1,1483 @@
+/*===---- altivec.h - Standard header for type generic math ---------------===*\
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef __ALTIVEC_H
+#define __ALTIVEC_H
+
+#ifndef __ALTIVEC__
+#error "AltiVec support not enabled"
+#endif
+
+/* constants for mapping CR6 bits to predicate result. */
+
+#define __CR6_EQ 0
+#define __CR6_EQ_REV 1
+#define __CR6_LT 2
+#define __CR6_LT_REV 3
+
+#define _ATTRS_o_ai __attribute__((__overloadable__, __always_inline__))
+
+/* vec_abs */
+
+#define __builtin_vec_abs vec_abs
+#define __builtin_altivec_abs_v16qi vec_abs
+#define __builtin_altivec_abs_v8hi vec_abs
+#define __builtin_altivec_abs_v4si vec_abs
+
+static vector signed char _ATTRS_o_ai
+vec_abs(vector signed char a)
+{
+ return __builtin_altivec_vmaxsb(a, -a);
+}
+
+static vector signed short _ATTRS_o_ai
+vec_abs(vector signed short a)
+{
+ return __builtin_altivec_vmaxsh(a, -a);
+}
+
+static vector signed int _ATTRS_o_ai
+vec_abs(vector signed int a)
+{
+ return __builtin_altivec_vmaxsw(a, -a);
+}
+
+static vector float _ATTRS_o_ai
+vec_abs(vector float a)
+{
+ vector unsigned int res = (vector unsigned int)a &
+ (vector unsigned int)(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF);
+ return (vector float)res;
+}
+
+/* vec_abss */
+
+#define __builtin_vec_abss vec_abss
+#define __builtin_altivec_abss_v16qi vec_abss
+#define __builtin_altivec_abss_v8hi vec_abss
+#define __builtin_altivec_abss_v4si vec_abss
+
+static vector signed char _ATTRS_o_ai
+vec_abss(vector signed char a)
+{
+ return __builtin_altivec_vmaxsb(a, __builtin_altivec_vsubsbs(
+ (vector signed char)(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), a));
+}
+
+static vector signed short _ATTRS_o_ai
+vec_abss(vector signed short a)
+{
+ return __builtin_altivec_vmaxsh(a, __builtin_altivec_vsubshs(
+ (vector signed short)(0, 0, 0, 0, 0, 0, 0, 0), a));
+}
+
+static vector signed int _ATTRS_o_ai
+vec_abss(vector signed int a)
+{
+ return __builtin_altivec_vmaxsw(a, __builtin_altivec_vsubsws(
+ (vector signed int)(0, 0, 0, 0), a));
+}
+
+/* vec_add */
+
+#define __builtin_altivec_vaddubm vec_add
+#define __builtin_altivec_vadduhm vec_add
+#define __builtin_altivec_vadduwm vec_add
+#define __builtin_altivec_vaddfp vec_add
+#define __builtin_vec_vaddubm vec_add
+#define __builtin_vec_vadduhm vec_add
+#define __builtin_vec_vadduwm vec_add
+#define __builtin_vec_vaddfp vec_add
+#define vec_vaddubm vec_add
+#define vec_vadduhm vec_add
+#define vec_vadduwm vec_add
+#define vec_vaddfp vec_add
+
+static vector signed char _ATTRS_o_ai
+vec_add(vector signed char a, vector signed char b)
+{
+ return a + b;
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_add(vector unsigned char a, vector unsigned char b)
+{
+ return a + b;
+}
+
+static vector short _ATTRS_o_ai
+vec_add(vector short a, vector short b)
+{
+ return a + b;
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_add(vector unsigned short a, vector unsigned short b)
+{
+ return a + b;
+}
+
+static vector int _ATTRS_o_ai
+vec_add(vector int a, vector int b)
+{
+ return a + b;
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_add(vector unsigned int a, vector unsigned int b)
+{
+ return a + b;
+}
+
+static vector float _ATTRS_o_ai
+vec_add(vector float a, vector float b)
+{
+ return a + b;
+}
+
+/* vec_addc */
+
+#define __builtin_vec_addc __builtin_altivec_vaddcuw
+#define vec_vaddcuw __builtin_altivec_vaddcuw
+#define vec_addc __builtin_altivec_vaddcuw
+
+/* vec_adds */
+
+#define __builtin_vec_vaddsbs __builtin_altivec_vaddsbs
+#define __builtin_vec_vaddubs __builtin_altivec_vaddubs
+#define __builtin_vec_vaddshs __builtin_altivec_vaddshs
+#define __builtin_vec_vadduhs __builtin_altivec_vadduhs
+#define __builtin_vec_vaddsws __builtin_altivec_vaddsws
+#define __builtin_vec_vadduws __builtin_altivec_vadduws
+#define vec_vaddsbs __builtin_altivec_vaddsbs
+#define vec_vaddubs __builtin_altivec_vaddubs
+#define vec_vaddshs __builtin_altivec_vaddshs
+#define vec_vadduhs __builtin_altivec_vadduhs
+#define vec_vaddsws __builtin_altivec_vaddsws
+#define vec_vadduws __builtin_altivec_vadduws
+
+static vector signed char _ATTRS_o_ai
+vec_adds(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vaddsbs(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_adds(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vaddubs(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_adds(vector short a, vector short b)
+{
+ return __builtin_altivec_vaddshs(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_adds(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vadduhs(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_adds(vector int a, vector int b)
+{
+ return __builtin_altivec_vaddsws(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_adds(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vadduws(a, b);
+}
+
+/* vec_sub */
+
+#define __builtin_altivec_vsububm vec_sub
+#define __builtin_altivec_vsubuhm vec_sub
+#define __builtin_altivec_vsubuwm vec_sub
+#define __builtin_altivec_vsubfp vec_sub
+#define __builtin_vec_vsububm vec_sub
+#define __builtin_vec_vsubuhm vec_sub
+#define __builtin_vec_vsubuwm vec_sub
+#define __builtin_vec_vsubfp vec_sub
+#define vec_vsububm vec_sub
+#define vec_vsubuhm vec_sub
+#define vec_vsubuwm vec_sub
+#define vec_vsubfp vec_sub
+
+static vector signed char _ATTRS_o_ai
+vec_sub(vector signed char a, vector signed char b)
+{
+ return a - b;
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_sub(vector unsigned char a, vector unsigned char b)
+{
+ return a - b;
+}
+
+static vector short _ATTRS_o_ai
+vec_sub(vector short a, vector short b)
+{
+ return a - b;
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_sub(vector unsigned short a, vector unsigned short b)
+{
+ return a - b;
+}
+
+static vector int _ATTRS_o_ai
+vec_sub(vector int a, vector int b)
+{
+ return a - b;
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_sub(vector unsigned int a, vector unsigned int b)
+{
+ return a - b;
+}
+
+static vector float _ATTRS_o_ai
+vec_sub(vector float a, vector float b)
+{
+ return a - b;
+}
+
+/* vec_subs */
+
+#define __builtin_vec_vsubsbs __builtin_altivec_vsubsbs
+#define __builtin_vec_vsububs __builtin_altivec_vsububs
+#define __builtin_vec_vsubshs __builtin_altivec_vsubshs
+#define __builtin_vec_vsubuhs __builtin_altivec_vsubuhs
+#define __builtin_vec_vsubsws __builtin_altivec_vsubsws
+#define __builtin_vec_vsubuws __builtin_altivec_vsubuws
+#define vec_vsubsbs __builtin_altivec_vsubsbs
+#define vec_vsububs __builtin_altivec_vsububs
+#define vec_vsubshs __builtin_altivec_vsubshs
+#define vec_vsubuhs __builtin_altivec_vsubuhs
+#define vec_vsubsws __builtin_altivec_vsubsws
+#define vec_vsubuws __builtin_altivec_vsubuws
+
+static vector signed char _ATTRS_o_ai
+vec_subs(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vsubsbs(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_subs(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vsububs(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_subs(vector short a, vector short b)
+{
+ return __builtin_altivec_vsubshs(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_subs(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vsubuhs(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_subs(vector int a, vector int b)
+{
+ return __builtin_altivec_vsubsws(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_subs(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vsubuws(a, b);
+}
+
+/* vec_avg */
+
+#define __builtin_vec_vavgsb __builtin_altivec_vavgsb
+#define __builtin_vec_vavgub __builtin_altivec_vavgub
+#define __builtin_vec_vavgsh __builtin_altivec_vavgsh
+#define __builtin_vec_vavguh __builtin_altivec_vavguh
+#define __builtin_vec_vavgsw __builtin_altivec_vavgsw
+#define __builtin_vec_vavguw __builtin_altivec_vavguw
+#define vec_vavgsb __builtin_altivec_vavgsb
+#define vec_vavgub __builtin_altivec_vavgub
+#define vec_vavgsh __builtin_altivec_vavgsh
+#define vec_vavguh __builtin_altivec_vavguh
+#define vec_vavgsw __builtin_altivec_vavgsw
+#define vec_vavguw __builtin_altivec_vavguw
+
+static vector signed char _ATTRS_o_ai
+vec_avg(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vavgsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_avg(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vavgub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_avg(vector short a, vector short b)
+{
+ return __builtin_altivec_vavgsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_avg(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vavguh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_avg(vector int a, vector int b)
+{
+ return __builtin_altivec_vavgsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_avg(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vavguw(a, b);
+}
+
+/* vec_st */
+
+#define __builtin_vec_st vec_st
+#define vec_stvx vec_st
+
+static void _ATTRS_o_ai
+vec_st(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_st(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvx((vector int)a, b, (void *)c);
+}
+
+/* vec_stl */
+
+#define __builtin_vec_stl vec_stl
+#define vec_stvxl vec_stl
+
+static void _ATTRS_o_ai
+vec_stl(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvxl(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_stl(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvxl((vector int)a, b, (void *)c);
+}
+
+/* vec_ste */
+
+#define __builtin_vec_stvebx __builtin_altivec_stvebx
+#define __builtin_vec_stvehx __builtin_altivec_stvehx
+#define __builtin_vec_stvewx __builtin_altivec_stvewx
+#define vec_stvebx __builtin_altivec_stvebx
+#define vec_stvehx __builtin_altivec_stvehx
+#define vec_stvewx __builtin_altivec_stvewx
+
+static void _ATTRS_o_ai
+vec_ste(vector signed char a, int b, vector signed char *c)
+{
+ __builtin_altivec_stvebx((vector char)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned char a, int b, vector unsigned char *c)
+{
+ __builtin_altivec_stvebx((vector char)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector short a, int b, vector short *c)
+{
+ __builtin_altivec_stvehx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned short a, int b, vector unsigned short *c)
+{
+ __builtin_altivec_stvehx((vector short)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector int a, int b, vector int *c)
+{
+ __builtin_altivec_stvewx(a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector unsigned int a, int b, vector unsigned int *c)
+{
+ __builtin_altivec_stvewx((vector int)a, b, (void *)c);
+}
+
+static void _ATTRS_o_ai
+vec_ste(vector float a, int b, vector float *c)
+{
+ __builtin_altivec_stvewx((vector int)a, b, (void *)c);
+}
+
+/* vec_cmpb */
+
+#define vec_cmpb __builtin_altivec_vcmpbfp
+#define vec_vcmpbfp __builtin_altivec_vcmpbfp
+#define __builtin_vec_cmpb __builtin_altivec_vcmpbfp
+
+/* vec_cmpeq */
+
+#define __builtin_vec_cmpeq vec_cmpeq
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpeq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpeq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpeq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpeq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh((vector short)a, (vector short)b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw((vector int)a, (vector int)b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpeq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp(a, b);
+}
+
+/* vec_cmpge */
+
+#define vec_cmpge __builtin_altivec_vcmpgefp
+#define vec_vcmpgefp __builtin_altivec_vcmpgefp
+#define __builtin_vec_cmpge __builtin_altivec_vcmpgefp
+
+/* vec_cmpgt */
+
+#define vec_vcmpgtsb __builtin_altivec_vcmpgtsb
+#define vec_vcmpgtub __builtin_altivec_vcmpgtub
+#define vec_vcmpgtsh __builtin_altivec_vcmpgtsh
+#define vec_vcmpgtuh __builtin_altivec_vcmpgtuh
+#define vec_vcmpgtsw __builtin_altivec_vcmpgtsw
+#define vec_vcmpgtuw __builtin_altivec_vcmpgtuw
+#define vec_vcmpgtfp __builtin_altivec_vcmpgtfp
+#define __builtin_vec_vcmpgtsb __builtin_altivec_vcmpgtsb
+#define __builtin_vec_vcmpgtub __builtin_altivec_vcmpgtub
+#define __builtin_vec_vcmpgtsh __builtin_altivec_vcmpgtsh
+#define __builtin_vec_vcmpgtuh __builtin_altivec_vcmpgtuh
+#define __builtin_vec_vcmpgtsw __builtin_altivec_vcmpgtsw
+#define __builtin_vec_vcmpgtuw __builtin_altivec_vcmpgtuw
+#define __builtin_vec_vcmpgtfp __builtin_altivec_vcmpgtfp
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpgt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb(a, b);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmpgt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpgt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh(a, b);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmpgt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw(a, b);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmpgt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp(a, b);
+}
+
+/* vec_cmple */
+
+#define __builtin_vec_cmple vec_cmple
+
+static vector /*bool*/ int __attribute__((__always_inline__))
+vec_cmple(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp(b, a);
+}
+
+/* vec_cmplt */
+
+#define __builtin_vec_cmplt vec_cmplt
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmplt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb(b, a);
+}
+
+static vector /*bool*/ char _ATTRS_o_ai
+vec_cmplt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub(b, a);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmplt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh(b, a);
+}
+
+static vector /*bool*/ short _ATTRS_o_ai
+vec_cmplt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw(b, a);
+}
+
+static vector /*bool*/ int _ATTRS_o_ai
+vec_cmplt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp(b, a);
+}
+
+/* vec_max */
+
+#define __builtin_vec_vmaxsb __builtin_altivec_vmaxsb
+#define __builtin_vec_vmaxub __builtin_altivec_vmaxub
+#define __builtin_vec_vmaxsh __builtin_altivec_vmaxsh
+#define __builtin_vec_vmaxuh __builtin_altivec_vmaxuh
+#define __builtin_vec_vmaxsw __builtin_altivec_vmaxsw
+#define __builtin_vec_vmaxuw __builtin_altivec_vmaxuw
+#define __builtin_vec_vmaxfp __builtin_altivec_vmaxfp
+#define vec_vmaxsb __builtin_altivec_vmaxsb
+#define vec_vmaxub __builtin_altivec_vmaxub
+#define vec_vmaxsh __builtin_altivec_vmaxsh
+#define vec_vmaxuh __builtin_altivec_vmaxuh
+#define vec_vmaxsw __builtin_altivec_vmaxsw
+#define vec_vmaxuw __builtin_altivec_vmaxuw
+#define vec_vmaxfp __builtin_altivec_vmaxfp
+#define __builtin_vec_max vec_max
+
+static vector signed char _ATTRS_o_ai
+vec_max(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vmaxsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_max(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vmaxub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_max(vector short a, vector short b)
+{
+ return __builtin_altivec_vmaxsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_max(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vmaxuh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_max(vector int a, vector int b)
+{
+ return __builtin_altivec_vmaxsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_max(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vmaxuw(a, b);
+}
+
+static vector float _ATTRS_o_ai
+vec_max(vector float a, vector float b)
+{
+ return __builtin_altivec_vmaxfp(a, b);
+}
+
+/* vec_mfvscr */
+
+#define __builtin_vec_mfvscr __builtin_altivec_mfvscr
+#define vec_mfvscr __builtin_altivec_mfvscr
+
+/* vec_min */
+
+#define __builtin_vec_vminsb __builtin_altivec_vminsb
+#define __builtin_vec_vminub __builtin_altivec_vminub
+#define __builtin_vec_vminsh __builtin_altivec_vminsh
+#define __builtin_vec_vminuh __builtin_altivec_vminuh
+#define __builtin_vec_vminsw __builtin_altivec_vminsw
+#define __builtin_vec_vminuw __builtin_altivec_vminuw
+#define __builtin_vec_vminfp __builtin_altivec_vminfp
+#define vec_vminsb __builtin_altivec_vminsb
+#define vec_vminub __builtin_altivec_vminub
+#define vec_vminsh __builtin_altivec_vminsh
+#define vec_vminuh __builtin_altivec_vminuh
+#define vec_vminsw __builtin_altivec_vminsw
+#define vec_vminuw __builtin_altivec_vminuw
+#define vec_vminfp __builtin_altivec_vminfp
+#define __builtin_vec_min vec_min
+
+static vector signed char _ATTRS_o_ai
+vec_min(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vminsb(a, b);
+}
+
+static vector unsigned char _ATTRS_o_ai
+vec_min(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vminub(a, b);
+}
+
+static vector short _ATTRS_o_ai
+vec_min(vector short a, vector short b)
+{
+ return __builtin_altivec_vminsh(a, b);
+}
+
+static vector unsigned short _ATTRS_o_ai
+vec_min(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vminuh(a, b);
+}
+
+static vector int _ATTRS_o_ai
+vec_min(vector int a, vector int b)
+{
+ return __builtin_altivec_vminsw(a, b);
+}
+
+static vector unsigned int _ATTRS_o_ai
+vec_min(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vminuw(a, b);
+}
+
+static vector float _ATTRS_o_ai
+vec_min(vector float a, vector float b)
+{
+ return __builtin_altivec_vminfp(a, b);
+}
+
+/* vec_mtvscr */
+
+#define __builtin_vec_mtvscr __builtin_altivec_mtvscr
+#define vec_mtvscr __builtin_altivec_mtvscr
+
+/* ------------------------------ predicates ------------------------------------ */
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpeq_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(CR6_param, a, b);
+}
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpge_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(CR6_param, a, b);
+}
+
+static int __attribute__((__always_inline__))
+__builtin_vec_vcmpgt_p(char CR6_param, vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(CR6_param, a, b);
+}
+
+/* vec_all_eq */
+
+static int _ATTRS_o_ai
+vec_all_eq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_eq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b);
+}
+
+/* vec_all_ge */
+
+static int _ATTRS_o_ai
+vec_all_ge(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_ge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+}
+
+/* vec_all_gt */
+
+static int _ATTRS_o_ai
+vec_all_gt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_gt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b);
+}
+
+/* vec_all_in */
+
+static int __attribute__((__always_inline__))
+vec_all_in(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_le */
+
+static int _ATTRS_o_ai
+vec_all_le(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_le(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_lt */
+
+static int _ATTRS_o_ai
+vec_all_lt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_all_lt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+}
+
+/* vec_all_nan */
+
+static int __attribute__((__always_inline__))
+vec_all_nan(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a);
+}
+
+/* vec_all_ne */
+
+static int _ATTRS_o_ai
+vec_all_ne(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_all_ne(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_nge */
+
+static int __attribute__((__always_inline__))
+vec_all_nge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_ngt */
+
+static int __attribute__((__always_inline__))
+vec_all_ngt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+}
+
+/* vec_all_nle */
+
+static int __attribute__((__always_inline__))
+vec_all_nle(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a);
+}
+
+/* vec_all_nlt */
+
+static int __attribute__((__always_inline__))
+vec_all_nlt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a);
+}
+
+/* vec_all_numeric */
+
+static int __attribute__((__always_inline__))
+vec_all_numeric(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a);
+}
+
+/* vec_any_eq */
+
+static int _ATTRS_o_ai
+vec_any_eq(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_eq(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b);
+}
+
+/* vec_any_ge */
+
+static int _ATTRS_o_ai
+vec_any_ge(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_ge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_gt */
+
+static int _ATTRS_o_ai
+vec_any_gt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_gt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b);
+}
+
+/* vec_any_le */
+
+static int _ATTRS_o_ai
+vec_any_le(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_le(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_lt */
+
+static int _ATTRS_o_ai
+vec_any_lt(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a);
+}
+
+static int _ATTRS_o_ai
+vec_any_lt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a);
+}
+
+/* vec_any_nan */
+
+static int __attribute__((__always_inline__))
+vec_any_nan(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a);
+}
+
+/* vec_any_ne */
+
+static int _ATTRS_o_ai
+vec_any_ne(vector signed char a, vector signed char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned char a, vector unsigned char b)
+{
+ return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector short a, vector short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned short a, vector unsigned short b)
+{
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector int a, vector int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector unsigned int a, vector unsigned int b)
+{
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+}
+
+static int _ATTRS_o_ai
+vec_any_ne(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_nge */
+
+static int __attribute__((__always_inline__))
+vec_any_nge(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_ngt */
+
+static int __attribute__((__always_inline__))
+vec_any_ngt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+}
+
+/* vec_any_nle */
+
+static int __attribute__((__always_inline__))
+vec_any_nle(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_nlt */
+
+static int __attribute__((__always_inline__))
+vec_any_nlt(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+}
+
+/* vec_any_numeric */
+
+static int __attribute__((__always_inline__))
+vec_any_numeric(vector float a)
+{
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, a);
+}
+
+/* vec_any_out */
+
+static int __attribute__((__always_inline__))
+vec_any_out(vector float a, vector float b)
+{
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, a, b);
+}
+
+#undef _ATTRS_o_ai
+
+#endif /* __ALTIVEC_H */
diff --git a/lib/Headers/arm_neon.h b/lib/Headers/arm_neon.h
new file mode 100644
index 000000000000..4508a27f36a4
--- /dev/null
+++ b/lib/Headers/arm_neon.h
@@ -0,0 +1,537 @@
+/*===---- arm_neon.h - NEON intrinsics --------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __ARM_NEON_H
+#define __ARM_NEON_H
+
+#ifndef __ARM_NEON__
+#error "NEON support not enabled"
+#endif
+
+// NEON document appears to be specified in terms of stdint types.
+#include <stdint.h>
+
+// Define some NEON-specific scalar types for floats and polynomials.
+typedef float float32_t;
+typedef uint8_t poly8_t;
+
+// FIXME: probably need a 'poly' attribute or something for correct codegen to
+// disambiguate from uint16_t.
+typedef uint16_t poly16_t;
+
+typedef __attribute__(( __vector_size__(8) )) int8_t __neon_int8x8_t;
+typedef __attribute__(( __vector_size__(16) )) int8_t __neon_int8x16_t;
+typedef __attribute__(( __vector_size__(8) )) int16_t __neon_int16x4_t;
+typedef __attribute__(( __vector_size__(16) )) int16_t __neon_int16x8_t;
+typedef __attribute__(( __vector_size__(8) )) int32_t __neon_int32x2_t;
+typedef __attribute__(( __vector_size__(16) )) int32_t __neon_int32x4_t;
+typedef __attribute__(( __vector_size__(8) )) int64_t __neon_int64x1_t;
+typedef __attribute__(( __vector_size__(16) )) int64_t __neon_int64x2_t;
+typedef __attribute__(( __vector_size__(8) )) uint8_t __neon_uint8x8_t;
+typedef __attribute__(( __vector_size__(16) )) uint8_t __neon_uint8x16_t;
+typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_uint16x4_t;
+typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_uint16x8_t;
+typedef __attribute__(( __vector_size__(8) )) uint32_t __neon_uint32x2_t;
+typedef __attribute__(( __vector_size__(16) )) uint32_t __neon_uint32x4_t;
+typedef __attribute__(( __vector_size__(8) )) uint64_t __neon_uint64x1_t;
+typedef __attribute__(( __vector_size__(16) )) uint64_t __neon_uint64x2_t;
+typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_float16x4_t;
+typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_float16x8_t;
+typedef __attribute__(( __vector_size__(8) )) float32_t __neon_float32x2_t;
+typedef __attribute__(( __vector_size__(16) )) float32_t __neon_float32x4_t;
+typedef __attribute__(( __vector_size__(8) )) poly8_t __neon_poly8x8_t;
+typedef __attribute__(( __vector_size__(16) )) poly8_t __neon_poly8x16_t;
+typedef __attribute__(( __vector_size__(8) )) poly16_t __neon_poly16x4_t;
+typedef __attribute__(( __vector_size__(16) )) poly16_t __neon_poly16x8_t;
+
+typedef struct __int8x8_t {
+ __neon_int8x8_t val;
+} int8x8_t;
+
+typedef struct __int8x16_t {
+ __neon_int8x16_t val;
+} int8x16_t;
+
+typedef struct __int16x4_t {
+ __neon_int16x4_t val;
+} int16x4_t;
+
+typedef struct __int16x8_t {
+ __neon_int16x8_t val;
+} int16x8_t;
+
+typedef struct __int32x2_t {
+ __neon_int32x2_t val;
+} int32x2_t;
+
+typedef struct __int32x4_t {
+ __neon_int32x4_t val;
+} int32x4_t;
+
+typedef struct __int64x1_t {
+ __neon_int64x1_t val;
+} int64x1_t;
+
+typedef struct __int64x2_t {
+ __neon_int64x2_t val;
+} int64x2_t;
+
+typedef struct __uint8x8_t {
+ __neon_uint8x8_t val;
+} uint8x8_t;
+
+typedef struct __uint8x16_t {
+ __neon_uint8x16_t val;
+} uint8x16_t;
+
+typedef struct __uint16x4_t {
+ __neon_uint16x4_t val;
+} uint16x4_t;
+
+typedef struct __uint16x8_t {
+ __neon_uint16x8_t val;
+} uint16x8_t;
+
+typedef struct __uint32x2_t {
+ __neon_uint32x2_t val;
+} uint32x2_t;
+
+typedef struct __uint32x4_t {
+ __neon_uint32x4_t val;
+} uint32x4_t;
+
+typedef struct __uint64x1_t {
+ __neon_uint64x1_t val;
+} uint64x1_t;
+
+typedef struct __uint64x2_t {
+ __neon_uint64x2_t val;
+} uint64x2_t;
+
+typedef struct __float16x4_t {
+ __neon_float16x4_t val;
+} float16x4_t;
+
+typedef struct __float16x8_t {
+ __neon_float16x8_t val;
+} float16x8_t;
+
+typedef struct __float32x2_t {
+ __neon_float32x2_t val;
+} float32x2_t;
+
+typedef struct __float32x4_t {
+ __neon_float32x4_t val;
+} float32x4_t;
+
+typedef struct __poly8x8_t {
+ __neon_poly8x8_t val;
+} poly8x8_t;
+
+typedef struct __poly8x16_t {
+ __neon_poly8x16_t val;
+} poly8x16_t;
+
+typedef struct __poly16x4_t {
+ __neon_poly16x4_t val;
+} poly16x4_t;
+
+typedef struct __poly16x8_t {
+ __neon_poly16x8_t val;
+} poly16x8_t;
+
+// FIXME: write tool to stamp out the structure-of-array types, possibly gen this whole file.
+
+// Intrinsics, per ARM document DUI0348B
+#define __ai static __attribute__((__always_inline__))
+
+#define INTTYPES_WIDE(op, builtin) \
+ __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_WIDENING(op, builtin) \
+ __ai int16x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_WIDENING_MUL(op, builtin) \
+ __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b, int8x8_t c) { return (int16x8_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b, int16x4_t c) { return (int32x4_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b, int32x2_t c) { return (int64x2_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) { return (uint16x8_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) { return (uint32x4_t){ builtin(a.val, b.val, c.val) }; } \
+ __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) { return (uint64x2_t){ builtin(a.val, b.val, c.val) }; }
+
+#define INTTYPES_NARROWING(op, builtin) \
+ __ai int8x8_t op##_s16(int16x8_t a, int16x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s32(int32x4_t a, int32x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s64(int64x2_t a, int64x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u16(uint16x8_t a, uint16x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u32(uint32x4_t a, uint32x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u64(uint64x2_t a, uint64x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_ADD_32(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ builtin(a.val, b.val) }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; }
+
+#define INTTYPES_ADD_64(op, builtin) \
+ __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ builtin(a.val, b.val) }; } \
+ __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; }
+
+#define FLOATTYPES_CMP(op, builtin) \
+ __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; }
+
+#define INT_FLOAT_CMP_OP(op, cc) \
+ __ai uint8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (uint8x8_t){(__neon_uint8x8_t)(a.val cc b.val)}; } \
+ __ai uint16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (uint16x4_t){(__neon_uint16x4_t)(a.val cc b.val)}; } \
+ __ai uint32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \
+ __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val cc b.val}; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val cc b.val}; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val cc b.val}; } \
+ __ai uint8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (uint8x16_t){(__neon_uint8x16_t)(a.val cc b.val)}; } \
+ __ai uint16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (uint16x8_t){(__neon_uint16x8_t)(a.val cc b.val)}; } \
+ __ai uint32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \
+ __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val cc b.val}; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val cc b.val}; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val cc b.val}; }
+
+#define INT_UNARY(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a) { return (int8x8_t){ builtin(a.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a) { return (int16x4_t){ builtin(a.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a) { return (int32x2_t){ builtin(a.val) }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a) { return (int8x16_t){ builtin(a.val) }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a) { return (int16x8_t){ builtin(a.val) }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a) { return (int32x4_t){ builtin(a.val) }; }
+
+#define FP_UNARY(op, builtin) \
+ __ai float32x2_t op##_f32(float32x2_t a) { return (float32x2_t){ builtin(a.val) }; } \
+ __ai float32x4_t op##q_f32(float32x4_t a) { return (float32x4_t){ builtin(a.val) }; }
+
+#define FP_BINARY(op, builtin) \
+ __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } \
+ __ai float32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){ builtin(a.val, b.val) }; }
+
+#define INT_FP_PAIRWISE_ADD(op, builtin) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \
+ __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; }
+
+#define INT_LOGICAL_OP(op, lop) \
+ __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ a.val lop b.val }; } \
+ __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ a.val lop b.val }; } \
+ __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ a.val lop b.val }; } \
+ __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ a.val lop b.val }; } \
+ __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ a.val lop b.val }; } \
+ __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ a.val lop b.val }; } \
+ __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ a.val lop b.val }; } \
+ __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ a.val lop b.val }; } \
+ __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ a.val lop b.val }; } \
+ __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ a.val lop b.val }; } \
+ __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ a.val lop b.val }; } \
+ __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ a.val lop b.val }; } \
+ __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ a.val lop b.val }; } \
+ __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ a.val lop b.val }; } \
+ __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ a.val lop b.val }; } \
+ __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ a.val lop b.val }; }
+
+// vector add
+__ai int8x8_t vadd_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){a.val + b.val}; }
+__ai int16x4_t vadd_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){a.val + b.val}; }
+__ai int32x2_t vadd_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){a.val + b.val}; }
+__ai int64x1_t vadd_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){a.val + b.val}; }
+__ai float32x2_t vadd_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){a.val + b.val}; }
+__ai uint8x8_t vadd_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val + b.val}; }
+__ai uint16x4_t vadd_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val + b.val}; }
+__ai uint32x2_t vadd_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val + b.val}; }
+__ai uint64x1_t vadd_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){a.val + b.val}; }
+__ai int8x16_t vaddq_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){a.val + b.val}; }
+__ai int16x8_t vaddq_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){a.val + b.val}; }
+__ai int32x4_t vaddq_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){a.val + b.val}; }
+__ai int64x2_t vaddq_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){a.val + b.val}; }
+__ai float32x4_t vaddq_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){a.val + b.val}; }
+__ai uint8x16_t vaddq_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val + b.val}; }
+__ai uint16x8_t vaddq_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val + b.val}; }
+__ai uint32x4_t vaddq_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val + b.val}; }
+__ai uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){a.val + b.val}; }
+
+// vector long add
+INTTYPES_WIDENING(vaddl, __builtin_neon_vaddl)
+
+// vector wide add
+INTTYPES_WIDE(vaddw, __builtin_neon_vaddw)
+
+// halving add
+// rounding halving add
+INTTYPES_ADD_32(vhadd, __builtin_neon_vhadd)
+INTTYPES_ADD_32(vrhadd, __builtin_neon_vrhadd)
+
+// saturating add
+INTTYPES_ADD_32(vqadd, __builtin_neon_vqadd)
+INTTYPES_ADD_64(vqadd, __builtin_neon_vqadd)
+
+// add high half
+// rounding add high half
+INTTYPES_NARROWING(vaddhn, __builtin_neon_vaddhn)
+INTTYPES_NARROWING(vraddhn, __builtin_neon_vraddhn)
+
+// multiply
+// mul-poly
+
+// multiple accumulate
+// multiple subtract
+
+// multiple accumulate long
+// multiple subtract long
+INTTYPES_WIDENING_MUL(vmlal, __builtin_neon_vmlal)
+INTTYPES_WIDENING_MUL(vmlsl, __builtin_neon_vmlsl)
+
+// saturating doubling multiply high
+// saturating rounding doubling multiply high
+
+// saturating doubling multiply accumulate long
+// saturating doubling multiply subtract long
+
+// long multiply
+// long multiply-poly
+INTTYPES_WIDENING(vmull, __builtin_neon_vmull)
+__ai poly16x8_t vmull_p8(poly8x8_t a, poly8x8_t b) { return (poly16x8_t){ __builtin_neon_vmull(a.val, b.val) }; }
+
+// saturating doubling long multiply
+
+// subtract
+
+// long subtract
+INTTYPES_WIDENING(vsubl, __builtin_neon_vsubl)
+
+// wide subtract
+INTTYPES_WIDE(vsubw, __builtin_neon_vsubw)
+
+// saturating subtract
+INTTYPES_ADD_32(vqsub, __builtin_neon_vqsub)
+INTTYPES_ADD_64(vqsub, __builtin_neon_vqsub)
+
+// halving subtract
+INTTYPES_ADD_32(vhsub, __builtin_neon_vhsub)
+
+// subtract high half
+// rounding subtract high half
+INTTYPES_NARROWING(vsubhn, __builtin_neon_vsubhn)
+INTTYPES_NARROWING(vrsubhn, __builtin_neon_vrsubhn)
+
+// compare eq
+// compare ge
+// compare le
+// compare gt
+// compare lt
+INT_FLOAT_CMP_OP(vceq, ==)
+INT_FLOAT_CMP_OP(vcge, >=)
+INT_FLOAT_CMP_OP(vcle, <=)
+INT_FLOAT_CMP_OP(vcgt, >)
+INT_FLOAT_CMP_OP(vclt, <)
+
+// compare eq-poly
+
+// compare abs ge
+// compare abs le
+// compare abs gt
+// compare abs lt
+FLOATTYPES_CMP(vcage, __builtin_neon_vcage)
+FLOATTYPES_CMP(vcale, __builtin_neon_vcale)
+FLOATTYPES_CMP(vcagt, __builtin_neon_vcagt)
+FLOATTYPES_CMP(vcalt, __builtin_neon_vcalt)
+
+// test bits
+
+// abs diff
+INTTYPES_ADD_32(vabd, __builtin_neon_vabd)
+FP_BINARY(vabd, __builtin_neon_vabd)
+
+// abs diff long
+INTTYPES_WIDENING(vabdl, __builtin_neon_vabdl)
+
+// abs diff accumulate
+// abs diff accumulate long
+
+// max
+// min
+INTTYPES_ADD_32(vmax, __builtin_neon_vmax)
+FP_BINARY(vmax, __builtin_neon_vmax)
+INTTYPES_ADD_32(vmin, __builtin_neon_vmin)
+FP_BINARY(vmin, __builtin_neon_vmin)
+
+// pairwise add
+// pairwise max
+// pairwise min
+INT_FP_PAIRWISE_ADD(vpadd, __builtin_neon_vpadd)
+INT_FP_PAIRWISE_ADD(vpmax, __builtin_neon_vpmax)
+INT_FP_PAIRWISE_ADD(vpmin, __builtin_neon_vpmin)
+
+// long pairwise add
+// long pairwise add accumulate
+
+// recip
+// recip sqrt
+FP_BINARY(vrecps, __builtin_neon_vrecps)
+FP_BINARY(vrsqrts, __builtin_neon_vrsqrts)
+
+// shl by vec
+// saturating shl by vec
+// rounding shl by vec
+// saturating rounding shl by vec
+
+// shr by constant
+// shl by constant
+// rounding shr by constant
+// shr by constant and accumulate
+// rounding shr by constant and accumulate
+// saturating shl by constant
+// s->u saturating shl by constant
+// narrowing saturating shr by constant
+// s->u narrowing saturating shr by constant
+// s->u rounding narrowing saturating shr by constant
+// narrowing saturating shr by constant
+// rounding narrowing shr by constant
+// rounding narrowing saturating shr by constant
+// widening shl by constant
+
+// shr and insert
+// shl and insert
+
+// loads and stores, single vector
+// loads and stores, lane
+// loads, dupe
+
+// loads and stores, arrays
+
+// vget,vgetq lane
+// vset, vsetq lane
+
+// vcreate
+// vdup, vdupq
+// vmov, vmovq
+// vdup_lane, vdupq_lane
+// vcombine
+// vget_high, vget_low
+
+// vcvt {u,s} <-> f, f <-> f16
+// narrow
+// long move (unpack)
+// saturating narrow
+// saturating narrow s->u
+
+// table lookup
+// extended table lookup
+
+// mla with scalar
+// widening mla with scalar
+// widening saturating doubling mla with scalar
+// mls with scalar
+// widening mls with scalar
+// widening saturating doubling mls with scalar
+// mul by scalar
+// long mul with scalar
+// long mul by scalar
+// saturating doubling long mul with scalar
+// saturating doubling long mul by scalar
+// saturating doubling mul high with scalar
+// saturating doubling mul high by scalar
+// saturating rounding doubling mul high with scalar
+// saturating rounding doubling mul high by scalar
+// mla with scalar
+// widening mla with sclar
+// widening saturating doubling mla with scalar
+// mls with scalar
+// widening mls with scalar
+// widening saturating doubling mls with scalar
+
+// extract
+
+// endian swap (vrev)
+
+// negate
+
+// abs
+// saturating abs
+// saturating negate
+// count leading signs
+INT_UNARY(vabs, __builtin_neon_vabs)
+FP_UNARY(vabs, __builtin_neon_vabs)
+INT_UNARY(vqabs, __builtin_neon_vqabs)
+INT_UNARY(vqneg, __builtin_neon_vqneg)
+INT_UNARY(vcls, __builtin_neon_vcls)
+
+// count leading zeroes
+// popcount
+
+// recip_est
+// recip_sqrt_est
+
+// not-poly
+// not
+
+// and
+// or
+// xor
+// andn
+// orn
+INT_LOGICAL_OP(vand, &)
+INT_LOGICAL_OP(vorr, |)
+INT_LOGICAL_OP(veor, ^)
+INT_LOGICAL_OP(vbic, &~)
+INT_LOGICAL_OP(vorn, |~)
+
+// bitselect
+
+// transpose elts
+// interleave elts
+// deinterleave elts
+
+// vreinterpret
+
+#endif /* __ARM_NEON_H */
diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h
index f24352b24691..cc213ce46b6e 100644
--- a/lib/Headers/nmmintrin.h
+++ b/lib/Headers/nmmintrin.h
@@ -32,4 +32,4 @@
just include it now then. */
#include <smmintrin.h>
#endif /* __SSE4_2__ */
-#endif /* _NMMINTRIN_H */ \ No newline at end of file
+#endif /* _NMMINTRIN_H */
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index 15b6eaa62708..1785f315dfbe 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -218,11 +218,18 @@ typedef __uint_least8_t uint_fast8_t;
#define __intn_t(n) __stdint_join3( int, n, _t)
#define __uintn_t(n) __stdint_join3(uint, n, _t)
+#ifndef _INTPTR_T
#ifndef __intptr_t_defined
typedef __intn_t(__INTPTR_WIDTH__) intptr_t;
#define __intptr_t_defined
+#define _INTPTR_T
#endif
+#endif
+
+#ifndef _UINTPTR_T
typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t;
+#define _UINTPTR_T
+#endif
/* C99 7.18.1.5 Greatest-width integer types.
*/
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 09ebc2378016..07fea1c98bf0 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -67,7 +67,7 @@ _mm_abs_epi32(__m128i a)
}
#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
-#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8)))
+#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n)))
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi16(__m128i a, __m128i b)
diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp
index c24f3bf5b3c1..091bc78c2669 100644
--- a/lib/Index/ASTLocation.cpp
+++ b/lib/Index/ASTLocation.cpp
@@ -87,7 +87,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_Decl:
OS << "[Decl: " << AsDecl()->getDeclKindName() << " ";
if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl()))
- OS << ND->getNameAsString();
+ OS << ND;
break;
case N_Stmt:
@@ -97,7 +97,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const {
case N_NamedRef:
OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " ";
- OS << AsNamedRef().ND->getNameAsString();
+ OS << AsNamedRef().ND;
break;
case N_Type: {
diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp
index 7b414f2a9fb5..1354fe6be0d2 100644
--- a/lib/Index/Analyzer.cpp
+++ b/lib/Index/Analyzer.cpp
@@ -153,9 +153,10 @@ public:
ObjCInterfaceDecl *MsgD = 0;
ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
- if (Msg->getReceiver()) {
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: {
const ObjCObjectPointerType *OPT =
- Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+ Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType();
// Can be anything! Accept it as a possibility..
if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
@@ -171,15 +172,34 @@ public:
// Should be an instance method.
if (!IsInstanceMethod)
return false;
+ break;
+ }
- } else {
+ case ObjCMessageExpr::Class: {
+ // Expecting class method.
+ if (IsInstanceMethod)
+ return false;
+
+ MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+ }
+
+ case ObjCMessageExpr::SuperClass:
// Expecting class method.
if (IsInstanceMethod)
return false;
- MsgD = Msg->getClassInfo().Decl;
- // FIXME: Case when we only have an identifier.
- assert(MsgD && "Identifier only");
+ MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ // Expecting instance method.
+ if (!IsInstanceMethod)
+ return false;
+
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
}
assert(MsgD);
@@ -248,31 +268,44 @@ public:
ObjCInterfaceDecl *MsgD = 0;
while (true) {
- if (Msg->getReceiver() == 0) {
- CanBeClassMethod = true;
- MsgD = Msg->getClassInfo().Decl;
- // FIXME: Case when we only have an identifier.
- assert(MsgD && "Identifier only");
- break;
- }
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: {
+ const ObjCObjectPointerType *OPT =
+ Msg->getInstanceReceiver()->getType()
+ ->getAsObjCInterfacePointerType();
+
+ if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
+ CanBeInstanceMethod = CanBeClassMethod = true;
+ break;
+ }
- const ObjCObjectPointerType *OPT =
- Msg->getReceiver()->getType()->getAsObjCInterfacePointerType();
+ if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
+ CanBeClassMethod = true;
+ break;
+ }
- if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
- CanBeInstanceMethod = CanBeClassMethod = true;
+ MsgD = OPT->getInterfaceDecl();
+ assert(MsgD);
+ CanBeInstanceMethod = true;
break;
}
+
+ case ObjCMessageExpr::Class:
+ CanBeClassMethod = true;
+ MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
- if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
+ case ObjCMessageExpr::SuperClass:
CanBeClassMethod = true;
+ MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
break;
- }
- MsgD = OPT->getInterfaceDecl();
- assert(MsgD);
- CanBeInstanceMethod = true;
- break;
+ case ObjCMessageExpr::SuperInstance:
+ CanBeInstanceMethod = true;
+ MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+ }
}
assert(CanBeInstanceMethod || CanBeClassMethod);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 19f25ea4a8bb..74e8d7489e9a 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1874,9 +1874,10 @@ LexNextToken:
if (PP->isCurrentLexer(this)) {
// Start a new token. If this is a #include or something, the PP may
// want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag.
+ // the StartOfLine flag and clear LeadingSpace.
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
IsAtStartOfLine = false;
}
goto LexNextToken; // GCC isn't tail call eliminating.
@@ -2024,9 +2025,10 @@ LexNextToken:
if (PP->isCurrentLexer(this)) {
// Start a new token. If this is a #include or something, the PP may
// want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag.
+ // the StartOfLine flag and clear LeadingSpace.
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
IsAtStartOfLine = false;
}
goto LexNextToken; // GCC isn't tail call eliminating.
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 1cfa0e374506..f4255822641d 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -654,6 +654,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0);
unsigned NumCharsSoFar = 0;
+ bool Warned = false;
while (begin[0] != '\'') {
uint64_t ResultChar;
if (begin[0] != '\\') // If this is a normal character, consume it.
@@ -670,8 +671,10 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
} else {
// Narrow character literals act as though their value is concatenated
// in this implementation, but warn on overflow.
- if (LitVal.countLeadingZeros() < 8)
+ if (LitVal.countLeadingZeros() < 8 && !Warned) {
PP.Diag(Loc, diag::warn_char_constant_too_large);
+ Warned = true;
+ }
LitVal <<= 8;
}
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 757ba9014df6..417724b77787 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -716,7 +716,8 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
if (Callbacks)
- Callbacks->FileChanged(DigitTok.getLocation(), PPCallbacks::RenameFile,
+ Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
+ PPCallbacks::RenameFile,
SrcMgr::C_User);
}
@@ -865,7 +866,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
else if (IsSystemHeader)
FileKind = SrcMgr::C_System;
- Callbacks->FileChanged(DigitTok.getLocation(), Reason, FileKind);
+ Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
}
}
@@ -1087,11 +1088,6 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
- // Ask HeaderInfo if we should enter this #include file. If not, #including
- // this file will have no effect.
- if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
- return;
-
// The #included file will be considered to be a system header if either it is
// in a system include directory, or if the #includer is a system include
// header.
@@ -1099,6 +1095,14 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
std::max(HeaderInfo.getFileDirFlavor(File),
SourceMgr.getFileCharacteristic(FilenameTok.getLocation()));
+ // Ask HeaderInfo if we should enter this #include file. If not, #including
+ // this file will have no effect.
+ if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) {
+ if (Callbacks)
+ Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
+ return;
+ }
+
// Look up the file, create a File ID for it.
FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
FileCharacter);
@@ -1108,10 +1112,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
}
// Finally, if all is good, enter the new file!
- std::string ErrorStr;
- if (EnterSourceFile(FID, CurDir, ErrorStr))
- Diag(FilenameTok, diag::err_pp_error_opening_file)
- << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr;
+ EnterSourceFile(FID, CurDir, FilenameTok.getLocation());
}
/// HandleIncludeNextDirective - Implements #include_next.
@@ -1666,4 +1667,3 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/CI.FoundElse);
}
-
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 335d3db627dd..4a4040599263 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -64,8 +64,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer.
-bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
- std::string &ErrorStr) {
+void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
+ SourceLocation Loc) {
assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
@@ -75,19 +75,23 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
if (PTH) {
if (PTHLexer *PL = PTH->CreateLexer(FID)) {
EnterSourceFileWithPTH(PL, CurDir);
- return false;
+ return;
}
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
bool Invalid = false;
- const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID,
- &Invalid);
- if (Invalid)
- return true;
+ const llvm::MemoryBuffer *InputFile =
+ getSourceManager().getBuffer(FID, Loc, &Invalid);
+ if (Invalid) {
+ SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID);
+ Diag(Loc, diag::err_pp_error_opening_file)
+ << std::string(SourceMgr.getBufferName(FileStart)) << "";
+ return;
+ }
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
- return false;
+ return;
}
/// EnterSourceFileWithLexer - Add a source file to the top of the include stack
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 1c6a5ad0ebce..71bb4fcf684a 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -487,28 +487,29 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
return llvm::StringSwitch<bool>(II->getName())
+ .Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_cf_returns_not_retained", true)
+ .Case("attribute_cf_returns_retained", true)
+ .Case("attribute_ext_vector_type", true)
+ .Case("attribute_ns_returns_not_retained", true)
+ .Case("attribute_ns_returns_retained", true)
+ .Case("attribute_objc_ivar_unused", true)
+ .Case("attribute_overloadable", true)
.Case("blocks", LangOpts.Blocks)
- .Case("cxx_rtti", LangOpts.RTTI)
- //.Case("cxx_lambdas", false)
- //.Case("cxx_nullptr", false)
- //.Case("cxx_concepts", false)
- .Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
+ .Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
.Case("cxx_exceptions", LangOpts.Exceptions)
- .Case("cxx_attributes", LangOpts.CPlusPlus0x)
+ .Case("cxx_rtti", LangOpts.RTTI)
.Case("cxx_static_assert", LangOpts.CPlusPlus0x)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
- .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
+ .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
+ //.Case("cxx_concepts", false)
+ //.Case("cxx_lambdas", false)
+ //.Case("cxx_nullptr", false)
//.Case("cxx_rvalue_references", false)
- .Case("attribute_overloadable", true)
//.Case("cxx_variadic_templates", false)
- .Case("attribute_ext_vector_type", true)
- .Case("attribute_analyzer_noreturn", true)
- .Case("attribute_cf_returns_not_retained", true)
- .Case("attribute_cf_returns_retained", true)
- .Case("attribute_ns_returns_not_retained", true)
- .Case("attribute_ns_returns_retained", true)
- .Case("attribute_objc_ivar_unused", true)
.Default(false);
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 4598383c1c93..ce6d9ab5c053 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -490,7 +490,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
-bool Preprocessor::EnterMainSourceFile() {
+void Preprocessor::EnterMainSourceFile() {
// We do not allow the preprocessor to reenter the main file. Doing so will
// cause FileID's to accumulate information from both runs (e.g. #line
// information) and predefined macros aren't guaranteed to be set properly.
@@ -498,9 +498,7 @@ bool Preprocessor::EnterMainSourceFile() {
FileID MainFileID = SourceMgr.getMainFileID();
// Enter the main file source buffer.
- std::string ErrorStr;
- if (EnterSourceFile(MainFileID, 0, ErrorStr))
- return true;
+ EnterSourceFile(MainFileID, 0, SourceLocation());
// Tell the header info that the main file was entered. If the file is later
// #imported, it won't be re-entered.
@@ -515,7 +513,7 @@ bool Preprocessor::EnterMainSourceFile() {
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
// Start parsing the predefines.
- return EnterSourceFile(FID, 0, ErrorStr);
+ EnterSourceFile(FID, 0, SourceLocation());
}
void Preprocessor::EndSourceFile() {
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index 51d2e2326fca..fc6db2151a3a 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -124,7 +124,8 @@ static char GetFirstChar(Preprocessor &PP, const Token &Tok) {
/// but the resulting output won't have incorrect concatenations going on.
/// Examples include "..", which we print with a space between, because we
/// don't want to track enough to tell "x.." from "...".
-bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
+bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
+ const Token &PrevTok,
const Token &Tok) const {
// First, check to see if the tokens were directly adjacent in the original
// source. If they were, it must be okay to stick them together: if there
@@ -192,7 +193,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok,
return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
FirstChar == '+' || FirstChar == '-' || FirstChar == '.';
case tok::period: // ..., .*, .1234
- return FirstChar == '.' || isdigit(FirstChar) ||
+ return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
+ isdigit(FirstChar) ||
(PP.getLangOptions().CPlusPlus && FirstChar == '*');
case tok::amp: // &&
return FirstChar == '&';
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index 3cd74d57f56d..bae2a09a9882 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -23,7 +23,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
AttributeList *n, bool declspec, bool cxx0x)
: AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc),
ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n),
- DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) {
+ DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) {
if (numArgs == 0)
Args = 0;
@@ -105,6 +105,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("overloadable", AT_overloadable)
.Case("address_space", AT_address_space)
.Case("always_inline", AT_always_inline)
+ .Case("returns_twice", IgnoredAttribute)
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
.Case("ext_vector_type", AT_ext_vector_type)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 11865ab97b84..5dc08b3dfa2c 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -433,6 +433,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
+ SaveStorageSpecifierAsWritten();
// Check the type specifier components first.
SourceManager &SrcMgr = PP.getSourceManager();
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 5f48897235ab..5a0376781175 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -26,11 +26,40 @@ ActionBase::~ActionBase() {}
/// Out-of-line virtual destructor to provide home for Action class.
Action::~Action() {}
+Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType) {
+ ReceiverType = 0;
+
+ if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope())
+ return ObjCSuperMessage;
+
+ if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) {
+ DeclSpec DS;
+ const char *PrevSpec = 0;
+ unsigned DiagID = 0;
+ if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec,
+ DiagID, TyName)) {
+ DS.SetRangeEnd(NameLoc);
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Ty = ActOnTypeName(S, DeclaratorInfo);
+ if (!Ty.isInvalid())
+ ReceiverType = Ty.get();
+ }
+ return ObjCClassMessage;
+ }
+
+ return ObjCInstanceMessage;
+}
+
// Defined out-of-line here because of dependecy on AttributeList
Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList) {
@@ -47,7 +76,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -144,7 +173,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
Action::TypeTy *
MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName, TypeTy *ObjectType) {
if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
if (TI->isTypeName)
@@ -161,7 +190,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
TemplateNameKind
MinimalAction::isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringScope,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 87e22fa9dce0..5405c0cb78ef 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -29,12 +29,14 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
"Current token not a '{', ':' or 'try'!");
Action::MultiTemplateParamsArg TemplateParams(Actions,
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
+
DeclPtrTy FnD;
if (D.getDeclSpec().isFriendSpecified())
// FIXME: Friend templates
- FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
+ FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true,
+ move(TemplateParams));
else // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
move(TemplateParams), 0, 0,
@@ -53,7 +55,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
// We may have a constructor initializer or function-try-block here.
if (kind == tok::colon || kind == tok::kw_try) {
// Consume everything up to (and including) the left brace.
- if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
+ if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) {
// We didn't find the left-brace we expected after the
// constructor initializer.
if (Tok.is(tok::semi)) {
@@ -72,13 +74,13 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
ConsumeBrace();
}
// Consume everything up to (and including) the matching right brace.
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
// If we're in a function-try-block, we need to store all the catch blocks.
if (kind == tok::kw_try) {
while (Tok.is(tok::kw_catch)) {
- ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
}
}
@@ -98,7 +100,8 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
// The current scope is still active if we're the top-level class.
// Otherwise we'll need to push and enter a new scope.
bool HasClassScope = !Class.TopLevelClass;
- ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope);
+ ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
+ HasClassScope);
if (HasClassScope)
Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
@@ -217,12 +220,17 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
"ParseFunctionTryBlock left tokens in the token stream!");
continue;
}
- if (Tok.is(tok::colon))
+ if (Tok.is(tok::colon)) {
ParseConstructorInitializer(LM.D);
- else
+
+ // Error recovery.
+ if (!Tok.is(tok::l_brace)) {
+ Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions));
+ continue;
+ }
+ } else
Actions.ActOnDefaultCtorInitializers(LM.D);
- // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
Tok.getLocation()) &&
@@ -238,14 +246,12 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
/// container until the token 'T' is reached (which gets
/// consumed/stored too, if ConsumeFinalToken).
-/// If EarlyAbortIf is specified, then we will stop early if we find that
-/// token at the top level.
+/// If StopAtSemi is true, then we will stop early at a ';' character.
/// Returns true if token 'T1' or 'T2' was found.
/// NOTE: This is a specialized version of Parser::SkipUntil.
bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
CachedTokens &Toks,
- tok::TokenKind EarlyAbortIf,
- bool ConsumeFinalToken) {
+ bool StopAtSemi, bool ConsumeFinalToken) {
// We always want this function to consume at least one token if the first
// token isn't T and if not at EOF.
bool isFirstTokenConsumed = true;
@@ -259,10 +265,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
return true;
}
- // If we found the early-abort token, return.
- if (Tok.is(EarlyAbortIf))
- return false;
-
switch (Tok.getKind()) {
case tok::eof:
// Ran out of tokens.
@@ -272,19 +274,19 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
// Recursively consume properly-nested parens.
Toks.push_back(Tok);
ConsumeParen();
- ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
break;
case tok::l_square:
// Recursively consume properly-nested square brackets.
Toks.push_back(Tok);
ConsumeBracket();
- ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false);
break;
case tok::l_brace:
// Recursively consume properly-nested braces.
Toks.push_back(Tok);
ConsumeBrace();
- ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
break;
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
@@ -316,6 +318,10 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
Toks.push_back(Tok);
ConsumeStringToken();
break;
+ case tok::semi:
+ if (StopAtSemi)
+ return false;
+ // FALL THROUGH.
default:
// consume this token.
Toks.push_back(Tok);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index c85b6ee9746c..91050e0a4cf9 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -904,7 +904,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// reinforced by the NAD status of core issue 635.
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
- if (DSContext == DSC_top_level && TemplateId->Name &&
+ if ((DSContext == DSC_top_level ||
+ (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
if (isConstructorDeclarator()) {
// The user meant this to be an out-of-line constructor
@@ -949,7 +951,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
- if (DSContext == DSC_top_level &&
+ if ((DSContext == DSC_top_level ||
+ (DSContext == DSC_class && DS.isFriendSpecified())) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope,
&SS)) {
if (isConstructorDeclarator())
@@ -1434,6 +1437,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
+ // If we already have a type specifier, this identifier is not a type.
+ if (DS.getTypeSpecType() != DeclSpec::TST_unspecified ||
+ DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
+ DS.getTypeSpecSign() != DeclSpec::TSS_unspecified)
+ return false;
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
@@ -1892,15 +1900,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- // enums cannot be templates.
- if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
- Diag(Tok, diag::err_enum_template);
-
- // Skip the rest of this declarator, up until the comma or semicolon.
- SkipUntil(tok::comma, true);
- return;
- }
-
// If an identifier is present, consume and remember it.
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
@@ -1924,23 +1923,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TUK = Action::TUK_Declaration;
else
TUK = Action::TUK_Reference;
+
+ // enums cannot be templates, although they can be referenced from a
+ // template.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ TUK != Action::TUK_Reference) {
+ Diag(Tok, diag::err_enum_template);
+
+ // Skip the rest of this declarator, up until the comma or semicolon.
+ SkipUntil(tok::comma, true);
+ return;
+ }
+
bool Owned = false;
bool IsDependent = false;
+ SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
+ const char *PrevSpec = 0;
+ unsigned DiagID;
DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, Attr.get(),
AS,
Action::MultiTemplateParamsArg(Actions),
Owned, IsDependent);
- assert(!IsDependent && "didn't expect dependent enum");
+ if (IsDependent) {
+ // This enum has a dependent nested-name-specifier. Handle it as a
+ // dependent tag.
+ if (!Name) {
+ DS.SetTypeSpecError();
+ Diag(Tok, diag::err_expected_type_name_after_typename);
+ return;
+ }
+
+ TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum,
+ TUK, SS, Name, StartLoc,
+ NameLoc);
+ if (Type.isInvalid()) {
+ DS.SetTypeSpecError();
+ return;
+ }
+
+ if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID,
+ Type.get(), false))
+ Diag(StartLoc, DiagID) << PrevSpec;
+
+ return;
+ }
+ if (!TagDecl.get()) {
+ // The action failed to produce an enumeration tag. If this is a
+ // definition, consume the entire definition.
+ if (Tok.is(tok::l_brace)) {
+ ConsumeBrace();
+ SkipUntil(tok::r_brace);
+ }
+
+ DS.SetTypeSpecError();
+ return;
+ }
+
if (Tok.is(tok::l_brace))
ParseEnumBody(StartLoc, TagDecl);
// FIXME: The DeclSpec should keep the locations of both the keyword and the
// name (if there is one).
- SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
- const char *PrevSpec = 0;
- unsigned DiagID;
if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
TagDecl.getAs<void>(), Owned))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -2427,7 +2472,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail
- if (SS.isSet()) {
+ if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
D.getCXXScopeSpec() = SS;
@@ -2583,36 +2628,42 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
if (getLang().CPlusPlus && D.mayHaveIdentifier()) {
// ParseDeclaratorInternal might already have parsed the scope.
- bool afterCXXScope = D.getCXXScopeSpec().isSet();
- if (!afterCXXScope) {
+ if (D.getCXXScopeSpec().isEmpty()) {
ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0,
true);
- afterCXXScope = D.getCXXScopeSpec().isSet();
}
- if (afterCXXScope) {
+ if (D.getCXXScopeSpec().isValid()) {
if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec()))
// Change the declaration context for name lookup, until this function
// is exited (and the declarator has been parsed).
DeclScopeObj.EnterDeclaratorScope();
- }
-
+ }
+
if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) ||
Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
// We found something that indicates the start of an unqualified-id.
// Parse that unqualified-id.
- bool AllowConstructorName
- = ((D.getCXXScopeSpec().isSet() &&
- D.getContext() == Declarator::FileContext) ||
- (!D.getCXXScopeSpec().isSet() &&
- D.getContext() == Declarator::MemberContext)) &&
- !D.getDeclSpec().hasTypeSpecifier();
+ bool AllowConstructorName;
+ if (D.getDeclSpec().hasTypeSpecifier())
+ AllowConstructorName = false;
+ else if (D.getCXXScopeSpec().isSet())
+ AllowConstructorName =
+ (D.getContext() == Declarator::FileContext ||
+ (D.getContext() == Declarator::MemberContext &&
+ D.getDeclSpec().isFriendSpecified()));
+ else
+ AllowConstructorName = (D.getContext() == Declarator::MemberContext);
+
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
AllowConstructorName,
/*ObjectType=*/0,
- D.getName())) {
+ D.getName()) ||
+ // Once we're past the identifier, if the scope was bad, mark the
+ // whole declarator bad.
+ D.getCXXScopeSpec().isInvalid()) {
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
} else {
@@ -2974,7 +3025,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DefArgToks = new CachedTokens;
if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,
- tok::semi, false)) {
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false)) {
delete DefArgToks;
DefArgToks = 0;
Actions.ActOnParamDefaultArgumentError(Param);
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 813c24ce3d58..015ac5b5dddd 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -178,7 +178,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
DeclPtrTy LinkageSpec
= Actions.ActOnStartLinkageSpecification(CurScope,
/*FIXME: */SourceLocation(),
- Loc, Lang.data(), Lang.size(),
+ Loc, Lang,
Tok.is(tok::l_brace)? Tok.getLocation()
: SourceLocation());
@@ -465,7 +465,7 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
/// simple-template-id
///
Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
- const CXXScopeSpec *SS) {
+ CXXScopeSpec *SS) {
// Check whether we have a template-id that names a type.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
@@ -780,9 +780,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Action::DeclResult TagOrTempResult = true; // invalid
Action::TypeResult TypeResult = true; // invalid
- // FIXME: When TUK == TUK_Reference and we have a template-id, we need
- // to turn that template-id into a type.
-
bool Owned = false;
if (TemplateId) {
// Explicit specialization, class template partial specialization,
@@ -806,7 +803,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateArgsPtr,
TemplateId->RAngleLoc,
AttrList);
- } else if (TUK == Action::TUK_Reference) {
+
+ // Friend template-ids are treated as references unless
+ // they have template headers, in which case they're ill-formed
+ // (FIXME: "template <class T> friend class A<T>::B<int>;").
+ // We diagnose this error in ActOnClassTemplateSpecialization.
+ } else if (TUK == Action::TUK_Reference ||
+ (TUK == Action::TUK_Friend &&
+ TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
TypeResult
= Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index af91021d33ce..b9e632a1846e 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -29,30 +29,6 @@
#include "llvm/ADT/SmallString.h"
using namespace clang;
-/// PrecedenceLevels - These are precedences for the binary/ternary operators in
-/// the C99 grammar. These have been named to relate with the C99 grammar
-/// productions. Low precedences numbers bind more weakly than high numbers.
-namespace prec {
- enum Level {
- Unknown = 0, // Not binary operator.
- Comma = 1, // ,
- Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
- Conditional = 3, // ?
- LogicalOr = 4, // ||
- LogicalAnd = 5, // &&
- InclusiveOr = 6, // |
- ExclusiveOr = 7, // ^
- And = 8, // &
- Equality = 9, // ==, !=
- Relational = 10, // >=, <=, >, <
- Shift = 11, // <<, >>
- Additive = 12, // -, +
- Multiplicative = 13, // *, /, %
- PointerToMember = 14 // .*, ->*
- };
-}
-
-
/// getBinOpPrecedence - Return the precedence of the specified binary operator
/// token. This returns:
///
@@ -268,11 +244,11 @@ Parser::OwningExprResult Parser::ParseAssignmentExpression() {
/// expressions and other binary operators for these expressions as well.
Parser::OwningExprResult
Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
- SourceLocation NameLoc,
- IdentifierInfo *ReceiverName,
+ SourceLocation SuperLoc,
+ TypeTy *ReceiverType,
ExprArg ReceiverExpr) {
- OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc,
- ReceiverName,
+ OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc,
+ ReceiverType,
move(ReceiverExpr)));
if (R.isInvalid()) return move(R);
R = ParsePostfixExpressionSuffix(move(R));
@@ -297,10 +273,10 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
/// LHS and has a precedence of at least MinPrec.
Parser::OwningExprResult
-Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
- unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
- GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
+ prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
SourceLocation ColonLoc;
while (1) {
@@ -335,14 +311,15 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
Diag(Tok, diag::ext_gnu_conditional_expr);
}
- if (Tok.isNot(tok::colon)) {
- Diag(Tok, diag::err_expected_colon);
+ if (Tok.is(tok::colon)) {
+ // Eat the colon.
+ ColonLoc = ConsumeToken();
+ } else {
+ Diag(Tok, diag::err_expected_colon)
+ << FixItHint::CreateInsertion(Tok.getLocation(), ": ");
Diag(OpToken, diag::note_matching) << "?";
- return ExprError();
+ ColonLoc = Tok.getLocation();
}
-
- // Eat the colon.
- ColonLoc = ConsumeToken();
}
// Parse another leaf here for the RHS of the operator.
@@ -362,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
- unsigned ThisPrec = NextTokPrec;
+ prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLang().CPlusPlus0x);
@@ -379,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
// A=(B=(C=D)), where each paren is a level of recursion here.
// The function takes ownership of the RHS.
- RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+ RHS = ParseRHSOfBinaryExpression(move(RHS),
+ static_cast<prec::Level>(ThisPrec + !isRightAssoc));
if (RHS.isInvalid())
return move(RHS);
@@ -480,7 +458,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [OBJC] '@encode' '(' type-name ')'
/// [OBJC] objc-string-literal
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO]
+/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
@@ -500,14 +478,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
///
/// id-expression: [C++ 5.1]
/// unqualified-id
-/// qualified-id [TODO]
+/// qualified-id
///
/// unqualified-id: [C++ 5.1]
/// identifier
/// operator-function-id
-/// conversion-function-id [TODO]
-/// '~' class-name [TODO]
-/// template-id [TODO]
+/// conversion-function-id
+/// '~' class-name
+/// template-id
///
/// new-expression: [C++ 5.3.4]
/// '::'[opt] 'new' new-placement[opt] new-type-id
@@ -637,11 +615,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
- // Support 'Class.property' notation. We don't use
- // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is
- // inappropriate here).
+ // Support 'Class.property' and 'super.property' notation.
if (getLang().ObjC1 && Tok.is(tok::period) &&
- Actions.getTypeName(II, ILoc, CurScope)) {
+ (Actions.getTypeName(II, ILoc, CurScope) ||
+ // Allow the base to be 'super' if in an objc-method.
+ (&II == Ident_super && CurScope->isInObjcMethodScope()))) {
SourceLocation DotLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
@@ -810,6 +788,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ // (We can end up in this situation after tentative parsing.)
+ if (TryAnnotateTypeOrScopeToken())
+ return ExprError();
+ if (!Tok.is(tok::annot_cxxscope))
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
+
Token Next = NextToken();
if (Next.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
@@ -897,11 +883,16 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::caret:
return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression());
+ case tok::code_completion:
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
+ ConsumeToken();
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, TypeOfCast);
case tok::l_square:
// These can be followed by postfix-expr pieces.
if (getLang().ObjC1)
return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
- // FALL THROUGH.
+ // FALL THROUGH.
default:
NotCastExpr = true;
return ExprError();
@@ -1431,10 +1422,19 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
CastTy = Ty.get();
- if (stopIfCastExpr) {
- // Note that this doesn't parse the subsequent cast-expression, it just
- // returns the parsed type to the callee.
+ // Note that this doesn't parse the subsequent cast-expression, it just
+ // returns the parsed type to the callee.
+ if (stopIfCastExpr)
return OwningExprResult(Actions);
+
+ // Reject the cast of super idiom in ObjC.
+ if (Tok.is(tok::identifier) && getLang().ObjC1 &&
+ Tok.getIdentifierInfo() == Ident_super &&
+ CurScope->isInObjcMethodScope() &&
+ GetLookAheadToken(1).isNot(tok::period)) {
+ Diag(Tok.getLocation(), diag::err_illegal_super_cast)
+ << SourceRange(OpenLoc, RParenLoc);
+ return ExprError();
}
// Parse the cast-expression that follows it next.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8528f8fe190c..146762b83ad5 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
return false;
}
+/// \brief Determine whether the current token starts a C++
+/// simple-type-specifier.
+bool Parser::isCXXSimpleTypeSpecifier() const {
+ switch (Tok.getKind()) {
+ case tok::annot_typename:
+ 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_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ // FIXME: C++0x decltype support.
+ // GNU typeof support.
+ case tok::kw_typeof:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
/// This should only be called when the current token is known to be part of
/// simple-type-specifier.
@@ -837,6 +867,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
+ // FIXME: C++0x decltype support.
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
@@ -1703,7 +1734,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
// Store the tokens of the parentheses. We will parse them after we determine
// the context that follows them.
- if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) {
+ if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) {
// We didn't find the ')' we expected.
MatchRHSPunctuation(tok::r_paren, LParenLoc);
return ExprError();
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 9154d8d59987..a382a9ae3c40 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/Designator.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Scope.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -33,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
}
}
+static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
+ Designation &Desig) {
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ P.Diag(Loc, diag::err_expected_equal_designator);
+}
+
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
/// checking to see if the token stream starts with a designator.
///
@@ -123,33 +137,97 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// [4][foo bar] -> obsolete GNU designation with objc message send.
//
SourceLocation StartLoc = ConsumeBracket();
+ OwningExprResult Idx(Actions);
+
+ // If Objective-C is enabled and this is a typename (class message
+ // send) or send to 'super', parse this as a message send
+ // expression. We handle C++ and C separately, since C++ requires
+ // much more complicated parsing.
+ if (getLang().ObjC1 && getLang().CPlusPlus) {
+ // Send to 'super'.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ ConsumeToken(), 0,
+ ExprArg(Actions));
+ }
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ // If the receiver was a type, we have a class message; parse
+ // the rest of it.
+ if (!IsExpr) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ TypeOrExpr,
+ ExprArg(Actions));
+ }
- // If Objective-C is enabled and this is a typename or other identifier
- // receiver, parse this as a message send expression.
- if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) {
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation NameLoc = ConsumeToken();
- return ParseAssignmentExprWithObjCMessageExprStart(
- StartLoc, NameLoc, Name, ExprArg(Actions));
+ // If the receiver was an expression, we still don't know
+ // whether we have a message send or an array designator; just
+ // adopt the expression for further analysis below.
+ // FIXME: potentially-potentially evaluated expression above?
+ Idx = OwningExprResult(Actions, TypeOrExpr);
+ } else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ SourceLocation IILoc = Tok.getLocation();
+ TypeTy *ReceiverType;
+ // Three cases. This is a message send to a type: [type foo]
+ // This is a message send to super: [super foo]
+ // This is a message sent to an expr: [super.bar foo]
+ switch (Action::ObjCMessageKind Kind
+ = Actions.getObjCMessageKind(CurScope, II, IILoc,
+ II == Ident_super,
+ NextToken().is(tok::period),
+ ReceiverType)) {
+ case Action::ObjCSuperMessage:
+ case Action::ObjCClassMessage:
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ if (Kind == Action::ObjCSuperMessage)
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ ConsumeToken(),
+ 0,
+ ExprArg(Actions));
+ ConsumeToken(); // the identifier
+ if (!ReceiverType) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ ReceiverType,
+ ExprArg(Actions));
+
+ case Action::ObjCInstanceMessage:
+ // Fall through; we'll just parse the expression and
+ // (possibly) treat this like an Objective-C message send
+ // later.
+ break;
+ }
}
+ // Parse the index expression, if we haven't already gotten one
+ // above (which can only happen in Objective-C++).
// Note that we parse this as an assignment expression, not a constant
// expression (allowing *=, =, etc) to handle the objc case. Sema needs
// to validate that the expression is a constant.
- OwningExprResult Idx(ParseAssignmentExpression());
- if (Idx.isInvalid()) {
- SkipUntil(tok::r_square);
- return move(Idx);
+ // FIXME: We also need to tell Sema that we're in a
+ // potentially-potentially evaluated context.
+ if (!Idx.get()) {
+ Idx = ParseAssignmentExpression();
+ if (Idx.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Idx);
+ }
}
// Given an expression, we could either have a designator (if the next
@@ -158,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
// an assignment-expression production.
if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
-
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
+ CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
0, move(Idx));
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 243be0ed45ae..7b1ecf6437dc 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -142,13 +142,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
- bool Err = false;
- if (Tok.is(tok::l_paren)) { // we have a category.
+ if (Tok.is(tok::l_paren) &&
+ !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
SourceLocation lparenLoc = ConsumeParen();
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId);
+ Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -157,12 +157,6 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
}
- else if (isKnownToBeTypeSpecifier(Tok)) {
- // Fall thru after diagnosing for better error recovery.
- Diag(Tok, diag::err_expected_minus_or_plus);
- ConsumeToken();
- Err = true;
- }
else if (!getLang().ObjC2) {
Diag(Tok, diag::err_expected_ident); // missing category name.
return DeclPtrTy();
@@ -173,34 +167,32 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
return DeclPtrTy();
}
rparenLoc = ConsumeParen();
- if (!Err) {
- // Next, we need to check for any protocol references.
- SourceLocation LAngleLoc, EndProtoLoc;
- llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
- llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
- if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
+ // Next, we need to check for any protocol references.
+ SourceLocation LAngleLoc, EndProtoLoc;
+ llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
+ if (Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
LAngleLoc, EndProtoLoc))
- return DeclPtrTy();
+ return DeclPtrTy();
- if (attrList) // categories don't support attributes.
- Diag(Tok, diag::err_objc_no_attributes_on_category);
-
- DeclPtrTy CategoryType =
- Actions.ActOnStartCategoryInterface(atLoc,
- nameId, nameLoc,
- categoryId, categoryLoc,
- ProtocolRefs.data(),
- ProtocolRefs.size(),
- ProtocolLocs.data(),
- EndProtoLoc);
- if (Tok.is(tok::l_brace))
+ if (attrList) // categories don't support attributes.
+ Diag(Tok, diag::err_objc_no_attributes_on_category);
+
+ DeclPtrTy CategoryType =
+ Actions.ActOnStartCategoryInterface(atLoc,
+ nameId, nameLoc,
+ categoryId, categoryLoc,
+ ProtocolRefs.data(),
+ ProtocolRefs.size(),
+ ProtocolLocs.data(),
+ EndProtoLoc);
+ if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private,
atLoc);
- ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
- return CategoryType;
- }
+ ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
+ return CategoryType;
}
// Parse a class interface.
IdentifierInfo *superClassId = 0;
@@ -211,7 +203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
// Code completion of superclass names.
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCSuperclass(CurScope, nameId);
+ Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -242,7 +234,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
- return Err ? DeclPtrTy() : ClsType;
+ return ClsType;
}
/// The Objective-C property callback. This should be defined where
@@ -787,6 +779,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::ObjCKeywordKind MethodImplKind) {
ParsingDeclRAIIObject PD(*this);
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
+ /*ReturnType=*/0, IDecl);
+ ConsumeToken();
+ }
+
// Parse the return type if present.
TypeTy *ReturnType = 0;
ObjCDeclSpec DSRet;
@@ -798,6 +796,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs.reset(ParseGNUAttributes());
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus,
+ ReturnType, IDecl);
+ ConsumeToken();
+ }
+
// Now parse the selector.
SourceLocation selLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
@@ -811,7 +815,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
return DeclPtrTy();
}
- llvm::SmallVector<Declarator, 8> CargNames;
+ llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
if (Tok.isNot(tok::colon)) {
// If attributes exist after the method, parse them.
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
@@ -822,7 +826,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- 0, CargNames, MethodAttrs.get(),
+ 0,
+ CParamInfo.data(), CParamInfo.size(),
+ MethodAttrs.get(),
MethodImplKind);
PD.complete(Result);
return Result;
@@ -885,7 +891,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// Parse the declarator.
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
- CargNames.push_back(ParmDecl);
+ IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+ DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+ CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
+ ParmDecl.getIdentifierLoc(),
+ Param,
+ 0));
+
}
// FIXME: Add support for optional parmameter list...
@@ -901,7 +913,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
DeclPtrTy Result
= Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0], CargNames,
+ &ArgInfos[0],
+ CParamInfo.data(), CParamInfo.size(),
MethodAttrs.get(),
MethodImplKind, isVariadic);
PD.complete(Result);
@@ -1053,7 +1066,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
= P.Actions.ActOnIvar(P.CurScope,
FD.D.getDeclSpec().getSourceRange().getBegin(),
IDecl, FD.D, FD.BitfieldSize, visibility);
- AllIvarDecls.push_back(Field);
+ if (Field)
+ AllIvarDecls.push_back(Field);
return Field;
}
} Callback(*this, interfaceDecl, visibility, AllIvarDecls);
@@ -1207,7 +1221,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId);
+ Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc);
ConsumeToken();
}
@@ -1404,8 +1418,12 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
break;
ConsumeToken(); // consume ','
}
- if (Tok.isNot(tok::semi))
+ if (Tok.isNot(tok::semi)) {
Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
+ SkipUntil(tok::semi);
+ }
+ else
+ ConsumeToken(); // consume ';'
return DeclPtrTy();
}
@@ -1422,7 +1440,8 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
return StmtError();
}
}
- ConsumeToken(); // consume ';'
+ // consume ';'
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw");
return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
}
@@ -1482,7 +1501,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
- OwningStmtResult CatchStmts(Actions);
+ StmtVector CatchStmts(Actions);
OwningStmtResult FinallyStmt(Actions);
ParseScope TryScope(this, Scope::DeclScope);
OwningStmtResult TryBody(ParseCompoundStatementBody());
@@ -1515,11 +1534,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
- // Inform the actions module about the parameter declarator, so it
+ // Inform the actions module about the 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);
+ FirstPart = Actions.ActOnObjCExceptionDecl(CurScope, ParmDecl);
} else
ConsumeToken(); // consume '...'
@@ -1537,9 +1554,14 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(Tok, diag::err_expected_lbrace);
if (CatchBody.isInvalid())
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
- CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
- RParenLoc, FirstPart, move(CatchBody),
- move(CatchStmts));
+
+ OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
+ RParenLoc,
+ FirstPart,
+ move(CatchBody));
+ if (!Catch.isInvalid())
+ CatchStmts.push_back(Catch.release());
+
} else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
<< "@catch clause";
@@ -1568,7 +1590,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(atLoc, diag::err_missing_catch_finally);
return StmtError();
}
- return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
+
+ return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody),
+ move_arg(CatchStmts),
move(FinallyStmt));
}
@@ -1604,7 +1628,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
SourceLocation BraceLoc = Tok.getLocation();
// Enter a scope for the method body.
- ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
+ ParseScope BodyScope(this,
+ Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
// Tell the actions module that we have entered a method definition with the
// specified Declarator for the method.
@@ -1683,39 +1708,191 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
}
+/// \brirg Parse the receiver of an Objective-C++ message send.
+///
+/// This routine parses the receiver of a message send in
+/// Objective-C++ either as a type or as an expression. Note that this
+/// routine must not be called to parse a send to 'super', since it
+/// has no way to return such a result.
+///
+/// \param IsExpr Whether the receiver was parsed as an expression.
+///
+/// \param TypeOrExpr If the receiver was parsed as an expression (\c
+/// IsExpr is true), the parsed expression. If the receiver was parsed
+/// as a type (\c IsExpr is false), the parsed type.
+///
+/// \returns True if an error occurred during parsing or semantic
+/// analysis, in which case the arguments do not have valid
+/// values. Otherwise, returns false for a successful parse.
+///
+/// objc-receiver: [C++]
+/// 'super' [not parsed here]
+/// expression
+/// simple-type-specifier
+/// typename-specifier
+
+bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
+ if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+ TryAnnotateTypeOrScopeToken();
+
+ if (!isCXXSimpleTypeSpecifier()) {
+ // objc-receiver:
+ // expression
+ OwningExprResult Receiver = ParseExpression();
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // objc-receiver:
+ // typename-specifier
+ // simple-type-specifier
+ // expression (that starts with one of the above)
+ DeclSpec DS;
+ ParseCXXSimpleTypeSpecifier(DS);
+
+ if (Tok.is(tok::l_paren)) {
+ // If we see an opening parentheses at this point, we are
+ // actually parsing an expression that starts with a
+ // function-style cast, e.g.,
+ //
+ // postfix-expression:
+ // simple-type-specifier ( expression-list [opt] )
+ // typename-specifier ( expression-list [opt] )
+ //
+ // Parse the remainder of this case, then the (optional)
+ // postfix-expression suffix, followed by the (optional)
+ // right-hand side of the binary expression. We have an
+ // instance method.
+ OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS);
+ if (!Receiver.isInvalid())
+ Receiver = ParsePostfixExpressionSuffix(move(Receiver));
+ if (!Receiver.isInvalid())
+ Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma);
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // We have a class message. Turn the simple-type-specifier or
+ // typename-specifier we parsed into a type and parse the
+ // remainder of the class message.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+ if (Type.isInvalid())
+ return true;
+
+ IsExpr = false;
+ TypeOrExpr = Type.get();
+ return false;
+}
+
/// objc-message-expr:
/// '[' objc-receiver objc-message-args ']'
///
-/// objc-receiver:
+/// objc-receiver: [C]
+/// 'super'
/// expression
/// class-name
/// type-name
+///
Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
assert(Tok.is(tok::l_square) && "'[' expected");
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
- // Parse receiver
- if (isTokObjCMessageIdentifierReceiver()) {
- IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
- if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
- SourceLocation NameLoc = ConsumeToken();
- return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
+ if (getLang().CPlusPlus) {
+ // We completely separate the C and C++ cases because C++ requires
+ // more complicated (read: slower) parsing.
+
+ // Handle send to super.
+ // FIXME: This doesn't benefit from the same typo-correction we
+ // get in Objective-C.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope())
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0,
ExprArg(Actions));
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
}
- }
+ if (IsExpr)
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+ OwningExprResult(Actions, TypeOrExpr));
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ TypeOrExpr, ExprArg(Actions));
+ } else if (Tok.is(tok::identifier)) {
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation NameLoc = Tok.getLocation();
+ TypeTy *ReceiverType;
+ switch (Actions.getObjCMessageKind(CurScope, Name, NameLoc,
+ Name == Ident_super,
+ NextToken().is(tok::period),
+ ReceiverType)) {
+ case Action::ObjCSuperMessage:
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0,
+ ExprArg(Actions));
+
+ case Action::ObjCClassMessage:
+ if (!ReceiverType) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ ConsumeToken(); // the type name
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ ReceiverType,
+ ExprArg(Actions));
+
+ case Action::ObjCInstanceMessage:
+ // Fall through to parse an expression.
+ break;
+ }
+ }
+
+ // Otherwise, an arbitrary expression can be the receiver of a send.
OwningExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
return move(Res);
}
- return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- 0, move(Res));
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+ move(Res));
}
-/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
-/// the rest of a message expression.
+/// \brief Parse the remainder of an Objective-C message following the
+/// '[' objc-receiver.
+///
+/// This routine handles sends to super, class messages (sent to a
+/// class name), and instance messages (sent to an object), and the
+/// target is represented by \p SuperLoc, \p ReceiverType, or \p
+/// ReceiverExpr, respectively. Only one of these parameters may have
+/// a valid value.
+///
+/// \param LBracLoc The location of the opening '['.
+///
+/// \param SuperLoc If this is a send to 'super', the location of the
+/// 'super' keyword that indicates a send to the superclass.
+///
+/// \param ReceiverType If this is a class message, the type of the
+/// class we are sending a message to.
+///
+/// \param ReceiverExpr If this is an instance message, the expression
+/// used to compute the receiver object.
///
/// objc-message-args:
/// objc-selector
@@ -1737,13 +1914,14 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
///
Parser::OwningExprResult
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
- SourceLocation NameLoc,
- IdentifierInfo *ReceiverName,
+ SourceLocation SuperLoc,
+ TypeTy *ReceiverType,
ExprArg ReceiverExpr) {
if (Tok.is(tok::code_completion)) {
- if (ReceiverName)
- Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
- 0, 0);
+ if (SuperLoc.isValid())
+ Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, 0, 0);
+ else if (ReceiverType)
+ Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, 0, 0);
else
Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(),
0, 0);
@@ -1789,8 +1967,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Code completion after each argument.
if (Tok.is(tok::code_completion)) {
- if (ReceiverName)
- Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc,
+ if (SuperLoc.isValid())
+ Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc,
+ KeyIdents.data(),
+ KeyIdents.size());
+ else if (ReceiverType)
+ Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType,
KeyIdents.data(),
KeyIdents.size());
else
@@ -1851,15 +2033,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents.push_back(selIdent);
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
- // We've just parsed a keyword message.
- if (ReceiverName)
- return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
- LBracLoc, NameLoc, SelectorLoc,
- RBracLoc,
- KeyExprs.take(), KeyExprs.size()));
- return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
- LBracLoc, SelectorLoc, RBracLoc,
- KeyExprs.take(), KeyExprs.size()));
+ if (SuperLoc.isValid())
+ return Actions.ActOnSuperMessage(CurScope, SuperLoc, Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
+ else if (ReceiverType)
+ return Actions.ActOnClassMessage(CurScope, ReceiverType, Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
+ return Actions.ActOnInstanceMessage(CurScope, move(ReceiverExpr), Sel,
+ LBracLoc, SelectorLoc, RBracLoc,
+ Action::MultiExprArg(Actions,
+ KeyExprs.take(),
+ KeyExprs.size()));
}
Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index b208c50c81bc..9b2227002f1b 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -643,6 +643,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
if (Tok.is(tok::kw_else)) {
ElseLoc = ConsumeToken();
+ ElseStmtLoc = Tok.getLocation();
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do
@@ -656,12 +657,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
ParseScope InnerScope(this, Scope::DeclScope,
C99orCXX && Tok.isNot(tok::l_brace));
- bool WithinElse = CurScope->isWithinElse();
- CurScope->setWithinElse(true);
- ElseStmtLoc = Tok.getLocation();
+ // Regardless of whether or not InnerScope actually pushed a scope, set the
+ // ElseScope flag for the innermost scope so we can diagnose use of the if
+ // condition variable in C++.
+ unsigned OldFlags = CurScope->getFlags();
+ CurScope->setFlags(OldFlags | Scope::ElseScope);
ElseStmt = ParseStatement();
- CurScope->setWithinElse(WithinElse);
-
+ CurScope->setFlags(OldFlags);
+
// Pop the 'else' scope if needed.
InnerScope.Exit();
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 516a9a620b62..a6c6d3f94535 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -14,6 +14,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Template.h"
using namespace clang;
/// isCXXDeclarationStatement - C++-specialized function that disambiguates
@@ -761,6 +762,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___vector:
return TPResult::True();
+ case tok::annot_template_id: {
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+ if (TemplateId->Kind != TNK_Type_template)
+ return TPResult::False();
+ CXXScopeSpec SS;
+ AnnotateTemplateIdTokenAsType(&SS);
+ assert(Tok.is(tok::annot_typename));
+ goto case_typename;
+ }
+
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
if (TryAnnotateTypeOrScopeToken())
@@ -801,6 +813,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_double:
case tok::kw_void:
case tok::annot_typename:
+ case_typename:
if (NextToken().is(tok::l_paren))
return TPResult::Ambiguous();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 489586c36f54..6dbb99e395f9 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -668,9 +668,15 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// If we have a colon, then we're probably parsing a C++
// ctor-initializer.
- if (Tok.is(tok::colon))
+ if (Tok.is(tok::colon)) {
ParseConstructorInitializer(Res);
- else
+
+ // Recover from error.
+ if (!Tok.is(tok::l_brace)) {
+ Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions));
+ return Res;
+ }
+ } else
Actions.ActOnDefaultCtorInitializers(Res);
return ParseFunctionStatementBody(Res);
@@ -1046,7 +1052,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext))
return true;
- if (!SS.isSet())
+ if (SS.isEmpty())
return false;
// Push the current token back into the token stream (or revert it if it is
diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 7b78070a27f8..5fe064990e96 100644
--- a/lib/Rewrite/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -533,6 +533,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
std::string Expansion = EscapeText(TmpPP.getSpelling(Tok));
unsigned LineLen = Expansion.size();
+ Token PrevPrevTok;
Token PrevTok = Tok;
// Okay, eat this token, getting the next one.
TmpPP.Lex(Tok);
@@ -553,13 +554,14 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) {
// If the tokens were already space separated, or if they must be to avoid
// them being implicitly pasted, add a space between them.
if (Tok.hasLeadingSpace() ||
- ConcatInfo.AvoidConcat(PrevTok, Tok))
+ ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok))
Expansion += ' ';
// Escape any special characters in the token text.
Expansion += EscapeText(TmpPP.getSpelling(Tok));
LineLen += Expansion.size();
+ PrevPrevTok = PrevTok;
PrevTok = Tok;
TmpPP.Lex(Tok);
}
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index bf8ba701a842..376678a5d74e 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -20,6 +20,12 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const {
+ // FIXME: eliminate the copy by writing out each chunk at a time
+ os << std::string(begin(), end());
+ return os;
+}
+
void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
// Nothing to remove, exit early.
if (Size == 0) return;
@@ -222,5 +228,3 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
ReplaceText(From->getLocStart(), Size, Str);
return false;
}
-
-
diff --git a/lib/Runtime/Makefile b/lib/Runtime/Makefile
index 9a3c34719cfb..580215acb62c 100644
--- a/lib/Runtime/Makefile
+++ b/lib/Runtime/Makefile
@@ -26,6 +26,7 @@ PROJ_resources_lib := $(PROJ_resources)/lib
# Expect compiler-rt to be in llvm/projects/compiler-rt
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
+ifndef CLANG_NO_RUNTIME
ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
# Select the compiler-rt configuration to use, and install directory.
@@ -97,3 +98,4 @@ install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
clean-local:: CleanRuntimeLibraries
endif
+endif
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index d1f00ca66d0a..6ded0a34601e 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -25,7 +25,6 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Casting.h"
-#include <queue>
using namespace clang;
@@ -75,7 +74,6 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
- std::queue<CFGBlock*> workq;
llvm::BitVector live(cfg->getNumBlockIDs());
unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(),
live);
@@ -149,7 +147,8 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- if (B.succ_begin()[0] != &cfg->getExit()) {
+ if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit())
+ == B.succ_end()) {
HasAbnormalEdge = true;
continue;
}
@@ -190,7 +189,7 @@ struct CheckFallThroughDiagnostics {
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
- static CheckFallThroughDiagnostics MakeForFunction() {
+ static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
diag::warn_falloff_noreturn_function;
@@ -200,8 +199,19 @@ struct CheckFallThroughDiagnostics {
diag::warn_falloff_noreturn_function;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::warn_falloff_nonvoid_function;
- D.diag_NeverFallThroughOrReturn =
- diag::warn_suggest_noreturn_function;
+
+ // Don't suggest that virtual functions be marked "noreturn", since they
+ // might be overridden by non-noreturn functions.
+ bool isVirtualMethod = false;
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func))
+ isVirtualMethod = Method->isVirtual();
+
+ if (!isVirtualMethod)
+ D.diag_NeverFallThroughOrReturn =
+ diag::warn_suggest_noreturn_function;
+ else
+ D.diag_NeverFallThroughOrReturn = 0;
+
D.funMode = true;
return D;
}
@@ -297,7 +307,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn)
+ if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn)
S.Diag(Compound->getLBracLoc(),
CD.diag_NeverFallThroughOrReturn);
break;
@@ -325,8 +335,7 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
void clang::sema::
AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
- const Decl *D, QualType BlockTy,
- const bool analyzeStaticInline) {
+ const Decl *D, QualType BlockTy) {
assert(BlockTy.isNull() || isa<BlockDecl>(D));
@@ -336,12 +345,14 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// don't bother trying.
// (2) The code already has problems; running the analysis just takes more
// time.
- if (S.getDiagnostics().hasErrorOccurred())
+ Diagnostic &Diags = S.getDiagnostics();
+
+ if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
return;
// Do not do any analysis for declarations in system headers if we are
// going to just ignore them.
- if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ if (Diags.getSuppressSystemWarnings() &&
S.SourceMgr.isInSystemHeader(D->getLocation()))
return;
@@ -350,17 +361,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
-
- // Only analyze 'static inline' functions when explicitly asked.
- if (!analyzeStaticInline && FD->isInlineSpecified() &&
- FD->getStorageClass() == FunctionDecl::Static) {
- FD = FD->getCanonicalDecl();
- VisitFlag &visitFlag = VisitedFD[FD];
- if (visitFlag == Pending)
- visitFlag = Visited;
- else
- return;
- }
}
const Stmt *Body = D->getBody();
@@ -369,61 +369,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
AnalysisContext AC(D, false);
- bool performedCheck = false;
// Warning: check missing 'return'
if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
- : CheckFallThroughDiagnostics::MakeForFunction());
+ : CheckFallThroughDiagnostics::MakeForFunction(D));
CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
- performedCheck = true;
}
// Warning: check for unreachable code
- if (P.enableCheckUnreachable) {
+ if (P.enableCheckUnreachable)
CheckUnreachable(S, AC);
- performedCheck = true;
- }
-
- // If this block or function calls a 'static inline' function,
- // we should analyze those functions as well.
- if (performedCheck) {
- // The CFG should already be constructed, so this should not
- // incur any extra cost. We might not have a CFG, however, for
- // invalid code.
- if (const CFG *cfg = AC.getCFG()) {
- // All CallExprs are block-level expressions in the CFG. This means
- // that walking the basic blocks in the CFG is more efficient
- // than walking the entire AST to find all calls.
- for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) {
- const CFGBlock *B = *I;
- for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI)
- if (const CallExpr *CE = dyn_cast<CallExpr>(*BI))
- if (const DeclRefExpr *DR =
- dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts()))
- if (const FunctionDecl *calleeD =
- dyn_cast<FunctionDecl>(DR->getDecl())) {
- calleeD = calleeD->getCanonicalDecl();
- if (calleeD->isInlineSpecified() &&
- calleeD->getStorageClass() == FunctionDecl::Static) {
- // Have we analyzed this static inline function before?
- VisitFlag &visitFlag = VisitedFD[calleeD];
- if (visitFlag == NotVisited) {
- // Mark the callee visited prior to analyzing it
- // so we terminate in case of recursion.
- if (calleeD->getBody()) {
- visitFlag = Visited;
- IssueWarnings(DefaultPolicy, calleeD, QualType(), true);
- }
- else {
- // Delay warnings until we encounter the definition.
- visitFlag = Pending;
- }
- }
- }
- }
- }
- }
- }
}
diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h
index b5db8af198f4..dea19ba28ccf 100644
--- a/lib/Sema/AnalysisBasedWarnings.h
+++ b/lib/Sema/AnalysisBasedWarnings.h
@@ -47,9 +47,7 @@ public:
Policy getDefaultPolicy() { return DefaultPolicy; }
- void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(),
- const bool analyzeStaticInline = false);
-
+ void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType());
};
}} // end namespace clang::sema
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 5483a292e955..0ef9a15faaf9 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -86,7 +86,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
break;
case CK_Colon:
- this->Text = ": ";
+ this->Text = ":";
break;
case CK_SemiColon:
@@ -425,7 +425,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << "COMPLETION: ";
switch (Results[I].Kind) {
case Result::RK_Declaration:
- OS << Results[I].Declaration->getNameAsString() ;
+ OS << Results[I].Declaration;
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 1c761b95039c..069429490385 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -155,8 +155,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
BuildScopeInformation(TryPart, Scopes.size()-1);
// Jump from the catch to the finally or try is not valid.
- for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC;
- AC = AC->getNextCatchStmt()) {
+ for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_catch,
AC->getAtCatchLoc()));
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index f310c253ab20..096129958717 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -124,7 +124,6 @@ public:
};
typedef UnresolvedSetImpl::iterator iterator;
- typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
Sema::LookupNameKind LookupKind,
@@ -136,7 +135,6 @@ public:
Name(Name),
NameLoc(NameLoc),
LookupKind(LookupKind),
- IsAcceptableFn(0),
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
@@ -156,7 +154,6 @@ public:
Name(Other.Name),
NameLoc(Other.NameLoc),
LookupKind(Other.LookupKind),
- IsAcceptableFn(Other.IsAcceptableFn),
IDNS(Other.IDNS),
Redecl(Other.Redecl),
HideTags(Other.HideTags),
@@ -242,8 +239,7 @@ public:
/// \brief Tests whether the given declaration is acceptable.
bool isAcceptableDecl(NamedDecl *D) const {
- assert(IsAcceptableFn);
- return IsAcceptableFn(D, IDNS);
+ return D->isInIdentifierNamespace(IDNS);
}
/// \brief Returns the identifier namespace mask for this lookup.
@@ -282,6 +278,18 @@ public:
NamingClass = Record;
}
+ /// \brief Returns the base object type associated with this lookup;
+ /// important for [class.protected]. Most lookups do not have an
+ /// associated base object.
+ QualType getBaseObjectType() const {
+ return BaseObjectType;
+ }
+
+ /// \brief Sets the base object type for this lookup.
+ void setBaseObjectType(QualType T) {
+ BaseObjectType = T;
+ }
+
/// \brief Add a declaration to these results with its natural access.
/// Does not test the acceptance criteria.
void addDecl(NamedDecl *D) {
@@ -331,6 +339,11 @@ public:
} else {
ResultKind = Found;
resolveKind();
+
+ if (Paths && (ResultKind != Ambiguous)) {
+ deletePaths(Paths);
+ Paths = 0;
+ }
}
}
@@ -550,6 +563,7 @@ private:
UnresolvedSet<8> Decls;
CXXBasePaths *Paths;
CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
// Parameters.
Sema &SemaRef;
@@ -557,7 +571,6 @@ private:
SourceLocation NameLoc;
SourceRange NameContextRange;
Sema::LookupNameKind LookupKind;
- ResultFilter IsAcceptableFn; // set by configure()
unsigned IDNS; // set by configure()
bool Redecl;
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 7cd39895f6fd..bb0bd9e1cb5e 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -24,6 +24,26 @@
using namespace clang;
+static void DumpRecordLayouts(ASTContext &C) {
+ for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end();
+ I != E; ++I) {
+ const RecordType *RT = dyn_cast<RecordType>(*I);
+ if (!RT)
+ continue;
+
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD || RD->isImplicit() || RD->isDependentType() ||
+ RD->isInvalidDecl() || !RD->getDefinition())
+ continue;
+
+ // FIXME: Do we really need to hard code this?
+ if (RD->getQualifiedNameAsString() == "__va_list_tag")
+ continue;
+
+ C.DumpRecordLayout(RD, llvm::errs());
+ }
+}
+
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//
@@ -44,8 +64,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer);
Parser P(PP, S);
- if (PP.EnterMainSourceFile())
- return;
+ PP.EnterMainSourceFile();
// Initialize the parser.
P.Initialize();
@@ -82,6 +101,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
E = S.WeakTopLevelDecls().end(); I != E; ++I)
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
+ // Dump record layouts, if requested.
+ if (PP.getLangOptions().DumpRecordLayouts)
+ DumpRecordLayouts(Ctx);
+
Consumer->HandleTranslationUnit(Ctx);
if (ExternalSemaSource *ESS =
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index ccfbe1e00a7e..755af84ca960 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -158,7 +158,8 @@ Sema::~Sema() {
/// If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
- CastExpr::CastKind Kind, bool isLvalue) {
+ CastExpr::CastKind Kind,
+ bool isLvalue, CXXBaseSpecifierArray BasePath) {
QualType ExprTy = Context.getCanonicalType(Expr->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
@@ -177,14 +178,14 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
CheckImplicitConversion(Expr, Ty);
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
- if (ImpCast->getCastKind() == Kind) {
+ if (ImpCast->getCastKind() == Kind && BasePath.empty()) {
ImpCast->setType(Ty);
ImpCast->setLvalueCast(isLvalue);
return;
}
}
- Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue);
+ Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, BasePath, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
@@ -197,14 +198,7 @@ void Sema::DeleteStmt(StmtTy *S) {
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// 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());
-
+void Sema::ActOnEndOfTranslationUnit() {
while (1) {
// C++: Perform implicit template instantiations.
//
@@ -225,6 +219,12 @@ void Sema::ActOnEndOfTranslationUnit() {
break;
}
+ // Remove functions that turned out to be used.
+ UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(),
+ UnusedStaticFuncs.end(),
+ std::mem_fun(&FunctionDecl::isUsed)),
+ UnusedStaticFuncs.end());
+
// Check for #pragma weak identifiers that were never declared
// FIXME: This will cause diagnostics to be emitted in a non-determinstic
// order! Iterating over a densemap like this is bad.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0766b1e83df5..f146c8578721 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -25,6 +25,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/FullExpr.h"
#include "clang/Parse/Action.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -108,33 +109,33 @@ namespace clang {
class TargetAttributesSema;
class ADLResult;
-/// \brief Retains information about a function, method, or block that is
+/// \brief Retains information about a function, method, or block that is
/// currently being parsed.
struct FunctionScopeInfo {
/// \brief Whether this scope information structure defined information for
/// a block.
bool IsBlockInfo;
-
- /// \brief Set true when a function, method contains a VLA or ObjC try block,
+
+ /// \brief Set true when a function, method contains a VLA or ObjC try block,
/// which introduce scopes that need to be checked for goto conditions. If a
/// function does not contain this, then it need not have the jump checker run on it.
bool NeedsScopeChecking;
-
+
/// \brief The number of errors that had occurred before starting this
/// function or block.
unsigned NumErrorsAtStartOfFunction;
-
+
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
/// it (which acts like the label decl in some ways). Forward referenced
/// labels have a LabelStmt created for them with a null location & SubStmt.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
-
+
/// SwitchStack - This is the current set of active switch statements in the
/// block.
- llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
-
- FunctionScopeInfo(unsigned NumErrors)
- : IsBlockInfo(false), NeedsScopeChecking(false),
+ llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+
+ FunctionScopeInfo(unsigned NumErrors)
+ : IsBlockInfo(false), NeedsScopeChecking(false),
NumErrorsAtStartOfFunction(NumErrors) { }
virtual ~FunctionScopeInfo();
@@ -142,11 +143,11 @@ struct FunctionScopeInfo {
/// \brief Clear out the information in this function scope, making it
/// suitable for reuse.
void Clear(unsigned NumErrors);
-
- static bool classof(const FunctionScopeInfo *FSI) { return true; }
+
+ static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
-
-
+
+
/// \brief Retains information about a block that is currently being parsed.
struct BlockScopeInfo : FunctionScopeInfo {
llvm::SmallVector<ParmVarDecl*, 8> Params;
@@ -164,11 +165,11 @@ struct BlockScopeInfo : FunctionScopeInfo {
/// return types, if any, in the block body.
QualType ReturnType;
- BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
- : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
- hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
+ BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
+ : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
+ hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
{
- IsBlockInfo = true;
+ IsBlockInfo = true;
}
virtual ~BlockScopeInfo();
@@ -233,6 +234,30 @@ public:
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
+ /// A RAII object to temporarily push a declaration context.
+ class ContextRAII {
+ private:
+ Sema &S;
+ DeclContext *SavedContext;
+
+ public:
+ ContextRAII(Sema &S, DeclContext *ContextToPush)
+ : S(S), SavedContext(S.CurContext) {
+ assert(ContextToPush && "pushing null context");
+ S.CurContext = ContextToPush;
+ }
+
+ void pop() {
+ if (!SavedContext) return;
+ S.CurContext = SavedContext;
+ SavedContext = 0;
+ }
+
+ ~ContextRAII() {
+ pop();
+ }
+ };
+
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
@@ -240,14 +265,14 @@ public:
/// \brief Stack containing information about each of the nested function,
/// block, and method scopes that are currently active.
llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes;
-
+
/// \brief Cached function scope object used for the top function scope
/// and when there is no function scope (in error cases).
///
- /// This should never be accessed directly; rather, it's address will be
+ /// This should never be accessed directly; rather, it's address will be
/// pushed into \c FunctionScopes when we want to re-use it.
FunctionScopeInfo TopFunctionScope;
-
+
/// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
@@ -312,26 +337,17 @@ public:
bool isMemberAccess() const { return IsMember; }
- AccessedEntity(ASTContext &Context,
- MemberNonce _,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- NamedDecl *Target)
- : Access(Access), IsMember(true),
- Target(Target), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
- }
-
- AccessedEntity(ASTContext &Context,
+ AccessedEntity(ASTContext &Context,
MemberNonce _,
CXXRecordDecl *NamingClass,
- DeclAccessPair FoundDecl)
- : Access(FoundDecl.getAccess()), IsMember(true),
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
+ : Access(FoundDecl.getAccess()), IsMember(true),
Target(FoundDecl.getDecl()), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
+ BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(ASTContext &Context,
+ AccessedEntity(ASTContext &Context,
BaseNonce _,
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
@@ -353,6 +369,10 @@ public:
CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+ /// Retrieves the base object type, important when accessing
+ /// an instance member.
+ QualType getBaseObjectType() const { return BaseObjectType; }
+
/// Sets a diagnostic to be performed. The diagnostic is given
/// four (additional) arguments:
/// %0 - 0 if the entity was private, 1 if protected
@@ -377,7 +397,8 @@ public:
unsigned Access : 2;
bool IsMember;
NamedDecl *Target;
- CXXRecordDecl *NamingClass;
+ CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
PartialDiagnostic Diag;
};
@@ -484,14 +505,14 @@ public:
/// \brief The C++ "std::bad_alloc" class, which is defined by the C++
/// standard library.
CXXRecordDecl *StdBadAlloc;
-
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
/// \brief The set of declarations that have been referenced within
/// a potentially evaluated expression.
- typedef std::vector<std::pair<SourceLocation, Decl *> >
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
PotentiallyReferencedDecls;
/// \brief A set of diagnostics that may be emitted.
@@ -522,8 +543,8 @@ public:
PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
- unsigned NumTemporaries)
- : Context(Context), NumTemporaries(NumTemporaries),
+ unsigned NumTemporaries)
+ : Context(Context), NumTemporaries(NumTemporaries),
PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
@@ -618,11 +639,11 @@ public:
/// \brief Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
- /// \brief Build a partial diagnostic.
+ /// \brief Build a partial diagnostic.
PartialDiagnostic PDiag(unsigned DiagID = 0) {
return PartialDiagnostic(DiagID, Context.getDiagAllocator());
}
-
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -646,13 +667,13 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
void PopFunctionOrBlockScope();
-
+
/// getLabelMap() - Return the current label map. If we're in a block, we
/// return it.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
if (FunctionScopes.empty())
return TopFunctionScope.LabelMap;
-
+
return FunctionScopes.back()->LabelMap;
}
@@ -661,24 +682,24 @@ public:
llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
if (FunctionScopes.empty())
return TopFunctionScope.SwitchStack;
-
+
return FunctionScopes.back()->SwitchStack;
}
- /// \brief Determine whether the current function or block needs scope
+ /// \brief Determine whether the current function or block needs scope
/// checking.
bool &FunctionNeedsScopeChecking() {
if (FunctionScopes.empty())
return TopFunctionScope.NeedsScopeChecking;
-
+
return FunctionScopes.back()->NeedsScopeChecking;
}
-
+
bool hasAnyErrorsInThisFunction() const;
-
+
/// \brief Retrieve the current block, if any.
BlockScopeInfo *getCurBlock();
-
+
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
@@ -708,7 +729,8 @@ public:
QualType GetTypeForDeclarator(Declarator &D, Scope *S,
TypeSourceInfo **TInfo = 0,
TagDecl **OwnedDecl = 0);
- TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T);
+ TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
+ TypeSourceInfo *ReturnTypeInfo);
/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo.
QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo);
DeclarationName GetNameForDeclarator(Declarator &D);
@@ -745,7 +767,7 @@ public:
const PartialDiagnostic &PD);
bool RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID);
-
+
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
@@ -762,16 +784,16 @@ public:
DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName = false,
TypeTy *ObjectType = 0);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
- virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
- const CXXScopeSpec *SS,
+ CXXScopeSpec *SS,
TypeTy *&SuggestedType);
-
+
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
@@ -809,7 +831,12 @@ public:
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
- virtual void ActOnObjCCatchParam(DeclPtrTy D);
+ ParmVarDecl *CheckParameter(DeclContext *DC,
+ TypeSourceInfo *TSInfo, QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ VarDecl::StorageClass StorageClass,
+ VarDecl::StorageClass StorageClassAsWritten);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
ExprArg defarg);
@@ -847,11 +874,21 @@ public:
/// ParmVarDecl pointers.
template<typename InputIterator>
void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) {
+ if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) ==
+ Diagnostic::Ignored)
+ return;
+
+ // Don't diagnose unused-parameter errors in template instantiations; we
+ // will already have done so in the template itself.
+ if (!ActiveTemplateInstantiations.empty())
+ return;
+
for (; Param != ParamEnd; ++Param) {
if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
- !(*Param)->template hasAttr<UnusedAttr>())
+ !(*Param)->template hasAttr<UnusedAttr>()) {
Diag((*Param)->getLocation(), diag::warn_unused_parameter)
<< (*Param)->getDeclName();
+ }
}
}
@@ -877,7 +914,7 @@ public:
const IdentifierInfo &Name);
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -911,12 +948,14 @@ public:
Declarator *D = 0);
enum CXXSpecialMember {
- CXXDefaultConstructor = 0,
+ CXXInvalid = -1,
+ CXXConstructor = 0,
CXXCopyConstructor = 1,
CXXCopyAssignment = 2,
CXXDestructor = 3
};
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+ CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
DeclPtrTy IntfDecl,
@@ -1034,7 +1073,7 @@ public:
AA_Sending,
AA_Casting
};
-
+
/// C++ Overloading.
enum OverloadKind {
/// This is a legitimate overload: the existing declarations are
@@ -1058,9 +1097,7 @@ public:
TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
- bool ForceRValue,
- bool InOverloadResolution,
- bool UserCast = false);
+ bool InOverloadResolution);
bool IsStandardConversion(Expr *From, QualType ToType,
bool InOverloadResolution,
StandardConversionSequence& SCS);
@@ -1072,24 +1109,27 @@ public:
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
+ bool FunctionArgTypesAreEqual (FunctionProtoType* OldType,
+ FunctionProtoType* NewType);
+
bool CheckPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray& BasePath,
bool IgnoreBaseAccess);
bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType,
bool InOverloadResolution,
QualType &ConvertedType);
bool CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
bool IgnoreBaseAccess);
bool IsQualificationConversion(QualType FromType, QualType ToType);
OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
- bool AllowConversionFunctions,
- bool AllowExplicit, bool ForceRValue,
- bool UserCast = false);
+ bool AllowExplicit);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
-
+
ImplicitConversionSequence::CompareKind
CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
@@ -1107,18 +1147,13 @@ public:
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
- ImplicitConversionSequence
- TryCopyInitialization(Expr* From, QualType ToType,
- bool SuppressUserConversions, bool ForceRValue,
- bool InOverloadResolution);
-
OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
OwningExprResult Init);
ImplicitConversionSequence
TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
CXXRecordDecl *ActingContext);
- bool PerformObjectArgumentInitialization(Expr *&From,
+ bool PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
CXXMethodDecl *Method);
@@ -1126,7 +1161,7 @@ public:
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
bool PerformContextuallyConvertToBool(Expr *&From);
- bool PerformObjectMemberConversion(Expr *&From,
+ bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
NamedDecl *Member);
@@ -1146,7 +1181,6 @@ public:
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool ForceRValue = false,
bool PartialOverloading = false);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
Expr **Args, unsigned NumArgs,
@@ -1156,15 +1190,13 @@ public:
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversion = false,
- bool ForceRValue = false);
+ bool SuppressUserConversion = false);
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -1172,15 +1204,13 @@ public:
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false,
- bool ForceRValue = false);
+ bool SuppressUserConversions = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -1197,11 +1227,6 @@ public:
const FunctionProtoType *Proto,
QualType ObjectTy, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
- void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
- SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange = SourceRange());
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
@@ -1254,18 +1279,18 @@ public:
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
Expr *FixOverloadedFunctionReference(Expr *E,
- NamedDecl *FoundDecl,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
- OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
- NamedDecl *FoundDecl,
+ OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
-
- OwningExprResult BuildOverloadedCallExpr(Expr *Fn,
+
+ OwningExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -1305,7 +1330,7 @@ public:
/// that best represents the call.
bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
CallExpr *CE, FunctionDecl *FD);
-
+
/// Helpers for dealing with blocks and functions.
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
@@ -1374,9 +1399,7 @@ public:
/// C99 6.2.2p4-5 and C++ [basic.link]p6.
LookupRedeclarationWithLinkage,
/// Look up the name of an Objective-C protocol.
- LookupObjCProtocolName,
- /// Look up the name of an Objective-C implementation
- LookupObjCImplementationName
+ LookupObjCProtocolName
};
/// \brief Specifies whether (or how) name lookup is being performed for a
@@ -1400,6 +1423,7 @@ public:
/// It is preferable to use the elaborated form and explicitly handle
/// ambiguity and overloaded.
NamedDecl *LookupSingleName(Scope *S, DeclarationName Name,
+ SourceLocation Loc,
LookupNameKind NameKind,
RedeclarationKind Redecl
= NotForRedeclaration);
@@ -1407,15 +1431,15 @@ public:
bool AllowBuiltinCreation = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
bool InUnqualifiedLookup = false);
- bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+ bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
- ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II);
+ ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc);
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
-
+
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
Expr **Args, unsigned NumArgs,
ADLResult &Functions);
@@ -1425,10 +1449,34 @@ public:
void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer);
- bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
- DeclContext *MemberContext = 0,
- bool EnteringContext = false,
- const ObjCObjectPointerType *OPT = 0);
+ /// \brief The context in which typo-correction occurs.
+ ///
+ /// The typo-correction context affects which keywords (if any) are
+ /// considered when trying to correct for typos.
+ enum CorrectTypoContext {
+ /// \brief An unknown context, where any keyword might be valid.
+ CTC_Unknown,
+ /// \brief A context where no keywords are used (e.g. we expect an actual
+ /// name).
+ CTC_NoKeywords,
+ /// \brief A context where we're correcting a type name.
+ CTC_Type,
+ /// \brief An expression context.
+ CTC_Expression,
+ /// \brief A type cast, or anything else that can be followed by a '<'.
+ CTC_CXXCasts,
+ /// \brief A member lookup context.
+ CTC_MemberLookup,
+ /// \brief The receiver of an Objective-C message send within an
+ /// Objective-C method where 'super' is a valid keyword.
+ CTC_ObjCMessageReceiver
+ };
+
+ DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext = 0,
+ bool EnteringContext = false,
+ CorrectTypoContext CTC = CTC_Unknown,
+ const ObjCObjectPointerType *OPT = 0);
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -1438,7 +1486,8 @@ public:
//@}
ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
- SourceLocation RecoverLoc = SourceLocation());
+ SourceLocation IdLoc,
+ bool TypoCorrection = false);
NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
@@ -1482,7 +1531,7 @@ public:
void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
-
+
/// DiagnoseUnimplementedProperties - This routine warns on those properties
/// which must be implemented by this implementation.
void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
@@ -1494,13 +1543,19 @@ public:
void CollectImmediateProperties(ObjCContainerDecl *CDecl,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+ /// ProtocolConformsToSuperClass - Returns true if class has a super class
+ /// and it, or its nested super class conforms to the protocol.
+ bool ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
+ const ObjCProtocolDecl *PDecl);
+ /// ProtocolConformsToProtocol - Returns true if 2nd Protocol (PDecl) is
+ /// qualified by the 1st.
+ bool ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol,
+ const ObjCProtocolDecl *PDecl);
+
/// LookupPropertyDecl - Looks up a property in the current class and all
/// its protocols.
- ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
+ ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl,
IdentifierInfo *II);
-
- ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII);
/// Called by ActOnProperty to handle @property declarations in
//// class extensions.
@@ -1572,6 +1627,11 @@ public:
/// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+
+ /// CollectIvarsToConstructOrDestruct - Collect those ivars which require
+ /// initialization.
+ void CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
public:
@@ -1601,7 +1661,7 @@ public:
FullExprArg CondVal, DeclPtrTy CondVar,
StmtArg ThenVal,
SourceLocation ElseLoc, StmtArg ElseVal);
- virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond,
DeclPtrTy CondVar);
virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch,
StmtArg Body);
@@ -1619,7 +1679,7 @@ public:
SourceLocation LParenLoc,
StmtArg First, FullExprArg Second,
DeclPtrTy SecondVar,
- FullExprArg Third,
+ FullExprArg Third,
SourceLocation RParenLoc,
StmtArg Body);
virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
@@ -1656,18 +1716,27 @@ public:
SourceLocation RParenLoc,
bool MSAsm = false);
+
+ VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ bool Invalid = false);
+
+ virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D);
+
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
- DeclPtrTy Parm, StmtArg Body,
- StmtArg CatchList);
+ DeclPtrTy Parm, StmtArg Body);
virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
StmtArg Body);
virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
StmtArg Try,
- StmtArg Catch, StmtArg Finally);
+ MultiStmtArg Catch,
+ StmtArg Finally);
+ virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw);
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
ExprArg Throw,
Scope *CurScope);
@@ -1717,17 +1786,17 @@ public:
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD);
-
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
virtual OwningExprResult ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
bool HasTrailingLParen,
bool IsAddressOfOperand);
- bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R);
+ bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R);
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
@@ -1739,7 +1808,7 @@ public:
SourceLocation NameLoc,
bool isAddressOfOperand,
const TemplateArgumentListInfo *TemplateArgs);
-
+
OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty,
SourceLocation Loc,
const CXXScopeSpec *SS = 0);
@@ -1761,7 +1830,7 @@ public:
const LookupResult &R,
bool HasTrailingLParen);
- OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+ OwningExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc);
OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
@@ -1831,7 +1900,7 @@ public:
QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name,
SourceLocation NameLoc,
@@ -1843,11 +1912,12 @@ public:
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck = false);
OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base,
bool &IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
DeclPtrTy ObjCImpDecl);
bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
@@ -1867,11 +1937,11 @@ public:
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen);
-
+
virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
@@ -1954,6 +2024,11 @@ public:
SourceLocation RPLoc); // "({..})"
/// __builtin_offsetof(type, a.b[123][456].c)
+ OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ TypeSourceInfo *TInfo,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc);
virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
@@ -2011,7 +2086,7 @@ public:
virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList);
@@ -2022,7 +2097,7 @@ public:
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident);
@@ -2043,7 +2118,7 @@ public:
NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
@@ -2055,7 +2130,7 @@ public:
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -2078,28 +2153,21 @@ public:
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
- OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
- QualType DeclInitType,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool RequiresZeroInit = false,
- bool BaseInitialization = false);
+ OwningExprResult
+ BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, MultiExprArg Exprs,
+ bool RequiresZeroInit = false,
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
- OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc,
- QualType DeclInitType,
- CXXConstructorDecl *Constructor,
- bool Elidable,
- MultiExprArg Exprs,
- bool RequiresZeroInit = false,
- bool BaseInitialization = false);
-
- OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc,
- QualType Ty,
- CastExpr::CastKind Kind,
- CXXMethodDecl *Method,
- ExprArg Arg);
+ OwningExprResult
+ BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ CXXConstructorDecl *Constructor, bool Elidable,
+ MultiExprArg Exprs, bool RequiresZeroInit = false,
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
@@ -2127,36 +2195,23 @@ public:
CXXConstructorDecl *Constructor,
unsigned TypeQuals);
- /// DefineImplicitOverloadedAssign - Checks for feasibility of
- /// defining implicit this overloaded assignment operator.
- void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
- CXXMethodDecl *MethodDecl);
-
- /// getAssignOperatorMethod - Returns the default copy assignmment operator
- /// for the class.
- CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation,
- ParmVarDecl *Decl,
- CXXRecordDecl *ClassDecl);
+ /// \brief Defined and implicitly-declared copy assignment operator.
+ void DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *MethodDecl);
/// MaybeBindToTemporary - If the passed in expression has a record type with
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
/// it simply returns the passed in expression.
OwningExprResult MaybeBindToTemporary(Expr *E);
- CXXConstructorDecl *
- TryInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
- SourceLocation Loc,
- InitializationKind Kind);
-
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
- SourceLocation Loc,
+ SourceLocation Loc,
ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
-
+
virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
TypeTy *ObjectType,
bool EnteringContext);
@@ -2177,6 +2232,15 @@ public:
SourceRange AngleBrackets,
SourceRange Parens);
+ OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
+ SourceLocation RParenLoc);
+ OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc);
+
/// ActOnCXXTypeid - Parse typeid( something ).
virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
SourceLocation LParenLoc, bool isType,
@@ -2247,7 +2311,7 @@ public:
QualType Argument,
bool addMallocAttr = false);
- bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
+ bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name, FunctionDecl* &Operator);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
@@ -2258,7 +2322,7 @@ public:
virtual DeclResult ActOnCXXConditionDeclaration(Scope *S,
Declarator &D);
OwningExprResult CheckConditionVariable(VarDecl *ConditionVar);
-
+
/// ActOnUnaryTypeTrait - Parsed one of the unary type trait support
/// pseudo-functions.
virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
@@ -2276,7 +2340,7 @@ public:
OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc,
ExprArg MemExpr);
-
+
OwningExprResult BuildPseudoDestructorExpr(ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -2286,27 +2350,28 @@ public:
SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType,
bool HasTrailingLParen);
-
+
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
-
+
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.
Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr);
OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr);
FullExpr CreateFullExpr(Expr *SubExpr);
-
+
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr);
- bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+ // Marks SS invalid if it represents an incomplete type.
+ bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC);
DeclContext *computeDeclContext(QualType T);
DeclContext *computeDeclContext(const CXXScopeSpec &SS,
@@ -2323,13 +2388,13 @@ public:
bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
- virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+ virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectType);
-
+
CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -2339,7 +2404,7 @@ public:
bool ErrorRecoveryLookup);
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -2347,11 +2412,11 @@ public:
bool EnteringContext);
virtual bool IsInvalidUnlessNestedName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo &II,
TypeTy *ObjectType,
bool EnteringContext);
-
+
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
/// nested-name-specifier that involves a template-id, e.g.,
/// "foo::bar<int, float>::", and now we need to build a scope
@@ -2374,7 +2439,7 @@ public:
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
- virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS);
+ virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS);
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
@@ -2400,7 +2465,7 @@ public:
unsigned NumStrings);
Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
- QualType EncodedType,
+ TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc);
CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp,
NamedDecl *FoundDecl,
@@ -2432,8 +2497,7 @@ public:
virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc);
virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S,
DeclPtrTy LinkageSpec,
@@ -2455,7 +2519,7 @@ public:
virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -2479,6 +2543,9 @@ public:
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers, bool AnyErrors);
+
+ void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation);
+
/// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
/// mark all the non-trivial destructors of its members and bases as
@@ -2494,28 +2561,28 @@ public:
ClassesWithUnmarkedVirtualMembers;
/// MaybeMarkVirtualMembersReferenced - If the passed in method is the
- /// key function of the record decl, will mark virtual member functions as
+ /// key function of the record decl, will mark virtual member functions as
/// referenced.
void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD);
-
+
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD);
- /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
+ /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
/// that might need to have their virtual members marked as referenced.
/// Returns false if no work was done.
bool ProcessPendingClassesWithUnmarkedVirtualMembers();
-
- void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
+
+ void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl);
virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
MemInitTy **MemInits, unsigned NumMemInits,
bool AnyErrors);
- void CheckCompletedCXXClass(CXXRecordDecl *Record);
+ void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record);
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
@@ -2537,6 +2604,8 @@ public:
ExprArg AssertExpr,
ExprArg AssertMessageExpr);
+ FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc,
+ TypeSourceInfo *TSInfo);
DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
@@ -2551,7 +2620,7 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
-
+
//===--------------------------------------------------------------------===//
// C++ Derived Classes
//
@@ -2562,14 +2631,14 @@ public:
bool Virtual, AccessSpecifier Access,
QualType BaseType,
SourceLocation BaseLoc);
-
- /// SetClassDeclAttributesFromBase - Copies class decl traits
- /// (such as whether the class has a trivial constructor,
+
+ /// SetClassDeclAttributesFromBase - Copies class decl traits
+ /// (such as whether the class has a trivial constructor,
/// trivial destructor etc) from the given base class.
void SetClassDeclAttributesFromBase(CXXRecordDecl *Class,
const CXXRecordDecl *BaseClass,
bool BaseIsVirtual);
-
+
virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl,
SourceRange SpecifierRange,
bool Virtual, AccessSpecifier Access,
@@ -2583,15 +2652,21 @@ public:
bool IsDerivedFrom(QualType Derived, QualType Base);
bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths);
-
+
+ // FIXME: I don't like this name.
+ void BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXBaseSpecifierArray &BasePath);
+
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
+ CXXBaseSpecifierArray *BasePath = 0,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
- DeclarationName Name);
+ DeclarationName Name,
+ CXXBaseSpecifierArray *BasePath);
std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
@@ -2636,6 +2711,7 @@ public:
DeclAccessPair FoundDecl);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
+ const InitializedEntity &Entity,
AccessSpecifier Access);
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
@@ -2691,23 +2767,23 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS,
+ void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
QualType ObjectType, bool EnteringContext);
virtual TemplateNameKind isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
-
- virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+
+ virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
const CXXScopeSpec *SS,
TemplateTy &SuggestedTemplate,
TemplateNameKind &SuggestedKind);
-
+
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
@@ -2765,10 +2841,11 @@ public:
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
+ bool IsFriend,
bool &IsExplicitSpecialization);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
@@ -2776,7 +2853,7 @@ public:
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
-
+
QualType CheckTemplateIdType(TemplateName Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo &TemplateArgs);
@@ -2796,13 +2873,13 @@ public:
LookupResult &R,
bool RequiresADL,
const TemplateArgumentListInfo &TemplateArgs);
- OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+ OwningExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &TemplateArgs);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext);
@@ -2815,7 +2892,7 @@ public:
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -2839,12 +2916,16 @@ public:
TemplateSpecializationKind PrevTSK,
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew);
-
+
+ bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ LookupResult &Previous);
+
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
-
+
virtual DeclResult
ActOnExplicitInstantiation(Scope *S,
SourceLocation ExternLoc,
@@ -2865,7 +2946,7 @@ public:
SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr);
@@ -2874,8 +2955,8 @@ public:
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
Declarator &D);
-
- TemplateArgumentLoc
+
+ TemplateArgumentLoc
SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
@@ -2905,7 +2986,7 @@ public:
SourceLocation RAngleLoc,
TemplateArgumentListBuilder &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
-
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo &TemplateArgs,
@@ -2918,23 +2999,23 @@ public:
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
- bool CheckTemplateArgumentPointerToMember(Expr *Arg,
+ bool CheckTemplateArgumentPointerToMember(Expr *Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
- bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
+ bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
- OwningExprResult
+ OwningExprResult
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc);
- OwningExprResult
+ OwningExprResult
BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc);
-
+
/// \brief Enumeration describing how template parameter lists are compared
/// for equality.
enum TemplateParameterListEqualKind {
@@ -2946,7 +3027,7 @@ public:
/// template<typename T> struct X;
/// \endcode
TPL_TemplateMatch,
-
+
/// \brief We are matching the template parameter lists of two template
/// template parameters as part of matching the template parameter lists
/// of two templates that might be redeclarations.
@@ -2956,7 +3037,7 @@ public:
/// template<template<int Value> class Other> struct X;
/// \endcode
TPL_TemplateTemplateParmMatch,
-
+
/// \brief We are matching the template parameter lists of a template
/// template argument against the template parameter lists of a template
/// template parameter.
@@ -2968,7 +3049,7 @@ public:
/// \endcode
TPL_TemplateTemplateArgumentMatch
};
-
+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
@@ -3001,12 +3082,15 @@ public:
ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
SourceLocation TemplateLoc, TypeTy *Ty);
- QualType CheckTypenameType(NestedNameSpecifier *NNS,
+ QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
const IdentifierInfo &II,
SourceRange Range);
- QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
- DeclarationName Name);
+ TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+ SourceLocation Loc,
+ DeclarationName Name);
+ bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
@@ -3016,7 +3100,7 @@ public:
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgument *Args,
unsigned NumArgs);
-
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -3205,27 +3289,28 @@ public:
const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag,
const PartialDiagnostic &CandidateDiag);
-
+
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
ClassTemplatePartialSpecializationDecl *PS2,
SourceLocation Loc);
-
+
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallVectorImpl<bool> &Used);
void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<bool> &Deduced);
-
+
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost = 0,
- bool RelativeToPrimary = false);
+ bool RelativeToPrimary = false,
+ const FunctionDecl *Pattern = 0);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
@@ -3257,12 +3342,12 @@ public:
/// Entity is either a ClassTemplatePartialSpecializationDecl or
/// a FunctionTemplateDecl.
DeducedTemplateArgumentSubstitution,
-
+
/// We are substituting prior template arguments into a new
/// template parameter. The template parameter itself is either a
/// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
PriorTemplateArgumentSubstitution,
-
+
/// We are checking the validity of a default template argument that
/// has been used when naming a template-id.
DefaultTemplateArgumentChecking
@@ -3274,7 +3359,7 @@ public:
/// \brief The template in which we are performing the instantiation,
/// for substitutions of prior template arguments.
TemplateDecl *Template;
-
+
/// \brief The entity that is being instantiated.
uintptr_t Entity;
@@ -3291,13 +3376,13 @@ public:
SourceRange InstantiationRange;
ActiveTemplateInstantiation()
- : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
+ : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
NumTemplateArgs(0) {}
/// \brief Determines whether this template is an actual instantiation
/// that should be counted toward the maximum instantiation depth.
bool isInstantiationRecord() const;
-
+
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
if (X.Kind != Y.Kind)
@@ -3314,9 +3399,9 @@ public:
case DefaultTemplateArgumentChecking:
if (X.Template != Y.Template)
return false;
-
+
// Fall through
-
+
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
@@ -3347,7 +3432,7 @@ public:
/// \c ActiveTemplateInstantiations that are not actual instantiations and,
/// therefore, should not be counted as part of the instantiation depth.
unsigned NonInstantiationEntries;
-
+
/// \brief The last template from which a template instantiation
/// error or warning was produced.
///
@@ -3422,7 +3507,7 @@ public:
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange);
-
+
/// \brief Note that we are checking the default template argument
/// against the template parameter for a given template-id.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -3431,8 +3516,8 @@ public:
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange);
-
-
+
+
/// \brief Note that we have finished instantiating this template.
void Clear();
@@ -3510,7 +3595,7 @@ public:
/// instantiated ParmVarDecl for 'x'.
llvm::DenseMap<const Decl *, Decl *> LocalDecls;
- /// \brief The outer scope, in which contains local variable
+ /// \brief The outer scope, which contains local variable
/// definitions from some other instantiation (that may not be
/// relevant to this particular scope).
LocalInstantiationScope *Outer;
@@ -3518,54 +3603,36 @@ public:
/// \brief Whether we have already exited this scope.
bool Exited;
- /// \brief Whether this scope is temporary, meaning that we should
- /// remove any additions we make once we exit this
- /// scope. Temporary scopes are always combined with their outer
- /// scopes.
- bool Temporary;
-
- /// \brief List of the declarations that we have added into this
- /// temporary scope. They will be removed when we exit the
- /// temporary scope.
- llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
-
+ /// \brief Whether to combine this scope with the outer scope, such that
+ /// lookup will search our outer scope.
+ bool CombineWithOuterScope;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
- bool Temporary = false)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false), Temporary(Temporary) {
- if (!CombineWithOuterScope && !Temporary)
- SemaRef.CurrentInstantiationScope = this;
- else
- assert(SemaRef.CurrentInstantiationScope &&
- "No outer instantiation scope?");
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
+ Exited(false), CombineWithOuterScope(CombineWithOuterScope)
+ {
+ SemaRef.CurrentInstantiationScope = this;
}
~LocalInstantiationScope() {
- if (!Exited) {
- SemaRef.CurrentInstantiationScope = Outer;
- for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
- LocalDecls.erase(AddedTemporaryDecls[I]);
- }
+ Exit();
}
/// \brief Exit this local instantiation scope early.
void Exit() {
+ if (Exited)
+ return;
+
SemaRef.CurrentInstantiationScope = Outer;
- LocalDecls.clear();
Exited = true;
}
- Decl *getInstantiationOf(const Decl *D) {
- Decl *Result = LocalDecls[D];
- assert((Result || D->isInvalidDecl()) &&
- "declaration was not instantiated in this scope!");
- return Result;
- }
+ Decl *getInstantiationOf(const Decl *D);
VarDecl *getInstantiationOf(const VarDecl *Var) {
return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
@@ -3579,16 +3646,8 @@ public:
const NonTypeTemplateParmDecl *Var) {
return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var)));
}
-
- void InstantiatedLocal(const Decl *D, Decl *Inst) {
- Decl *&Stored = LocalDecls[D];
- assert((!Stored || Stored == Inst) && "Already instantiated this local");
- if (Temporary && !Stored)
- AddedTemporaryDecls.push_back(D);
-
- Stored = Inst;
- }
+ void InstantiatedLocal(const Decl *D, Decl *Inst);
};
/// \brief The current instantiation scope used to store local
@@ -3634,6 +3693,12 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc, DeclarationName Entity);
+ TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SourceLocation Loc,
+ DeclarationName Entity);
+ ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
OwningExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -3701,8 +3766,6 @@ public:
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
- bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params);
-
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,
@@ -3823,7 +3886,7 @@ public:
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
- llvm::SmallVectorImpl<Declarator> &Cdecls,
+ DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind,
bool isVariadic = false);
@@ -3836,28 +3899,66 @@ public:
ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl);
- virtual OwningExprResult ActOnClassPropertyRefExpr(
- IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation &receiverNameLoc,
- SourceLocation &propertyNameLoc);
-
- // ActOnClassMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnClassMessage(
- Scope *S,
- IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac,
- SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs);
-
- // ActOnInstanceMessage - used for both unary and keyword messages.
- // ArgExprs is optional - if it is present, the number of expressions
- // is obtained from NumArgs.
- virtual ExprResult ActOnInstanceMessage(
- ExprTy *receiver, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac,
- ExprTy **ArgExprs, unsigned NumArgs);
+ OwningExprResult
+ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
+ Expr *BaseExpr,
+ DeclarationName MemberName,
+ SourceLocation MemberLoc);
+
+ virtual OwningExprResult
+ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation receiverNameLoc,
+ SourceLocation propertyNameLoc);
+
+ virtual ObjCMessageKind getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType);
+
+ virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ OwningExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ virtual OwningExprResult ActOnClassMessage(Scope *S,
+ TypeTy *Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ OwningExprResult BuildInstanceMessage(ExprArg Receiver,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
+ virtual OwningExprResult ActOnInstanceMessage(Scope *S,
+ ExprArg Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args);
+
/// ActOnPragmaPack - Called on well formed #pragma pack(...).
virtual void ActOnPragmaPack(PragmaPackKind Kind,
@@ -3900,7 +4001,9 @@ public:
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind,
- bool isLvalue = false);
+ bool isLvalue = false,
+ CXXBaseSpecifierArray BasePath =
+ CXXBaseSpecifierArray());
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1).
@@ -3985,11 +4088,11 @@ public:
/// CompatiblePointerDiscardsQualifiers - The assignment discards
/// c/v/r qualifiers, which we accept as an extension.
CompatiblePointerDiscardsQualifiers,
-
+
/// IncompatibleNestedPointerQualifiers - The assignment is between two
/// nested pointer types, and the qualifiers other than the first two
- /// levels differ e.g. char ** -> const char **, but we accept them as an
- /// extension.
+ /// levels differ e.g. char ** -> const char **, but we accept them as an
+ /// extension.
IncompatibleNestedPointerQualifiers,
/// IncompatibleVectors - The assignment is between two vector types that
@@ -4013,14 +4116,15 @@ public:
/// represent it in the AST.
Incompatible
};
-
+
/// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
/// assignment conversion type specified by ConvTy. This returns true if the
/// conversion was invalid or false if the conversion was accepted.
bool DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, AssignmentAction Action);
+ Expr *SrcExpr, AssignmentAction Action,
+ bool *Complained = 0);
/// CheckAssignmentConstraints - Perform type checking for assignment,
/// argument passing, variable initialization, and function return values.
@@ -4056,12 +4160,10 @@ public:
bool PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action,
- bool AllowExplicit = false,
- bool Elidable = false);
+ bool AllowExplicit = false);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action,
bool AllowExplicit,
- bool Elidable,
ImplicitConversionSequence& ICS);
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence& ICS,
@@ -4106,12 +4208,12 @@ public:
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
- QualType FindCompositePointerType(Expr *&E1, Expr *&E2,
+ QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType = 0);
QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
SourceLocation questionLoc);
-
+
/// type checking for vector binary operators.
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx,
@@ -4120,7 +4222,7 @@ public:
/// type checking unary operators (subroutines of ActOnUnaryOp).
/// C99 6.5.3.1, 6.5.3.2, 6.5.3.4
QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc,
- bool isInc);
+ bool isInc, bool isPrefix);
QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal);
@@ -4162,19 +4264,10 @@ public:
QualType T1, QualType T2,
bool& DerivedToBase);
- bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType,
- SourceLocation DeclLoc,
- bool SuppressUserConversions,
- bool AllowExplicit,
- bool ForceRValue,
- ImplicitConversionSequence *ICS = 0,
- bool IgnoreBaseAccess = false);
-
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics, or forward to CXXCheckCStyleCast in C++.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *& ConversionDecl,
+ CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath,
bool FunctionalStyle = false);
// CheckVectorCast - check type constraints for vectors.
@@ -4195,8 +4288,9 @@ public:
/// CXXCheckCStyleCast - Check constraints of a C-style or function-style
/// cast under C++ semantics.
bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind, bool FunctionalStyle,
- CXXMethodDecl *&ConversionDecl);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
+ bool FunctionalStyle);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
@@ -4253,7 +4347,7 @@ public:
/// \name Code completion
//@{
- virtual void CodeCompleteOrdinaryName(Scope *S,
+ virtual void CodeCompleteOrdinaryName(Scope *S,
CodeCompletionContext CompletionContext);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
SourceLocation OpLoc,
@@ -4262,14 +4356,14 @@ public:
virtual void CodeCompleteCase(Scope *S);
virtual void CodeCompleteCall(Scope *S, ExprTy *Fn,
ExprTy **Args, unsigned NumArgs);
- virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+ virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext);
virtual void CodeCompleteUsing(Scope *S);
virtual void CodeCompleteUsingDirective(Scope *S);
virtual void CodeCompleteNamespaceDecl(Scope *S);
virtual void CodeCompleteNamespaceAliasDecl(Scope *S);
virtual void CodeCompleteOperatorName(Scope *S);
-
+
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
bool InInterface);
virtual void CodeCompleteObjCAtVisibility(Scope *S);
@@ -4283,9 +4377,11 @@ public:
DeclPtrTy *Methods,
unsigned NumMethods);
- virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
- SourceLocation FNameLoc,
- IdentifierInfo **SelIdents,
+ virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents);
+ virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
+ IdentifierInfo **SelIdents,
unsigned NumSelIdents);
virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
IdentifierInfo **SelIdents,
@@ -4294,20 +4390,27 @@ public:
unsigned NumProtocols);
virtual void CodeCompleteObjCProtocolDecl(Scope *S);
virtual void CodeCompleteObjCInterfaceDecl(Scope *S);
- virtual void CodeCompleteObjCSuperclass(Scope *S,
- IdentifierInfo *ClassName);
+ virtual void CodeCompleteObjCSuperclass(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
virtual void CodeCompleteObjCImplementationDecl(Scope *S);
- virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
- IdentifierInfo *ClassName);
- virtual void CodeCompleteObjCImplementationCategory(Scope *S,
- IdentifierInfo *ClassName);
- virtual void CodeCompleteObjCPropertyDefinition(Scope *S,
+ virtual void CodeCompleteObjCInterfaceCategory(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
+ virtual void CodeCompleteObjCImplementationCategory(Scope *S,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc);
+ virtual void CodeCompleteObjCPropertyDefinition(Scope *S,
DeclPtrTy ObjCImpDecl);
- virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
+ virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
IdentifierInfo *PropertyName,
DeclPtrTy ObjCImpDecl);
+ virtual void CodeCompleteObjCMethodDecl(Scope *S,
+ bool IsInstanceMethod,
+ TypeTy *ReturnType,
+ DeclPtrTy IDecl);
//@}
-
+
//===--------------------------------------------------------------------===//
// Extra semantic analysis beyond the C type system
@@ -4327,7 +4430,6 @@ private:
bool SemaBuiltinVAStart(CallExpr *TheCall);
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
- bool SemaBuiltinStackAddress(CallExpr *TheCall);
public:
// Used by C++ template instantiation.
@@ -4338,7 +4440,8 @@ private:
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall);
- bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall);
+ bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
+ llvm::APSInt &Result);
bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg);
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index f628884aab42..444ee798587d 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInit.h"
#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -22,6 +23,13 @@
using namespace clang;
+/// A copy of Sema's enum without AR_delayed.
+enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent
+};
+
/// SetMemberAccessSpecifier - Set the access specifier of a member.
/// Returns true on error (when the previous member decl access specifier
/// is different from the new member decl access specifier).
@@ -51,6 +59,20 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
+static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
+ DeclContext *DC = D->getDeclContext();
+
+ // This can only happen at top: enum decls only "publish" their
+ // immediate members.
+ if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
+ while (DeclaringClass->isAnonymousStructOrUnion())
+ DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
+ return DeclaringClass;
+}
+
namespace {
struct EffectiveContext {
EffectiveContext() : Inner(0), Dependent(false) {}
@@ -109,22 +131,168 @@ struct EffectiveContext {
llvm::SmallVector<CXXRecordDecl*, 4> Records;
bool Dependent;
};
+
+/// Like Sema's AccessedEntity, but kindly lets us scribble all over
+/// it.
+struct AccessTarget : public Sema::AccessedEntity {
+ AccessTarget(const Sema::AccessedEntity &Entity)
+ : AccessedEntity(Entity) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ BaseNonce _,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access)
+ : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) {
+ initialize();
+ }
+
+ bool hasInstanceContext() const {
+ return HasInstanceContext;
+ }
+
+ class SavedInstanceContext {
+ public:
+ ~SavedInstanceContext() {
+ Target.HasInstanceContext = Has;
+ }
+
+ private:
+ friend struct AccessTarget;
+ explicit SavedInstanceContext(AccessTarget &Target)
+ : Target(Target), Has(Target.HasInstanceContext) {}
+ AccessTarget &Target;
+ bool Has;
+ };
+
+ SavedInstanceContext saveInstanceContext() {
+ return SavedInstanceContext(*this);
+ }
+
+ void suppressInstanceContext() {
+ HasInstanceContext = false;
+ }
+
+ const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
+ assert(HasInstanceContext);
+ if (CalculatedInstanceContext)
+ return InstanceContext;
+
+ CalculatedInstanceContext = true;
+ DeclContext *IC = S.computeDeclContext(getBaseObjectType());
+ InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0);
+ return InstanceContext;
+ }
+
+ const CXXRecordDecl *getDeclaringClass() const {
+ return DeclaringClass;
+ }
+
+private:
+ void initialize() {
+ HasInstanceContext = (isMemberAccess() &&
+ !getBaseObjectType().isNull() &&
+ getTargetDecl()->isCXXInstanceMember());
+ CalculatedInstanceContext = false;
+ InstanceContext = 0;
+
+ if (isMemberAccess())
+ DeclaringClass = FindDeclaringClass(getTargetDecl());
+ else
+ DeclaringClass = getBaseClass();
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+ }
+
+ bool HasInstanceContext : 1;
+ mutable bool CalculatedInstanceContext : 1;
+ mutable const CXXRecordDecl *InstanceContext;
+ const CXXRecordDecl *DeclaringClass;
+};
+
}
-static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
- DeclContext *DC = D->getDeclContext();
+/// Checks whether one class might instantiate to the other.
+static bool MightInstantiateTo(const CXXRecordDecl *From,
+ const CXXRecordDecl *To) {
+ // Declaration names are always preserved by instantiation.
+ if (From->getDeclName() != To->getDeclName())
+ return false;
- // This can only happen at top: enum decls only "publish" their
- // immediate members.
- if (isa<EnumDecl>(DC))
- DC = cast<EnumDecl>(DC)->getDeclContext();
+ const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
+ const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
+ if (FromDC == ToDC) return true;
+ if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
- while (DeclaringClass->isAnonymousStructOrUnion())
- DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
- return DeclaringClass;
+ // Be conservative.
+ return true;
}
+/// Checks whether one class is derived from another, inclusively.
+/// Properly indicates when it couldn't be determined due to
+/// dependence.
+///
+/// This should probably be donated to AST or at least Sema.
+static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *Target) {
+ assert(Derived->getCanonicalDecl() == Derived);
+ assert(Target->getCanonicalDecl() == Target);
+
+ if (Derived == Target) return AR_accessible;
+
+ bool CheckDependent = Derived->isDependentContext();
+ if (CheckDependent && MightInstantiateTo(Derived, Target))
+ return AR_dependent;
+
+ AccessResult OnFailure = AR_inaccessible;
+ llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
+
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
+
+ const CXXRecordDecl *RD;
+
+ QualType T = I->getType();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RD = cast<CXXRecordDecl>(RT->getDecl());
+ } else if (const InjectedClassNameType *IT
+ = T->getAs<InjectedClassNameType>()) {
+ RD = IT->getDecl();
+ } else {
+ assert(T->isDependentType() && "non-dependent base wasn't a record?");
+ OnFailure = AR_dependent;
+ continue;
+ }
+
+ RD = RD->getCanonicalDecl();
+ if (RD == Target) return AR_accessible;
+ if (CheckDependent && MightInstantiateTo(RD, Target))
+ OnFailure = AR_dependent;
+
+ Queue.push_back(RD);
+ }
+
+ if (Queue.empty()) break;
+
+ Derived = Queue.back();
+ Queue.pop_back();
+ }
+
+ return OnFailure;
+}
+
+
static bool MightInstantiateTo(Sema &S, DeclContext *Context,
DeclContext *Friend) {
if (Friend == Context)
@@ -204,11 +372,11 @@ static bool MightInstantiateTo(Sema &S,
Friend->getTemplatedDecl());
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Friend) {
if (EC.includesClass(Friend))
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent()) {
CanQualType FriendTy
@@ -219,32 +387,32 @@ static Sema::AccessResult MatchesFriend(Sema &S,
CanQualType ContextTy
= S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
if (MightInstantiateTo(S, ContextTy, FriendTy))
- return Sema::AR_dependent;
+ return AR_dependent;
}
}
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- CanQualType Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ CanQualType Friend) {
if (const RecordType *RT = Friend->getAs<RecordType>())
return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
// TODO: we can do better than this
if (Friend->isDependentType())
- return Sema::AR_dependent;
+ return AR_dependent;
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
/// Determines whether the given friend class template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- ClassTemplateDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ ClassTemplateDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
// Check whether the friend is the template of a class in the
// context chain.
@@ -268,7 +436,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
// It's a match.
if (Friend == CTD->getCanonicalDecl())
- return Sema::AR_accessible;
+ return AR_accessible;
// If the context isn't dependent, it can't be a dependent match.
if (!EC.isDependent())
@@ -286,7 +454,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
continue;
// Otherwise, it's a dependent match.
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -294,18 +462,18 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function matches anything in
/// the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (Friend == *I)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -313,12 +481,12 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionTemplateDecl *Friend) {
- if (EC.Functions.empty()) return Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionTemplateDecl *Friend) {
+ if (EC.Functions.empty()) return AR_inaccessible;
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
@@ -332,10 +500,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
FTD = FTD->getCanonicalDecl();
if (Friend == FTD)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -343,9 +511,9 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend declaration matches anything
/// in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FriendDecl *FriendD) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *FriendD) {
if (TypeSourceInfo *T = FriendD->getFriendType())
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
@@ -367,10 +535,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
-static Sema::AccessResult GetFriendKind(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Class) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ AccessResult OnFailure = AR_inaccessible;
// Okay, check friends.
for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
@@ -378,18 +546,15 @@ static Sema::AccessResult GetFriendKind(Sema &S,
FriendDecl *Friend = *I;
switch (MatchesFriend(S, EC, Friend)) {
- case Sema::AR_accessible:
- return Sema::AR_accessible;
+ case AR_accessible:
+ return AR_accessible;
- case Sema::AR_inaccessible:
- break;
+ case AR_inaccessible:
+ continue;
- case Sema::AR_dependent:
- OnFailure = Sema::AR_dependent;
+ case AR_dependent:
+ OnFailure = AR_dependent;
break;
-
- case Sema::AR_delayed:
- llvm_unreachable("cannot get delayed answer from MatchesFriend");
}
}
@@ -397,16 +562,19 @@ static Sema::AccessResult GetFriendKind(Sema &S,
return OnFailure;
}
-static Sema::AccessResult HasAccess(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *NamingClass,
- AccessSpecifier Access) {
+static AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const AccessTarget &Target) {
assert(NamingClass->getCanonicalDecl() == NamingClass &&
"declaration should be canonicalized before being passed here");
- if (Access == AS_public) return Sema::AR_accessible;
+ if (Access == AS_public) return AR_accessible;
assert(Access == AS_private || Access == AS_protected);
+ AccessResult OnFailure = AR_inaccessible;
+
for (EffectiveContext::record_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
// All the declarations in EC have been canonicalized, so pointer
@@ -414,16 +582,78 @@ static Sema::AccessResult HasAccess(Sema &S,
const CXXRecordDecl *ECRecord = *I;
// [B2] and [M2]
- if (ECRecord == NamingClass)
- return Sema::AR_accessible;
+ if (Access == AS_private) {
+ if (ECRecord == NamingClass)
+ return AR_accessible;
+
+ if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
+ OnFailure = AR_dependent;
// [B3] and [M3]
- if (Access == AS_protected &&
- ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
- return Sema::AR_accessible;
+ } else {
+ assert(Access == AS_protected);
+ switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+
+ if (!Target.hasInstanceContext())
+ return AR_accessible;
+
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) {
+ OnFailure = AR_dependent;
+ continue;
+ }
+
+ // C++ [class.protected]p1:
+ // An additional access check beyond those described earlier in
+ // [class.access] is applied when a non-static data member or
+ // non-static member function is a protected member of its naming
+ // class. As described earlier, access to a protected member is
+ // granted because the reference occurs in a friend or member of
+ // some class C. If the access is to form a pointer to member,
+ // the nested-name-specifier shall name C or a class derived from
+ // C. All other accesses involve a (possibly implicit) object
+ // expression. In this case, the class of the object expression
+ // shall be C or a class derived from C.
+ //
+ // We interpret this as a restriction on [M3]. Most of the
+ // conditions are encoded by not having any instance context.
+ switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+ }
}
- return GetFriendKind(S, EC, NamingClass);
+ if (!NamingClass->hasFriends())
+ return OnFailure;
+
+ // Don't consider friends if we're under the [class.protected]
+ // restriction, above.
+ if (Access == AS_protected && Target.hasInstanceContext()) {
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) return AR_dependent;
+
+ switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: return OnFailure;
+ case AR_dependent: return AR_dependent;
+ }
+ }
+
+ switch (GetFriendKind(S, EC, NamingClass)) {
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: return OnFailure;
+ case AR_dependent: return AR_dependent;
+ }
+
+ // Silence bogus warnings
+ llvm_unreachable("impossible friendship kind");
+ return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
@@ -479,17 +709,21 @@ static Sema::AccessResult HasAccess(Sema &S,
///
/// B is an accessible base of N at R iff ACAB(1) = public.
///
-/// \param FinalAccess the access of the "final step", or AS_none if
+/// \param FinalAccess the access of the "final step", or AS_public if
/// there is no final step.
/// \return null if friendship is dependent
static CXXBasePath *FindBestPath(Sema &S,
const EffectiveContext &EC,
- CXXRecordDecl *Derived,
- CXXRecordDecl *Base,
+ AccessTarget &Target,
AccessSpecifier FinalAccess,
CXXBasePaths &Paths) {
// Derive the paths to the desired base.
- bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ const CXXRecordDecl *Derived = Target.getNamingClass();
+ const CXXRecordDecl *Base = Target.getDeclaringClass();
+
+ // FIXME: fail correctly when there are dependent paths.
+ bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
+ Paths);
assert(isDerived && "derived class not actually derived from base");
(void) isDerived;
@@ -502,6 +736,7 @@ static CXXBasePath *FindBestPath(Sema &S,
// Derive the friend-modified access along each path.
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
+ AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
// Walk through the path backwards.
AccessSpecifier PathAccess = FinalAccess;
@@ -519,16 +754,23 @@ static CXXBasePath *FindBestPath(Sema &S,
break;
}
+ const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
+
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
PathAccess = std::max(PathAccess, BaseAccess);
- switch (HasAccess(S, EC, I->Class, PathAccess)) {
- case Sema::AR_inaccessible: break;
- case Sema::AR_accessible: PathAccess = AS_public; break;
- case Sema::AR_dependent:
+
+ switch (HasAccess(S, EC, NC, PathAccess, Target)) {
+ case AR_inaccessible: break;
+ case AR_accessible:
+ PathAccess = AS_public;
+
+ // Future tests are not against members and so do not have
+ // instance context.
+ Target.suppressInstanceContext();
+ break;
+ case AR_dependent:
AnyDependent = true;
goto Next;
- case Sema::AR_delayed:
- llvm_unreachable("friend resolution is never delayed"); break;
}
}
@@ -561,46 +803,36 @@ static CXXBasePath *FindBestPath(Sema &S,
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
AccessSpecifier Access = Entity.getAccess();
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ const CXXRecordDecl *NamingClass = Entity.getNamingClass();
NamingClass = NamingClass->getCanonicalDecl();
- NamedDecl *D;
- CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- D = Entity.getTargetDecl();
- DeclaringClass = FindDeclaringClass(D);
- } else {
- D = 0;
- DeclaringClass = Entity.getBaseClass();
- }
- DeclaringClass = DeclaringClass->getCanonicalDecl();
+ NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
// Easy case: the decl's natural access determined its path access.
// We have to check against AS_private here in case Access is AS_none,
// indicating a non-public member of a private base class.
if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) {
- case Sema::AR_inaccessible: {
+ switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
+ case AR_inaccessible: {
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
<< /*FIXME: not implicitly*/ 0;
return;
}
- case Sema::AR_accessible: break;
+ case AR_accessible: break;
- case Sema::AR_dependent:
- case Sema::AR_delayed:
- llvm_unreachable("dependent/delayed not allowed");
+ case AR_dependent:
+ llvm_unreachable("can't diagnose dependent access failures");
return;
}
}
CXXBasePaths Paths;
- CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
- AS_public, Paths);
+ CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths);
CXXBasePath::iterator I = Path.end(), E = Path.begin();
while (I != E) {
@@ -615,12 +847,10 @@ static void DiagnoseAccessPath(Sema &S,
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");
+ case AR_accessible: continue;
+ case AR_inaccessible: break;
+ case AR_dependent:
+ llvm_unreachable("can't diagnose dependent access failures");
}
// Check whether this base specifier is the tighest point
@@ -649,17 +879,10 @@ static void DiagnoseAccessPath(Sema &S,
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
const CXXRecordDecl *NamingClass = Entity.getNamingClass();
- NamedDecl *D;
- const CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- D = Entity.getTargetDecl();
- DeclaringClass = FindDeclaringClass(D);
- } else {
- D = 0;
- DeclaringClass = Entity.getBaseClass();
- }
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
+ NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
S.Diag(Loc, Entity.getDiag())
<< (Entity.getAccess() == AS_protected)
@@ -671,9 +894,9 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
/// Determines whether the accessed entity is accessible. Public members
/// have been weeded out by this point.
-static Sema::AccessResult IsAccessible(Sema &S,
- const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity) {
+static AccessResult IsAccessible(Sema &S,
+ const EffectiveContext &EC,
+ AccessTarget &Entity) {
// Determine the actual naming class.
CXXRecordDecl *NamingClass = Entity.getNamingClass();
while (NamingClass->isAnonymousStructOrUnion())
@@ -686,10 +909,10 @@ static Sema::AccessResult IsAccessible(Sema &S,
// Before we try to recalculate access paths, try to white-list
// accesses which just trade in on the final step, i.e. accesses
// which don't require [M4] or [B4]. These are by far the most
- // common forms of access.
+ // common forms of privileged access.
if (UnprivilegedAccess != AS_none) {
- switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) {
- case Sema::AR_dependent:
+ switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
+ case AR_dependent:
// This is actually an interesting policy decision. We don't
// *have* to delay immediately here: we can do the full access
// calculation in the hope that friendship on some intermediate
@@ -697,23 +920,14 @@ static Sema::AccessResult IsAccessible(Sema &S,
// But that's not cheap, and odds are very good (note: assertion
// made without data) that the friend declaration will determine
// access.
- return Sema::AR_dependent;
+ return AR_dependent;
- case Sema::AR_accessible: return Sema::AR_accessible;
- case Sema::AR_inaccessible: break;
- case Sema::AR_delayed:
- llvm_unreachable("friendship never subject to contextual delay");
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: break;
}
}
- // Determine the declaring class.
- CXXRecordDecl *DeclaringClass;
- if (Entity.isMemberAccess()) {
- DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
- } else {
- DeclaringClass = Entity.getBaseClass();
- }
- DeclaringClass = DeclaringClass->getCanonicalDecl();
+ AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
// We lower member accesses to base accesses by pretending that the
// member is a base class of its declaring class.
@@ -723,43 +937,44 @@ static Sema::AccessResult IsAccessible(Sema &S,
// Determine if the declaration is accessible from EC when named
// in its declaring class.
NamedDecl *Target = Entity.getTargetDecl();
+ const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
FinalAccess = Target->getAccess();
- switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) {
- case Sema::AR_accessible: FinalAccess = AS_public; break;
- case Sema::AR_inaccessible: break;
- case Sema::AR_dependent: return Sema::AR_dependent; // see above
- case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
+ switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
+ case AR_accessible:
+ FinalAccess = AS_public;
+ break;
+ case AR_inaccessible: break;
+ case AR_dependent: return AR_dependent; // see above
}
if (DeclaringClass == NamingClass)
- return (FinalAccess == AS_public
- ? Sema::AR_accessible
- : Sema::AR_inaccessible);
+ return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
+
+ Entity.suppressInstanceContext();
} else {
FinalAccess = AS_public;
}
- assert(DeclaringClass != NamingClass);
+ assert(Entity.getDeclaringClass() != NamingClass);
// Append the declaration's access if applicable.
CXXBasePaths Paths;
- CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass,
- FinalAccess, Paths);
+ CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
if (!Path)
- return Sema::AR_dependent;
+ return AR_dependent;
assert(Path->Access <= UnprivilegedAccess &&
"access along best path worse than direct?");
if (Path->Access == AS_public)
- return Sema::AR_accessible;
- return Sema::AR_inaccessible;
+ return AR_accessible;
+ return AR_inaccessible;
}
-static void DelayAccess(Sema &S,
- const EffectiveContext &EC,
- SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+static void DelayDependentAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ const AccessTarget &Entity) {
assert(EC.isDependent() && "delaying non-dependent access");
DeclContext *DC = EC.getInnerContext();
assert(DC->isDependentContext() && "delaying non-dependent access");
@@ -769,48 +984,38 @@ static void DelayAccess(Sema &S,
Entity.getAccess(),
Entity.getTargetDecl(),
Entity.getNamingClass(),
+ Entity.getBaseObjectType(),
Entity.getDiag());
}
/// Checks access to an entity from the given effective context.
-static Sema::AccessResult CheckEffectiveAccess(Sema &S,
- const EffectiveContext &EC,
- SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+static AccessResult CheckEffectiveAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
switch (IsAccessible(S, EC, Entity)) {
- case Sema::AR_dependent:
- DelayAccess(S, EC, Loc, Entity);
- return Sema::AR_dependent;
-
- case Sema::AR_delayed:
- llvm_unreachable("IsAccessible cannot contextually delay");
+ case AR_dependent:
+ DelayDependentAccess(S, EC, Loc, Entity);
+ return AR_dependent;
- case Sema::AR_inaccessible:
+ case AR_inaccessible:
if (!Entity.isQuiet())
DiagnoseBadAccess(S, Loc, EC, Entity);
- return Sema::AR_inaccessible;
-
- case Sema::AR_accessible:
- break;
- }
+ return AR_inaccessible;
- // We only consider the natural access of the declaration when
- // deciding whether to do the protected check.
- if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) {
- NamedDecl *D = Entity.getTargetDecl();
- if (isa<FieldDecl>(D) ||
- (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) {
- // FIXME: implement [class.protected]
- }
+ case AR_accessible:
+ return AR_accessible;
}
- return Sema::AR_accessible;
+ // silence unnecessary warning
+ llvm_unreachable("invalid access result");
+ return AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
- const Sema::AccessedEntity &Entity) {
+ AccessTarget &Entity) {
// If the access path is public, it's accessible everywhere.
if (Entity.getAccess() == AS_public)
return Sema::AR_accessible;
@@ -825,16 +1030,31 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
return Sema::AR_delayed;
}
- return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
- Loc, Entity);
+ EffectiveContext EC(S.CurContext);
+ switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
+ case AR_accessible: return Sema::AR_accessible;
+ case AR_inaccessible: return Sema::AR_inaccessible;
+ case AR_dependent: return Sema::AR_dependent;
+ }
+ llvm_unreachable("falling off end");
+ return Sema::AR_accessible;
}
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.getAccessData()))
+ // declaration. If that declaration itself forms a declaration context,
+ // include it in the effective context so that parameters and return types of
+ // befriended functions have that function's access priveledges.
+ DeclContext *DC = Ctx->getDeclContext();
+ if (isa<FunctionDecl>(Ctx))
+ DC = cast<DeclContext>(Ctx);
+ else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx))
+ DC = cast<DeclContext>(FnTpl->getTemplatedDecl());
+ EffectiveContext EC(DC);
+
+ AccessTarget Target(DD.getAccessData());
+
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
DD.Triggered = true;
}
@@ -851,19 +1071,28 @@ void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
if (!TargetD) return;
if (DD.isAccessToMember()) {
- AccessedEntity Entity(Context,
- AccessedEntity::Member,
- cast<CXXRecordDecl>(NamingD),
- Access,
- cast<NamedDecl>(TargetD));
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
+ NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
+ QualType BaseObjectType = DD.getAccessBaseObjectType();
+ if (!BaseObjectType.isNull()) {
+ BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
+ DeclarationName());
+ if (BaseObjectType.isNull()) return;
+ }
+
+ AccessTarget Entity(Context,
+ AccessTarget::Member,
+ NamingClass,
+ DeclAccessPair::make(TargetDecl, Access),
+ BaseObjectType);
Entity.setDiag(DD.getDiagnostic());
CheckAccess(*this, Loc, Entity);
} else {
- AccessedEntity Entity(Context,
- AccessedEntity::Base,
- cast<CXXRecordDecl>(TargetD),
- cast<CXXRecordDecl>(NamingD),
- Access);
+ AccessTarget Entity(Context,
+ AccessTarget::Base,
+ cast<CXXRecordDecl>(TargetD),
+ cast<CXXRecordDecl>(NamingD),
+ Access);
Entity.setDiag(DD.getDiagnostic());
CheckAccess(*this, Loc, Entity);
}
@@ -876,8 +1105,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
- Found);
+ AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
+ Found, QualType());
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getNameLoc(), Entity);
@@ -891,8 +1120,12 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
- Found);
+ QualType BaseType = E->getBaseType();
+ if (E->isArrow())
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+
+ AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
+ Found, BaseType);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getMemberLoc(), Entity);
@@ -910,8 +1143,9 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Dtor, Access));
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Dtor, Access),
+ QualType());
Entity.setDiag(PDiag); // TODO: avoid copy
return CheckAccess(*this, Loc, Entity);
@@ -920,17 +1154,39 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ const InitializedEntity &Entity,
AccessSpecifier Access) {
if (!getLangOptions().AccessControl ||
Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Constructor, Access));
- Entity.setDiag(diag::err_access_ctor);
+ AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Access),
+ QualType());
+ switch (Entity.getKind()) {
+ default:
+ AccessEntity.setDiag(diag::err_access_ctor);
+ break;
- return CheckAccess(*this, UseLoc, Entity);
+ case InitializedEntity::EK_Base:
+ AccessEntity.setDiag(PDiag(diag::err_access_base)
+ << Entity.isInheritedVirtualBase()
+ << Entity.getBaseSpecifier()->getType()
+ << getSpecialMember(Constructor));
+ break;
+
+ case InitializedEntity::EK_Member: {
+ const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
+ AccessEntity.setDiag(PDiag(diag::err_access_field)
+ << Field->getType()
+ << getSpecialMember(Constructor));
+ break;
+ }
+
+ }
+
+ return CheckAccess(*this, UseLoc, AccessEntity);
}
/// Checks direct (i.e. non-inherited) access to an arbitrary class
@@ -944,8 +1200,9 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
- DeclAccessPair::make(Target, Access));
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Target, Access),
+ QualType());
Entity.setDiag(Diag);
return CheckAccess(*this, UseLoc, Entity);
}
@@ -961,7 +1218,8 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ QualType());
Entity.setDiag(diag::err_access)
<< PlacementRange;
@@ -982,7 +1240,8 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ ObjectExpr->getType());
Entity.setDiag(diag::err_access)
<< ObjectExpr->getSourceRange()
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
@@ -998,24 +1257,16 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
return AR_accessible;
OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
- NestedNameSpecifier *Qualifier = Ovl->getQualifier();
- assert(Qualifier && "address of overloaded member without qualifier");
+ CXXRecordDecl *NamingClass = Ovl->getNamingClass();
- CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- SS.setRange(Ovl->getQualifierRange());
- DeclContext *DC = computeDeclContext(SS);
- assert(DC && DC->isRecord() && "scope did not resolve to record");
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC);
-
- AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ Context.getTypeDeclType(NamingClass));
Entity.setDiag(diag::err_access)
<< Ovl->getSourceRange();
return CheckAccess(*this, Ovl->getNameLoc(), Entity);
}
-
/// Checks access for a hierarchy conversion.
///
/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
@@ -1042,13 +1293,20 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
- Path.Access);
+ AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
+ Path.Access);
if (DiagID)
Entity.setDiag(DiagID) << Derived << Base;
- if (ForceUnprivileged)
- return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
+ if (ForceUnprivileged) {
+ switch (CheckEffectiveAccess(*this, EffectiveContext(),
+ AccessLoc, Entity)) {
+ case ::AR_accessible: return Sema::AR_accessible;
+ case ::AR_inaccessible: return Sema::AR_inaccessible;
+ case ::AR_dependent: return Sema::AR_dependent;
+ }
+ llvm_unreachable("unexpected result from CheckEffectiveAccess");
+ }
return CheckAccess(*this, AccessLoc, Entity);
}
@@ -1060,9 +1318,9 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (I.getAccess() != AS_public) {
- AccessedEntity Entity(Context, AccessedEntity::Member,
- R.getNamingClass(),
- I.getPair());
+ AccessTarget Entity(Context, AccessedEntity::Member,
+ R.getNamingClass(), I.getPair(),
+ R.getBaseObjectType());
Entity.setDiag(diag::err_access);
CheckAccess(*this, R.getNameLoc(), Entity);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 11c8e6ddab5c..ba7e1ff6341b 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -47,11 +47,12 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CXXBaseSpecifierArray &BasePath);
static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
const SourceRange &DestRange,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
@@ -69,39 +70,43 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
QualType DestType, unsigned &msg);
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
- QualType DestType, bool CStyle,
- const SourceRange &OpRange,
- unsigned &msg,
- CastExpr::CastKind &Kind);
+ QualType DestType, bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
CanQualType DestType, bool CStyle,
const SourceRange &OpRange,
QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
- CastExpr::CastKind &Kind);
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr,
- QualType SrcType,
- QualType DestType,bool CStyle,
- const SourceRange &OpRange,
- unsigned &msg,
- CastExpr::CastKind &Kind);
+ QualType SrcType,
+ QualType DestType,bool CStyle,
+ const SourceRange &OpRange,
+ unsigned &msg,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath);
+
static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CastExpr::CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl);
+ CXXBaseSpecifierArray &BasePath);
static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
@@ -153,10 +158,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
case tok::kw_dynamic_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXBaseSpecifierArray BasePath;
if (!TypeDependent)
- CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
+ CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath);
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, BasePath, DestTInfo,
+ OpLoc));
}
case tok::kw_reinterpret_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -164,28 +171,18 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context) CXXReinterpretCastExpr(
DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, CXXBaseSpecifierArray(),
+ DestTInfo, OpLoc));
}
case tok::kw_static_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (!TypeDependent) {
- CXXMethodDecl *Method = 0;
-
- CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method);
-
- if (Method) {
- OwningExprResult CastArg
- = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(),
- Kind, Method, Owned(Ex));
- if (CastArg.isInvalid())
- return ExprError();
-
- Ex = CastArg.takeAs<Expr>();
- }
- }
+ CXXBaseSpecifierArray BasePath;
+ if (!TypeDependent)
+ CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath);
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestTInfo, OpLoc));
+ Kind, Ex, BasePath,
+ DestTInfo, OpLoc));
}
}
@@ -290,7 +287,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
static void
CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange,
- const SourceRange &DestRange, CastExpr::CastKind &Kind) {
+ const SourceRange &DestRange, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType();
DestType = Self.Context.getCanonicalType(DestType);
@@ -384,10 +382,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// C++ 5.2.7p5
// Upcasts are resolved statically.
if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
- Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
- OpRange.getBegin(), OpRange);
+ if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
+ OpRange.getBegin(), OpRange,
+ &BasePath))
+ return;
+
Kind = CastExpr::CK_DerivedToBase;
- // Diagnostic already emitted on error.
return;
}
@@ -448,7 +448,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
void
CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const SourceRange &OpRange, CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CXXBaseSpecifierArray &BasePath) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@@ -462,8 +462,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
- Kind, ConversionDecl)
- != TC_Success && msg != 0)
+ Kind, BasePath) != TC_Success && msg != 0)
Self.Diag(OpRange.getBegin(), msg) << CT_Static
<< SrcExpr->getType() << DestType << OpRange;
}
@@ -475,7 +474,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
QualType DestType, bool CStyle,
const SourceRange &OpRange, unsigned &msg,
CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CXXBaseSpecifierArray &BasePath) {
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@@ -497,7 +496,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// See the function for details.
// DR 427 specifies that this is to be applied before paragraph 2.
tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange,
- msg, Kind);
+ msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -512,7 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
- Kind, ConversionDecl);
+ Kind);
if (tcr != TC_NotApplicable)
return tcr;
@@ -548,7 +547,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast.
// C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance.
tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg,
- Kind);
+ Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -556,7 +555,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// conversion. C++ 5.2.9p9 has additional information.
// DR54's access restrictions apply here also.
tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle,
- OpRange, msg, Kind);
+ OpRange, msg, Kind, BasePath);
if (tcr != TC_NotApplicable)
return tcr;
@@ -630,7 +629,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
TryCastResult
TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
// C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be
// cast to type "reference to cv2 D", where D is a class derived from B,
// if a valid standard conversion from "pointer to D" to "pointer to B"
@@ -656,14 +656,16 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcExpr->getType()),
Self.Context.getCanonicalType(DestPointee), CStyle,
- OpRange, SrcExpr->getType(), DestType, msg, Kind);
+ OpRange, SrcExpr->getType(), DestType, msg, Kind,
+ BasePath);
}
/// Tests whether a conversion according to C++ 5.2.9p8 is valid.
TryCastResult
TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
bool CStyle, const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
// C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class
// type, can be converted to an rvalue of type "pointer to cv2 D", where D
// is a class derived from B, if a valid standard conversion from "pointer
@@ -686,7 +688,8 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType,
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcPointer->getPointeeType()),
Self.Context.getCanonicalType(DestPointer->getPointeeType()),
- CStyle, OpRange, SrcType, DestType, msg, Kind);
+ CStyle, OpRange, SrcType, DestType, msg, Kind,
+ BasePath);
}
/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and
@@ -696,7 +699,7 @@ TryCastResult
TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
bool CStyle, const SourceRange &OpRange, QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
- CastExpr::CastKind &Kind) {
+ CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath) {
// We can only work with complete types. But don't complain if it doesn't work
if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) ||
Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0)))
@@ -707,7 +710,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_NotApplicable;
}
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) {
return TC_NotApplicable;
@@ -787,6 +790,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_Failed;
}
+ Self.BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_BaseToDerived;
return TC_Success;
}
@@ -802,22 +806,25 @@ TryCastResult
TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
- unsigned &msg, CastExpr::CastKind &Kind) {
+ unsigned &msg, CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath) {
const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
if (!DestMemPtr)
return TC_NotApplicable;
bool WasOverloadedFunction = false;
DeclAccessPair FoundOverload;
- if (FunctionDecl *Fn
- = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
- FoundOverload)) {
- CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
- SrcType = Self.Context.getMemberPointerType(Fn->getType(),
- Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
- WasOverloadedFunction = true;
+ if (SrcExpr->getType() == Self.Context.OverloadTy) {
+ if (FunctionDecl *Fn
+ = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
+ FoundOverload)) {
+ CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
+ SrcType = Self.Context.getMemberPointerType(Fn->getType(),
+ Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
+ WasOverloadedFunction = true;
+ }
}
-
+
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (!SrcMemPtr) {
msg = diag::err_bad_static_cast_member_pointer_nonmp;
@@ -832,7 +839,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
// B base of D
QualType SrcClass(SrcMemPtr->getClass(), 0);
QualType DestClass(DestMemPtr->getClass(), 0);
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
return TC_NotApplicable;
@@ -886,6 +893,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
}
}
+ Self.BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_DerivedToBaseMemberPointer;
return TC_Success;
}
@@ -898,8 +906,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
TryCastResult
TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
- CastExpr::CastKind &Kind,
- CXXMethodDecl *&ConversionDecl) {
+ CastExpr::CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_dynamic_cast_incomplete)) {
@@ -907,71 +914,35 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return TC_Failed;
}
}
-
- if (DestType->isReferenceType()) {
- // All reference bindings insert implicit casts above that do the actual
- // casting.
- Kind = CastExpr::CK_NoOp;
-
- // At this point of CheckStaticCast, if the destination is a reference,
- // this has to work. There is no other way that works.
- // On the other hand, if we're checking a C-style cast, we've still got
- // the reinterpret_cast way.
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
- InitializationKind InitKind = InitializationKind::CreateCast(OpRange,
- CStyle);
- InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
- if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle)
- return TC_NotApplicable;
-
- Sema::OwningExprResult Result
- = InitSeq.Perform(Self, Entity, InitKind,
- Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
- if (Result.isInvalid()) {
- msg = 0;
- return TC_Failed;
- }
-
- SrcExpr = Result.takeAs<Expr>();
- return TC_Success;
- }
-
- if (DestType->isRecordType()) {
- if (CXXConstructorDecl *Constructor
- = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1,
- OpRange.getBegin(),
- InitializationKind::CreateDirect(OpRange.getBegin(),
- OpRange.getBegin(),
- OpRange.getEnd()))) {
- ConversionDecl = Constructor;
- Kind = CastExpr::CK_ConstructorConversion;
- return TC_Success;
- }
-
+
+ // At this point of CheckStaticCast, if the destination is a reference,
+ // this has to work. There is no other way that works.
+ // On the other hand, if we're checking a C-style cast, we've still got
+ // the reinterpret_cast way.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
+ InitializationKind InitKind
+ = InitializationKind::CreateCast(/*FIXME:*/OpRange,
+ CStyle);
+ InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+ if (InitSeq.getKind() == InitializationSequence::FailedSequence &&
+ (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
+
+ Sema::OwningExprResult Result
+ = InitSeq.Perform(Self, Entity, InitKind,
+ Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
+ if (Result.isInvalid()) {
+ msg = 0;
+ return TC_Failed;
}
-
- // FIXME: To get a proper error from invalid conversions here, we need to
- // reimplement more of this.
- // FIXME: This does not actually perform the conversion, and thus does not
- // check for ambiguity or access.
- ImplicitConversionSequence ICS =
- Self.TryImplicitConversion(SrcExpr, DestType,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/true,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false,
- /*one of user provided casts*/true);
-
- if (ICS.isBad())
- return TC_NotApplicable;
-
- // The conversion is possible, so commit to it.
- Kind = CastExpr::CK_NoOp;
- msg = 0;
- return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting,
- /*IgnoreBaseAccess*/CStyle) ?
- TC_Failed : TC_Success;
+
+ if (InitSeq.isConstructorInitialization())
+ Kind = CastExpr::CK_ConstructorConversion;
+ else
+ Kind = CastExpr::CK_NoOp;
+
+ SrcExpr = Result.takeAs<Expr>();
+ return TC_Success;
}
/// TryConstCast - See if a const_cast from source to destination is allowed,
@@ -1234,9 +1205,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
return TC_Success;
}
-bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
- CastExpr::CastKind &Kind, bool FunctionalStyle,
- CXXMethodDecl *&ConversionDecl) {
+bool
+Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
+ CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
+ bool FunctionalStyle) {
// This test is outside everything else because it's the only case where
// a non-lvalue-reference target type does not lead to decay.
// C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
@@ -1271,8 +1244,8 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
- tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
- Kind, ConversionDecl);
+ tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind,
+ BasePath);
if (tcr == TC_NotApplicable) {
// ... and finally a reinterpret_cast, ignoring const.
tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg,
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index c90f75eef5fa..c0ec9e997d13 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -24,61 +24,17 @@
using namespace clang;
/// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *
-getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
- QualType T) {
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T) {
if (T.isNull())
return 0;
-
- T = Context.getCanonicalType(T).getUnqualifiedType();
-
- for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
- // If we've hit a namespace or the global scope, then the
- // nested-name-specifier can't refer to the current instantiation.
- if (Ctx->isFileContext())
- return 0;
-
- // Skip non-class contexts.
- CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
- if (!Record)
- continue;
-
- // If this record type is not dependent,
- if (!Record->isDependentType())
- return 0;
-
- // C++ [temp.dep.type]p1:
- //
- // In the definition of a class template, a nested class of a
- // class template, a member of a class template, or a member of a
- // nested class of a class template, a name refers to the current
- // instantiation if it is
- // -- the injected-class-name (9) of the class template or
- // nested class,
- // -- in the definition of a primary class template, the name
- // of the class template followed by the template argument
- // list of the primary template (as described below)
- // enclosed in <>,
- // -- in the definition of a nested class of a class template,
- // the name of the nested class referenced as a member of
- // the current instantiation, or
- // -- in the definition of a partial specialization, the name
- // of the class template followed by the template argument
- // list of the partial specialization enclosed in <>. If
- // the nth template parameter is a parameter pack, the nth
- // template argument is a pack expansion (14.6.3) whose
- // pattern is the name of the parameter pack.
- // (FIXME: parameter packs)
- //
- // All of these options come down to having the
- // nested-name-specifier type that is equivalent to the
- // injected-class-name of one of the types that is currently in
- // our context.
- if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
- return Record;
- }
-
- return 0;
+
+ const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
+ if (isa<RecordType>(Ty))
+ return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+ else if (isa<InjectedClassNameType>(Ty))
+ return cast<InjectedClassNameType>(Ty)->getDecl();
+ else
+ return 0;
}
/// \brief Compute the DeclContext that is associated with the given type.
@@ -92,7 +48,7 @@ DeclContext *Sema::computeDeclContext(QualType T) {
if (const TagType *Tag = T->getAs<TagType>())
return Tag->getDecl();
- return ::getCurrentInstantiationOf(Context, CurContext, T);
+ return ::getCurrentInstantiationOf(T);
}
/// \brief Compute the DeclContext that is associated with the given
@@ -218,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
return 0;
QualType T = QualType(NNS->getAsType(), 0);
- return ::getCurrentInstantiationOf(Context, CurContext, T);
+ return ::getCurrentInstantiationOf(T);
}
/// \brief Require that the context specified by SS be complete.
@@ -230,11 +186,10 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
/// that is currently being defined. Or, if we have a type that names
/// a class template specialization that is not a complete type, we
/// will attempt to instantiate that class template.
-bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
- if (!SS.isSet() || SS.isInvalid())
- return false;
+bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
+ DeclContext *DC) {
+ assert(DC != 0 && "given null context");
- 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())
@@ -247,10 +202,13 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
return false;
// The type must be complete.
- return RequireCompleteType(SS.getRange().getBegin(),
- Context.getTypeDeclType(Tag),
- PDiag(diag::err_incomplete_nested_name_spec)
- << SS.getRange());
+ if (RequireCompleteType(SS.getRange().getBegin(),
+ Context.getTypeDeclType(Tag),
+ PDiag(diag::err_incomplete_nested_name_spec)
+ << SS.getRange())) {
+ SS.setScopeRep(0); // Mark the ScopeSpec invalid.
+ return true;
+ }
}
return false;
@@ -322,7 +280,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
return 0;
}
-bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
SourceLocation IdLoc,
IdentifierInfo &II,
TypeTy *ObjectTypePtr) {
@@ -353,7 +311,8 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
// nested-name-specifier.
// The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(SS, LookupCtx))
return false;
LookupQualifiedName(Found, LookupCtx);
@@ -384,7 +343,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
/// scope if it *knows* that the result is correct. It should not return in a
/// dependent context, for example.
Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -423,7 +382,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// nested-name-specifier.
// The declaration context must be complete.
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(SS, LookupCtx))
return 0;
LookupQualifiedName(Found, LookupCtx);
@@ -480,7 +440,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
- if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) &&
+ if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext,
+ CTC_NoKeywords) &&
Found.isSingleResult() &&
isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
if (LookupCtx)
@@ -593,7 +554,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
/// Returns a CXXScopeTy* object representing the C++ scope.
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdLoc,
SourceLocation CCLoc,
IdentifierInfo &II,
@@ -611,7 +572,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
/// conservatively correct to always return false from this method.
///
/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier.
-bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS,
+bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
IdentifierInfo &II, TypeTy *ObjectType,
bool EnteringContext) {
return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(),
@@ -676,7 +637,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
/// looked up in the declarator-id's scope, until the declarator is parsed and
/// ActOnCXXExitDeclaratorScope is called.
/// The 'SS' should be a non-empty valid CXXScopeSpec.
-bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
if (SS.isInvalid()) return true;
@@ -686,10 +647,15 @@ bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
// Before we enter a declarator's context, we need to make sure that
// it is a complete declaration context.
- if (!DC->isDependentContext() && RequireCompleteDeclContext(SS))
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC))
return true;
EnterDeclaratorContext(S, DC);
+
+ // Rebuild the nested name specifier for the new scope.
+ if (DC->isDependentContext())
+ RebuildNestedNameSpecifierInCurrentInstantiation(SS);
+
return false;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f2520fc5eb7f..7029711d446c 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -26,6 +26,7 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "clang/Basic/TargetBuiltins.h"
#include <limits>
using namespace clang;
@@ -155,14 +156,18 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return ExprError();
break;
case Builtin::BI__builtin_return_address:
- case Builtin::BI__builtin_frame_address:
- if (SemaBuiltinStackAddress(TheCall))
+ case Builtin::BI__builtin_frame_address: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 0, Result))
return ExprError();
break;
- case Builtin::BI__builtin_eh_return_data_regno:
- if (SemaBuiltinEHReturnDataRegNo(TheCall))
+ }
+ case Builtin::BI__builtin_eh_return_data_regno: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 0, Result))
return ExprError();
break;
+ }
case Builtin::BI__builtin_shufflevector:
return SemaBuiltinShuffleVector(TheCall);
// TheCall will be freed by the smart pointer here, but that's fine, since
@@ -196,6 +201,15 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinAtomicOverloaded(TheCall))
return ExprError();
break;
+
+ // Target specific builtins start here.
+ case X86::BI__builtin_ia32_palignr128:
+ case X86::BI__builtin_ia32_palignr: {
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, 2, Result))
+ return ExprError();
+ break;
+ }
}
return move(TheCallResult);
@@ -270,8 +284,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Ensure that we have at least one argument to do type inference from.
if (TheCall->getNumArgs() < 1)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << TheCall->getCallee()->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
// Inspect the first argument of the atomic builtin. This should always be
// a pointer type, whose element is an integral scalar or pointer type.
@@ -367,8 +383,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Now that we know how many fixed arguments we expect, first check that we
// have at least that many.
if (TheCall->getNumArgs() < 1+NumFixed)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 << TheCall->getCallee()->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 1+NumFixed << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
// Get the decl for the concrete builtin from this, we can tell what the
@@ -405,9 +423,8 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// GCC does an implicit conversion to the pointer or integer ValType. This
// can fail in some cases (1i -> int**), check for this error case now.
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- CXXMethodDecl *ConversionDecl = 0;
- if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind,
- ConversionDecl))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath))
return true;
// Okay, we have something that *can* be converted to the right type. Check
@@ -416,7 +433,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false);
+ ImpCastExprToType(Arg, ValType, Kind);
TheCall->setArg(i+1, Arg);
}
@@ -476,15 +493,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
if (TheCall->getNumArgs() > 2) {
Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << Fn->getSourceRange()
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs()
+ << Fn->getSourceRange()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
return true;
}
if (TheCall->getNumArgs() < 2) {
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs();
}
// Determine whether the current function is variadic or not.
@@ -492,15 +511,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
bool isVariadic;
if (CurBlock)
isVariadic = CurBlock->isVariadic;
- else if (getCurFunctionDecl()) {
- if (FunctionProtoType* FTP =
- dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType()))
- isVariadic = FTP->isVariadic();
- else
- isVariadic = false;
- } else {
+ else if (FunctionDecl *FD = getCurFunctionDecl())
+ isVariadic = FD->isVariadic();
+ else
isVariadic = getCurMethodDecl()->isVariadic();
- }
if (!isVariadic) {
Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
@@ -538,11 +552,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 2)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ << 0 << 2 << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > 2)
return Diag(TheCall->getArg(2)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/
+ << 0 /*function call*/ << 2 << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(2)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
@@ -580,11 +594,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (TheCall->getNumArgs() < NumArgs)
return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/;
+ << 0 << NumArgs << TheCall->getNumArgs()/*function call*/;
if (TheCall->getNumArgs() > NumArgs)
return Diag(TheCall->getArg(NumArgs)->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/
+ << 0 /*function call*/ << NumArgs << TheCall->getNumArgs()
<< SourceRange(TheCall->getArg(NumArgs)->getLocStart(),
(*(TheCall->arg_end()-1))->getLocEnd());
@@ -602,25 +616,14 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
return false;
}
-bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) {
- // The signature for these builtins is exact; the only thing we need
- // to check is that the argument is a constant.
- SourceLocation Loc;
- if (!TheCall->getArg(0)->isTypeDependent() &&
- !TheCall->getArg(0)->isValueDependent() &&
- !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc))
- return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange();
-
- return false;
-}
-
/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
// This is declared to take (...), so we have to check everything.
Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < 3)
return ExprError(Diag(TheCall->getLocEnd(),
- diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << 3 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
unsigned numElements = std::numeric_limits<unsigned>::max();
if (!TheCall->getArg(0)->isTypeDependent() &&
@@ -647,10 +650,14 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
if (TheCall->getNumArgs() < numElements+2)
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ << 0 /*function call*/
+ << numElements+2 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
return ExprError(Diag(TheCall->getLocEnd(),
diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << TheCall->getSourceRange());
+ << 0 /*function call*/
+ << numElements+2 << TheCall->getNumArgs()
+ << TheCall->getSourceRange());
}
}
@@ -659,11 +666,9 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getArg(i)->isValueDependent())
continue;
- llvm::APSInt Result(32);
- if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
- return ExprError(Diag(TheCall->getLocStart(),
- diag::err_shufflevector_nonconstant_argument)
- << TheCall->getArg(i)->getSourceRange());
+ llvm::APSInt Result;
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return ExprError();
if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2)
return ExprError(Diag(TheCall->getLocStart(),
@@ -691,30 +696,19 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs > 3)
- return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << TheCall->getSourceRange();
+ return Diag(TheCall->getLocEnd(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << 3 << NumArgs
+ << TheCall->getSourceRange();
// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
for (unsigned i = 1; i != NumArgs; ++i) {
Expr *Arg = TheCall->getArg(i);
- if (Arg->isTypeDependent())
- continue;
-
- if (!Arg->getType()->isIntegralType())
- return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type)
- << Arg->getSourceRange();
-
- ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast);
- TheCall->setArg(i, Arg);
-
- if (Arg->isValueDependent())
- continue;
-
+
llvm::APSInt Result;
- if (!Arg->isIntegerConstantExpr(Result, Context))
- return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
+ if (SemaBuiltinConstantArg(TheCall, i, Result))
+ return true;
// FIXME: gcc issues a warning and rewrites these to 0. These
// seems especially odd for the third argument since the default
@@ -733,42 +727,35 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
return false;
}
-/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the
-/// operand must be an integer constant.
-bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) {
- llvm::APSInt Result;
- if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context))
- return Diag(TheCall->getLocStart(), diag::err_expr_not_ice)
- << TheCall->getArg(0)->getSourceRange();
-
+/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr
+/// TheCall is a constant expression.
+bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
+ llvm::APSInt &Result) {
+ Expr *Arg = TheCall->getArg(ArgNum);
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+
+ if (Arg->isTypeDependent() || Arg->isValueDependent()) return false;
+
+ if (!Arg->isIntegerConstantExpr(Result, Context))
+ return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type)
+ << FDecl->getDeclName() << Arg->getSourceRange();
+
return false;
}
-
/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
/// int type). This simply type checks that type is one of the defined
/// constants (0-3).
// For compatability check 0-3, llvm only handles 0 and 2.
bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
- Expr *Arg = TheCall->getArg(1);
- if (Arg->isTypeDependent())
- return false;
-
- QualType ArgType = Arg->getType();
- const BuiltinType *BT = ArgType->getAs<BuiltinType>();
- llvm::APSInt Result(32);
- if (!BT || BT->getKind() != BuiltinType::Int)
- return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
-
- if (Arg->isValueDependent())
- return false;
-
- if (!Arg->isIntegerConstantExpr(Result, Context)) {
- return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument)
- << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
- }
+ llvm::APSInt Result;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ return true;
+ Expr *Arg = TheCall->getArg(1);
if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
<< "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
@@ -781,11 +768,13 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
/// This checks that val is a constant 1.
bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(1);
- if (Arg->isTypeDependent() || Arg->isValueDependent())
- return false;
+ llvm::APSInt Result;
- llvm::APSInt Result(32);
- if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1)
+ // TODO: This is less than ideal. Overload this to take a value.
+ if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ return true;
+
+ if (Result != 1)
return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val)
<< SourceRange(Arg->getLocStart(), Arg->getLocEnd());
@@ -1885,6 +1874,17 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// Left shift gets black-listed based on a judgement call.
case BinaryOperator::Shl:
+ // ...except that we want to treat '1 << (blah)' as logically
+ // positive. It's an important idiom.
+ if (IntegerLiteral *I
+ = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
+ if (I->getValue() == 1) {
+ IntRange R = IntRange::forType(C, E->getType());
+ return IntRange(R.Width, /*NonNegative*/ true);
+ }
+ }
+ // fallthrough
+
case BinaryOperator::ShlAssign:
return IntRange::forType(C, E->getType());
@@ -1945,6 +1945,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return GetExprRange(C, UO->getSubExpr(), MaxWidth);
}
}
+
+ if (dyn_cast<OffsetOfExpr>(E)) {
+ IntRange::forType(C, E->getType());
+ }
FieldDecl *BitField = E->getBitField();
if (BitField) {
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index df14aa7fc5a4..c075d161704e 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -13,12 +13,14 @@
#include "Sema.h"
#include "Lookup.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include <list>
#include <map>
#include <vector>
@@ -413,6 +415,9 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
return false;
}
+
+ if (Filter == &ResultBuilder::IsNestedNameSpecifier)
+ AsNestedNameSpecifier = true;
// ... then it must be interesting!
return true;
@@ -502,7 +507,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
for (; I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if (I->first->hasTagIdentifierNamespace() &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -627,7 +632,7 @@ void ResultBuilder::ExitScope() {
bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
return true;
@@ -639,7 +644,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
- IDNS |= Decl::IDNS_Tag;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace;
return (ND->getIdentifierNamespace() & IDNS) &&
!isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND);
@@ -882,7 +887,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddPlaceholderChunk("identifier");
Pattern->AddChunk(CodeCompletionString::CK_Equal);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// Using directives
@@ -892,7 +896,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("namespace");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// asm(string-literal)
@@ -901,7 +904,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("string-literal");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// Explicit template instantiation
@@ -909,7 +911,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTypedTextChunk("template");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("declaration");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -926,7 +927,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTypedTextChunk("using");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("qualified-id");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// using typename qualified-id; (only in a dependent context)
@@ -937,7 +937,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("typename");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("qualified-id");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1090,7 +1089,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("expression");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// for ( for-init-statement ; condition ; expression ) { statements }
@@ -1116,7 +1114,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// continue ;
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("continue");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1124,7 +1121,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
// break ;
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("break");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -1145,7 +1141,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
}
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// goto identifier ;
@@ -1153,7 +1148,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTypedTextChunk("goto");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// Using directives
@@ -1163,7 +1157,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
Pattern->AddTextChunk("namespace");
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
}
@@ -2075,10 +2068,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
Results.ExitScope();
- // Add macros
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
-
// Hand off the results found for code completion.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2108,13 +2097,17 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
return;
}
- ResultBuilder Results(*this, Filter);
- Results.allowNestedNameSpecifiers();
+ ResultBuilder Results(*this);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
+
+ // First pass: look for tags.
+ Results.setFilter(Filter);
LookupVisibleDecls(S, LookupTagName, Consumer);
+
+ // Second pass: look for nested name specifiers.
+ Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+ LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer);
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2192,7 +2185,7 @@ void Sema::CodeCompleteCase(Scope *S) {
CurContext, 0, false);
}
Results.ExitScope();
-
+
if (CodeCompleter->includeMacros())
AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2258,7 +2251,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// FIXME: access?
AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none),
Args, NumArgs, CandidateSet,
- false, false, /*PartialOverloading*/ true);
+ false, /*PartialOverloading*/true);
}
}
@@ -2276,14 +2269,13 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
}
- if (Results.empty())
- CodeCompleteOrdinaryName(S, CCC_Expression);
- else
+ CodeCompleteOrdinaryName(S, CCC_Expression);
+ if (!Results.empty())
CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
}
-void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
+void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.getScopeRep() || !CodeCompleter)
return;
@@ -2294,7 +2286,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
// Try to instantiate any non-dependent declaration contexts before
// we look in them.
- if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS))
+ if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
return;
ResultBuilder Results(*this);
@@ -2307,8 +2299,6 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
if (!Results.empty() && NNS->isDependent())
Results.AddResult("template");
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2329,8 +2319,6 @@ void Sema::CodeCompleteUsing(Scope *S) {
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2345,8 +2333,6 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2381,8 +2367,6 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
Results.ExitScope();
}
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2394,8 +2378,6 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2422,8 +2404,6 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
AddTypeSpecifierResults(getLangOptions(), Results);
Results.ExitScope();
- if (CodeCompleter->includeMacros())
- AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2484,7 +2464,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class));
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// @interface name
@@ -2593,7 +2572,6 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw));
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
- Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Pattern));
// @synchronized ( expression ) { statements }
@@ -2908,70 +2886,198 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl,
HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName,
- SourceLocation FNameLoc,
+/// \brief When we have an expression with type "id", we may assume
+/// that it has some more-specific class type based on knowledge of
+/// common uses of Objective-C. This routine returns that class type,
+/// or NULL if no better result could be determined.
+static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
+ ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E);
+ if (!Msg)
+ return 0;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel.isNull())
+ return 0;
+
+ IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0);
+ if (!Id)
+ return 0;
+
+ ObjCMethodDecl *Method = Msg->getMethodDecl();
+ if (!Method)
+ return 0;
+
+ // Determine the class that we're sending the message to.
+ ObjCInterfaceDecl *IFace = 0;
+ switch (Msg->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ if (const ObjCInterfaceType *IFaceType
+ = Msg->getClassReceiver()->getAs<ObjCInterfaceType>())
+ IFace = IFaceType->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance: {
+ QualType T = Msg->getInstanceReceiver()->getType();
+ if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>())
+ IFace = Ptr->getInterfaceDecl();
+ break;
+ }
+
+ case ObjCMessageExpr::SuperInstance:
+ case ObjCMessageExpr::SuperClass:
+ break;
+ }
+
+ if (!IFace)
+ return 0;
+
+ ObjCInterfaceDecl *Super = IFace->getSuperClass();
+ if (Method->isInstanceMethod())
+ return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+ .Case("retain", IFace)
+ .Case("autorelease", IFace)
+ .Case("copy", IFace)
+ .Case("copyWithZone", IFace)
+ .Case("mutableCopy", IFace)
+ .Case("mutableCopyWithZone", IFace)
+ .Case("awakeFromCoder", IFace)
+ .Case("replacementObjectFromCoder", IFace)
+ .Case("class", IFace)
+ .Case("classForCoder", IFace)
+ .Case("superclass", Super)
+ .Default(0);
+
+ return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
+ .Case("new", IFace)
+ .Case("alloc", IFace)
+ .Case("allocWithZone", IFace)
+ .Case("class", IFace)
+ .Case("superclass", Super)
+ .Default(0);
+}
+
+void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
IdentifierInfo **SelIdents,
unsigned NumSelIdents) {
- typedef CodeCompleteConsumer::Result Result;
ObjCInterfaceDecl *CDecl = 0;
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
+ // Figure out which interface we're in.
+ CDecl = CurMethod->getClassInterface();
+ if (!CDecl)
+ return;
+
+ // Find the superclass of this class.
+ CDecl = CDecl->getSuperClass();
+ if (!CDecl)
+ return;
- if (FName->isStr("super")) {
- // We're sending a message to "super".
- if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
- // Figure out which interface we're in.
- CDecl = CurMethod->getClassInterface();
- if (!CDecl)
- return;
-
- // Find the superclass of this class.
- CDecl = CDecl->getSuperClass();
- if (!CDecl)
- return;
+ if (CurMethod->isInstanceMethod()) {
+ // We are inside an instance method, which means that the message
+ // send [super ...] is actually calling an instance method on the
+ // current object. Build the super expression and handle this like
+ // an instance method.
+ QualType SuperTy = Context.getObjCInterfaceType(CDecl);
+ SuperTy = Context.getObjCObjectPointerType(SuperTy);
+ OwningExprResult Super
+ = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy));
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
+ SelIdents, NumSelIdents);
+ }
- if (CurMethod->isInstanceMethod()) {
- // We are inside an instance method, which means that the message
- // send [super ...] is actually calling an instance method on the
- // current object. Build the super expression and handle this like
- // an instance method.
- QualType SuperTy = Context.getObjCInterfaceType(CDecl);
- SuperTy = Context.getObjCObjectPointerType(SuperTy);
- OwningExprResult Super
- = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy));
- return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
- SelIdents, NumSelIdents);
- }
+ // Fall through to send to the superclass in CDecl.
+ } else {
+ // "super" may be the name of a type or variable. Figure out which
+ // it is.
+ IdentifierInfo *Super = &Context.Idents.get("super");
+ NamedDecl *ND = LookupSingleName(S, Super, SuperLoc,
+ LookupOrdinaryName);
+ if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
+ // "super" names an interface. Use it.
+ } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) {
+ if (const ObjCInterfaceType *Iface
+ = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>())
+ CDecl = Iface->getDecl();
+ } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) {
+ // "super" names an unresolved type; we can't be more specific.
+ } else {
+ // Assume that "super" names some kind of value and parse that way.
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Super, SuperLoc);
+ OwningExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false);
+ return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(),
+ SelIdents, NumSelIdents);
+ }
- // Okay, we're calling a factory method in our superclass.
- }
+ // Fall through
}
+ TypeTy *Receiver = 0;
+ if (CDecl)
+ Receiver = Context.getObjCInterfaceType(CDecl).getAsOpaquePtr();
+ return CodeCompleteObjCClassMessage(S, Receiver, SelIdents,
+ NumSelIdents);
+}
+
+void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver,
+ IdentifierInfo **SelIdents,
+ unsigned NumSelIdents) {
+ typedef CodeCompleteConsumer::Result Result;
+ ObjCInterfaceDecl *CDecl = 0;
+
// If the given name refers to an interface type, retrieve the
// corresponding declaration.
- if (!CDecl)
- if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) {
- QualType T = GetTypeFromParser(Ty, 0);
- if (!T.isNull())
- if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
- CDecl = Interface->getDecl();
- }
-
- if (!CDecl && FName->isStr("super")) {
- // "super" may be the name of a variable, in which case we are
- // probably calling an instance method.
- CXXScopeSpec SS;
- UnqualifiedId id;
- id.setIdentifier(FName, FNameLoc);
- OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false);
- return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(),
- SelIdents, NumSelIdents);
+ if (Receiver) {
+ QualType T = GetTypeFromParser(Receiver, 0);
+ if (!T.isNull())
+ if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>())
+ CDecl = Interface->getDecl();
}
// Add all of the factory methods in this Objective-C class, its protocols,
// superclasses, categories, implementation, etc.
ResultBuilder Results(*this);
Results.EnterNewScope();
- AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
- Results);
+
+ if (CDecl)
+ AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext,
+ Results);
+ else {
+ // We're messaging "id" as a type; provide all class/factory methods.
+
+ // If we have an external source, load the entire class method
+ // pool from the PCH file.
+ if (ExternalSource) {
+ for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N;
+ ++I) {
+ Selector Sel = ExternalSource->GetSelector(I);
+ if (Sel.isNull() || FactoryMethodPool.count(Sel) ||
+ InstanceMethodPool.count(Sel))
+ continue;
+
+ ReadMethodPool(Sel, /*isInstance=*/false);
+ }
+ }
+
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ M = FactoryMethodPool.begin(),
+ MEnd = FactoryMethodPool.end();
+ M != MEnd;
+ ++M) {
+ for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method;
+ MethList = MethList->Next) {
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
+ NumSelIdents))
+ continue;
+
+ Result R(MethList->Method, 0);
+ R.StartParameter = NumSelIdents;
+ R.AllParametersAreInformative = false;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+ }
+
Results.ExitScope();
// This also suppresses remaining diagnostics.
@@ -2990,15 +3096,17 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
DefaultFunctionArrayLvalueConversion(RecExpr);
QualType ReceiverType = RecExpr->getType();
- if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) {
- // FIXME: We're messaging 'id'. Do we actually want to look up every method
- // in the universe?
- return;
- }
-
// Build the set of methods we can see.
ResultBuilder Results(*this);
Results.EnterNewScope();
+
+ // If we're messaging an expression with type "id" or "Class", check
+ // whether we know something special about the receiver that allows
+ // us to assume a more-specific receiver type.
+ if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType())
+ if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr))
+ ReceiverType = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(IFace));
// Handle messages to Class. This really isn't a message to an instance
// method, so we treat it the same way we would treat a message send to a
@@ -3035,7 +3143,44 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver,
AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext,
Results);
}
-
+ // Handle messages to "id".
+ else if (ReceiverType->isObjCIdType()) {
+ // We're messaging "id", so provide all instance methods we know
+ // about as code-completion results.
+
+ // If we have an external source, load the entire class method
+ // pool from the PCH file.
+ if (ExternalSource) {
+ for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N;
+ ++I) {
+ Selector Sel = ExternalSource->GetSelector(I);
+ if (Sel.isNull() || InstanceMethodPool.count(Sel) ||
+ FactoryMethodPool.count(Sel))
+ continue;
+
+ ReadMethodPool(Sel, /*isInstance=*/true);
+ }
+ }
+
+ for (llvm::DenseMap<Selector, ObjCMethodList>::iterator
+ M = InstanceMethodPool.begin(),
+ MEnd = InstanceMethodPool.end();
+ M != MEnd;
+ ++M) {
+ for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method;
+ MethList = MethList->Next) {
+ if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents,
+ NumSelIdents))
+ continue;
+
+ Result R(MethList->Method, 0);
+ R.StartParameter = NumSelIdents;
+ R.AllParametersAreInformative = false;
+ Results.MaybeAddResult(R, CurContext);
+ }
+ }
+ }
+
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -3076,7 +3221,8 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols,
// Tell the result set to ignore all of the protocols we have
// already seen.
for (unsigned I = 0; I != NumProtocols; ++I)
- if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first))
+ if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first,
+ Protocols[I].second))
Results.Ignore(Protocol);
// Add all protocols.
@@ -3140,13 +3286,14 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) {
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) {
+void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
ResultBuilder Results(*this);
Results.EnterNewScope();
// Make sure that we ignore the class we're currently defining.
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
if (CurClass && isa<ObjCInterfaceDecl>(CurClass))
Results.Ignore(CurClass);
@@ -3171,7 +3318,8 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) {
}
void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
typedef CodeCompleteConsumer::Result Result;
ResultBuilder Results(*this);
@@ -3180,7 +3328,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
// interface.
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
Category = Category->getNextClassCategory())
@@ -3201,17 +3349,18 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
}
void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
- IdentifierInfo *ClassName) {
+ IdentifierInfo *ClassName,
+ SourceLocation ClassNameLoc) {
typedef CodeCompleteConsumer::Result Result;
// Find the corresponding interface. If we couldn't find the interface, the
// program itself is ill-formed. However, we'll try to be helpful still by
// providing the list of all of the categories we know about.
NamedDecl *CurClass
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass);
if (!Class)
- return CodeCompleteObjCInterfaceCategory(S, ClassName);
+ return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc);
ResultBuilder Results(*this);
@@ -3306,3 +3455,224 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
+
+typedef llvm::DenseMap<Selector, ObjCMethodDecl *> KnownMethodsMap;
+
+/// \brief Find all of the methods that reside in the given container
+/// (and its superclasses, protocols, etc.) that meet the given
+/// criteria. Insert those methods into the map of known methods,
+/// indexed by selector so they can be easily found.
+static void FindImplementableMethods(ASTContext &Context,
+ ObjCContainerDecl *Container,
+ bool WantInstanceMethods,
+ QualType ReturnType,
+ bool IsInImplementation,
+ KnownMethodsMap &KnownMethods) {
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = IFace->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+
+ // If we're not in the implementation of a class, also visit the
+ // superclass.
+ if (!IsInImplementation && IFace->getSuperClass())
+ FindImplementableMethods(Context, IFace->getSuperClass(),
+ WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+
+ // Add methods from any class extensions (but not from categories;
+ // those should go into category implementations).
+ for (ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat;
+ Cat = Cat->getNextClassCategory()) {
+ if (!Cat->IsClassExtension())
+ continue;
+
+ FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Category->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
+ // Recurse into protocols.
+ const ObjCList<ObjCProtocolDecl> &Protocols
+ = Protocol->getReferencedProtocols();
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end();
+ I != E; ++I)
+ FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType,
+ IsInImplementation, KnownMethods);
+ }
+
+ // Add methods in this container. This operation occurs last because
+ // we want the methods from this container to override any methods
+ // we've previously seen with the same selector.
+ for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
+ MEnd = Container->meth_end();
+ M != MEnd; ++M) {
+ if ((*M)->isInstanceMethod() == WantInstanceMethods) {
+ if (!ReturnType.isNull() &&
+ !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType()))
+ continue;
+
+ KnownMethods[(*M)->getSelector()] = *M;
+ }
+ }
+}
+
+void Sema::CodeCompleteObjCMethodDecl(Scope *S,
+ bool IsInstanceMethod,
+ TypeTy *ReturnTy,
+ DeclPtrTy IDecl) {
+ // Determine the return type of the method we're declaring, if
+ // provided.
+ QualType ReturnType = GetTypeFromParser(ReturnTy);
+
+ // Determine where we should start searching for methods, and where we
+ ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0;
+ bool IsInImplementation = false;
+ if (Decl *D = IDecl.getAs<Decl>()) {
+ if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) {
+ SearchDecl = Impl->getClassInterface();
+ CurrentDecl = Impl;
+ IsInImplementation = true;
+ } else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(D)) {
+ SearchDecl = CatImpl->getCategoryDecl();
+ CurrentDecl = CatImpl;
+ IsInImplementation = true;
+ } else {
+ SearchDecl = dyn_cast<ObjCContainerDecl>(D);
+ CurrentDecl = SearchDecl;
+ }
+ }
+
+ if (!SearchDecl && S) {
+ if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) {
+ SearchDecl = dyn_cast<ObjCContainerDecl>(DC);
+ CurrentDecl = SearchDecl;
+ }
+ }
+
+ if (!SearchDecl || !CurrentDecl) {
+ HandleCodeCompleteResults(this, CodeCompleter, 0, 0);
+ return;
+ }
+
+ // Find all of the methods that we could declare/implement here.
+ KnownMethodsMap KnownMethods;
+ FindImplementableMethods(Context, SearchDecl, IsInstanceMethod,
+ ReturnType, IsInImplementation, KnownMethods);
+
+ // Erase any methods that have already been declared or
+ // implemented here.
+ for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(),
+ MEnd = CurrentDecl->meth_end();
+ M != MEnd; ++M) {
+ if ((*M)->isInstanceMethod() != IsInstanceMethod)
+ continue;
+
+ KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector());
+ if (Pos != KnownMethods.end())
+ KnownMethods.erase(Pos);
+ }
+
+ // Add declarations or definitions for each of the known methods.
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ PrintingPolicy Policy(Context.PrintingPolicy);
+ Policy.AnonymousTagLocations = false;
+ for (KnownMethodsMap::iterator M = KnownMethods.begin(),
+ MEnd = KnownMethods.end();
+ M != MEnd; ++M) {
+ ObjCMethodDecl *Method = M->second;
+ CodeCompletionString *Pattern = new CodeCompletionString;
+
+ // If the result type was not already provided, add it to the
+ // pattern as (type).
+ if (ReturnType.isNull()) {
+ std::string TypeStr;
+ Method->getResultType().getAsStringInternal(TypeStr, Policy);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddTextChunk(TypeStr);
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ }
+
+ Selector Sel = Method->getSelector();
+
+ // Add the first part of the selector to the pattern.
+ Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
+
+ // Add parameters to the pattern.
+ unsigned I = 0;
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; (void)++P, ++I) {
+ // Add the part of the selector name.
+ if (I == 0)
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ else if (I < Sel.getNumArgs()) {
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(1)->getName());
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ } else
+ break;
+
+ // Add the parameter type.
+ std::string TypeStr;
+ (*P)->getOriginalType().getAsStringInternal(TypeStr, Policy);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddTextChunk(TypeStr);
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+
+ if (IdentifierInfo *Id = (*P)->getIdentifier())
+ Pattern->AddTextChunk(Id->getName());
+ }
+
+ if (Method->isVariadic()) {
+ if (Method->param_size() > 0)
+ Pattern->AddChunk(CodeCompletionString::CK_Comma);
+ Pattern->AddTextChunk("...");
+ }
+
+ if (IsInImplementation) {
+ // We will be defining the method here, so add a compound statement.
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ if (!Method->getResultType()->isVoidType()) {
+ // If the result type is not void, add a return clause.
+ Pattern->AddTextChunk("return");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ } else
+ Pattern->AddPlaceholderChunk("statements");
+
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ }
+
+ Results.AddResult(Result(Pattern));
+ }
+
+ Results.ExitScope();
+
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 541c27169a7c..0e839a9d2d69 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -61,7 +61,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
/// If name lookup results in an ambiguity, this routine will complain
/// and then return NULL.
Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec *SS,
+ Scope *S, CXXScopeSpec *SS,
bool isClassName,
TypeTy *ObjectTypePtr) {
// Determine where we will perform name lookup.
@@ -70,7 +70,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
if (ObjectType->isRecordType())
LookupCtx = computeDeclContext(ObjectType);
- } else if (SS && SS->isSet()) {
+ } else if (SS && SS->isNotEmpty()) {
LookupCtx = computeDeclContext(*SS, false);
if (!LookupCtx) {
@@ -89,16 +89,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type, so build a
// DependentNameType node to describe the type.
- // FIXME: Record somewhere that this DependentNameType node has no "typename"
- // keyword associated with it.
- return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ return CheckTypenameType(ETK_None,
+ (NestedNameSpecifier *)SS->getScopeRep(),
II, SS->getRange()).getAsOpaquePtr();
}
return 0;
}
- if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
+ if (!LookupCtx->isDependentContext() &&
+ RequireCompleteDeclContext(*SS, LookupCtx))
return 0;
}
@@ -236,7 +236,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
SourceLocation IILoc,
Scope *S,
- const CXXScopeSpec *SS,
+ CXXScopeSpec *SS,
TypeTy *&SuggestedType) {
// We don't have anything to suggest (yet).
SuggestedType = 0;
@@ -246,31 +246,53 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName,
NotForRedeclaration);
- // FIXME: It would be nice if we could correct for typos in built-in
- // names, such as "itn" for "int".
-
- if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) {
- NamedDecl *Result = Lookup.getAsSingle<NamedDecl>();
- if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
- !Result->isInvalidDecl()) {
- // We found a similarly-named type or interface; suggest that.
- if (!SS || !SS->isSet())
- Diag(IILoc, diag::err_unknown_typename_suggest)
- << &II << Lookup.getLookupName()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
- else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_unknown_nested_typename_suggest)
- << &II << DC << Lookup.getLookupName() << SS->getRange()
- << FixItHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
- else
- llvm_unreachable("could not have corrected a typo here");
+ if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) {
+ if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) {
+ if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
+ !Result->isInvalidDecl()) {
+ // We found a similarly-named type or interface; suggest that.
+ if (!SS || !SS->isSet())
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << Lookup.getLookupName()
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+ << &II << DC << Lookup.getLookupName() << SS->getRange()
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
+ else
+ llvm_unreachable("could not have corrected a typo here");
- Diag(Result->getLocation(), diag::note_previous_decl)
- << Result->getDeclName();
-
- SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << Result->getDeclName();
+
+ SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
+ return true;
+ }
+ } else if (Lookup.empty()) {
+ // We corrected to a keyword.
+ // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+ Diag(IILoc, diag::err_unknown_typename_suggest)
+ << &II << Corrected;
+ return true;
+ }
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ // See if II is a class template that the user forgot to pass arguments to.
+ UnqualifiedId Name;
+ Name.setIdentifier(&II, IILoc);
+ CXXScopeSpec EmptySS;
+ TemplateTy TemplateResult;
+ if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult)
+ == TNK_Type_template) {
+ TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
+ Diag(IILoc, diag::err_template_missing_args) << TplName;
+ if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) {
+ Diag(TplDecl->getLocation(), diag::note_template_decl_here)
+ << TplDecl->getTemplateParameters()->getSourceRange();
+ }
return true;
}
}
@@ -522,6 +544,11 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
}
+ // If we failed to complete the type for some reason, don't
+ // diagnose the variable.
+ if (Ty->isIncompleteType())
+ return false;
+
if (const TagType *TT = Ty->getAs<TagType>()) {
const TagDecl *Tag = TT->getDecl();
if (Tag->hasAttr<UnusedAttr>())
@@ -558,40 +585,48 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Diagnose unused variables in this scope.
if (ShouldDiagnoseUnusedDecl(D) &&
- S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
- Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
-
+ S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) {
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
+ Diag(D->getLocation(), diag::warn_unused_exception_param)
+ << D->getDeclName();
+ else
+ Diag(D->getLocation(), diag::warn_unused_variable)
+ << D->getDeclName();
+ }
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
}
-/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
-/// return 0 if one not found.
+/// \brief Look for an Objective-C class in the translation unit.
///
-/// \param Id the name of the Objective-C class we're looking for. If
+/// \param Id The name of the Objective-C class we're looking for. If
/// typo-correction fixes this name, the Id will be updated
/// to the fixed name.
///
-/// \param RecoverLoc if provided, this routine will attempt to
-/// recover from a typo in the name of an existing Objective-C class
-/// and, if successful, will return the lookup that results from
-/// typo-correction.
+/// \param IdLoc The location of the name in the translation unit.
+///
+/// \param TypoCorrection If true, this routine will attempt typo correction
+/// if there is no class with the given name.
+///
+/// \returns The declaration of the named Objective-C class, or NULL if the
+/// class could not be found.
ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
- SourceLocation RecoverLoc) {
+ SourceLocation IdLoc,
+ bool TypoCorrection) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
- NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+ NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
- if (!IDecl && !RecoverLoc.isInvalid()) {
+ if (!IDecl && TypoCorrection) {
// Perform typo correction at the given location, but only if we
// find an Objective-C class name.
- LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0) &&
+ LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
- Diag(RecoverLoc, diag::err_undef_interface_suggest)
+ Diag(IdLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
- << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString());
+ << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< IDecl->getDeclName();
@@ -639,7 +674,8 @@ void Sema::InitBuiltinVaListType() {
return;
IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
- NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName);
+ NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(),
+ LookupOrdinaryName, ForRedeclaration);
TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl);
Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
}
@@ -691,7 +727,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
FunctionDecl *New = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
Loc, II, R, /*TInfo=*/0,
- FunctionDecl::Extern, false,
+ FunctionDecl::Extern,
+ FunctionDecl::None, false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -702,7 +739,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i)
Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
- VarDecl::None, 0));
+ VarDecl::None, VarDecl::None, 0));
New->setParams(Params.data(), Params.size());
}
@@ -897,13 +934,12 @@ struct GNUCompatibleParamWarning {
/// getSpecialMember - get the special member enum for a method.
-static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
- const CXXMethodDecl *MD) {
+Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
- if (Ctor->isDefaultConstructor())
- return Sema::CXXDefaultConstructor;
if (Ctor->isCopyConstructor())
return Sema::CXXCopyConstructor;
+
+ return Sema::CXXConstructor;
}
if (isa<CXXDestructorDecl>(MD))
@@ -1040,10 +1076,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
}
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod) {
- if (!NewMethod->getFriendObjectKind() &&
- NewMethod->getLexicalDeclContext()->isRecord()) {
+ // Preserve triviality.
+ NewMethod->setTrivial(OldMethod->isTrivial());
+
+ bool isFriend = NewMethod->getFriendObjectKind();
+
+ if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
// is a static member function declaration.
@@ -1069,14 +1109,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Diag(New->getLocation(), NewDiag);
Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
- } else {
- if (OldMethod->isImplicit()) {
+
+ // Complain if this is an explicit declaration of a special
+ // member that was initially declared implicitly.
+ //
+ // As an exception, it's okay to befriend such methods in order
+ // to permit the implicit constructor/destructor/operator calls.
+ } else if (OldMethod->isImplicit()) {
+ if (isFriend) {
+ NewMethod->setImplicit();
+ } else {
Diag(NewMethod->getLocation(),
diag::err_definition_of_implicitly_declared_member)
- << New << getSpecialMember(Context, OldMethod);
-
- Diag(OldMethod->getLocation(),
- diag::note_previous_implicit_declaration);
+ << New << getSpecialMember(OldMethod);
return true;
}
}
@@ -1125,7 +1170,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
SourceLocation(), 0,
*ParamType, /*TInfo=*/0,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None,
+ 0);
Param->setImplicit();
Params.push_back(Param);
}
@@ -1441,7 +1487,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
Record->getDeclContext()->isRecord())
return BuildAnonymousStructOrUnion(S, DS, Record);
- Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
}
@@ -1463,9 +1509,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
return DeclPtrTy::make(Tag);
}
- Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators)
+ Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
<< DS.getSourceRange();
- return DeclPtrTy();
}
return DeclPtrTy::make(Tag);
@@ -1558,6 +1603,64 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
return Invalid;
}
+/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to
+/// a VarDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to VarDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
+static VarDecl::StorageClass
+StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
+ switch (StorageClassSpec) {
+ case DeclSpec::SCS_unspecified: return VarDecl::None;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? VarDecl::None : VarDecl::Extern;
+ case DeclSpec::SCS_static: return VarDecl::Static;
+ case DeclSpec::SCS_auto: return VarDecl::Auto;
+ case DeclSpec::SCS_register: return VarDecl::Register;
+ case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern;
+ // Illegal SCSs map to None: error reporting is up to the caller.
+ case DeclSpec::SCS_mutable: // Fall through.
+ case DeclSpec::SCS_typedef: return VarDecl::None;
+ }
+ llvm_unreachable("unknown storage class specifier");
+}
+
+/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
+/// a FunctionDecl::StorageClass. Any error reporting is up to the caller:
+/// illegal input values are mapped to FunctionDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
+static FunctionDecl::StorageClass
+StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
+ switch (StorageClassSpec) {
+ case DeclSpec::SCS_unspecified: return FunctionDecl::None;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? FunctionDecl::None : FunctionDecl::Extern;
+ case DeclSpec::SCS_static: return FunctionDecl::Static;
+ case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern;
+ // Illegal SCSs map to None: error reporting is up to the caller.
+ case DeclSpec::SCS_auto: // Fall through.
+ case DeclSpec::SCS_mutable: // Fall through.
+ case DeclSpec::SCS_register: // Fall through.
+ case DeclSpec::SCS_typedef: return FunctionDecl::None;
+ }
+ llvm_unreachable("unknown storage class specifier");
+}
+
/// ActOnAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a GNU C extension; anonymous structures
@@ -1675,32 +1778,31 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
TInfo,
/*BitWidth=*/0, /*Mutable=*/false);
Anon->setAccess(AS_public);
- if (getLangOptions().CPlusPlus)
+ if (getLangOptions().CPlusPlus) {
FieldCollector->Add(cast<FieldDecl>(Anon));
+ if (!cast<CXXRecordDecl>(Record)->isEmpty())
+ cast<CXXRecordDecl>(OwningClass)->setEmpty(false);
+ }
} else {
- VarDecl::StorageClass SC;
- switch (DS.getStorageClassSpec()) {
- default: assert(0 && "Unknown storage class!");
- case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
- case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
- case DeclSpec::SCS_static: SC = VarDecl::Static; break;
- case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
- case DeclSpec::SCS_register: SC = VarDecl::Register; break;
- case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
- case DeclSpec::SCS_mutable:
+ DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
+ assert(SCSpec != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class VarDecl.");
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
Diag(Record->getLocation(), diag::err_mutable_nonmember);
Invalid = true;
SC = VarDecl::None;
- break;
}
+ SCSpec = DS.getStorageClassSpecAsWritten();
+ VarDecl::StorageClass SCAsWritten
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- TInfo,
- SC);
+ TInfo, SC, SCAsWritten);
}
Anon->setImplicit();
@@ -1708,7 +1810,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// context. We'll be referencing this object when we refer to one of
// its members.
Owner->addDecl(Anon);
-
+
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
@@ -1829,6 +1931,71 @@ static bool isNearlyMatchingFunction(ASTContext &Context,
return true;
}
+/// NeedsRebuildingInCurrentInstantiation - Checks whether the given
+/// declarator needs to be rebuilt in the current instantiation.
+/// Any bits of declarator which appear before the name are valid for
+/// consideration here. That's specifically the type in the decl spec
+/// and the base type in any member-pointer chunks.
+static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
+ DeclarationName Name) {
+ // The types we specifically need to rebuild are:
+ // - typenames, typeofs, and decltypes
+ // - types which will become injected class names
+ // Of course, we also need to rebuild any type referencing such a
+ // type. It's safest to just say "dependent", but we call out a
+ // few cases here.
+
+ DeclSpec &DS = D.getMutableDeclSpec();
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_typename:
+ case DeclSpec::TST_typeofType:
+ case DeclSpec::TST_typeofExpr:
+ case DeclSpec::TST_decltype: {
+ // Grab the type from the parser.
+ TypeSourceInfo *TSI = 0;
+ QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI);
+ if (T.isNull() || !T->isDependentType()) break;
+
+ // Make sure there's a type source info. This isn't really much
+ // of a waste; most dependent types should have type source info
+ // attached already.
+ if (!TSI)
+ TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc());
+
+ // Rebuild the type in the current instantiation.
+ TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name);
+ if (!TSI) return true;
+
+ // Store the new type back in the decl spec.
+ QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI);
+ DS.UpdateTypeRep(LocType.getAsOpaquePtr());
+ break;
+ }
+
+ default:
+ // Nothing to do for these decl specs.
+ break;
+ }
+
+ // It doesn't matter what order we do this in.
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
+ DeclaratorChunk &Chunk = D.getTypeObject(I);
+
+ // The only type information in the declarator which can come
+ // before the declaration name is the base type of a member
+ // pointer.
+ if (Chunk.Kind != DeclaratorChunk::MemberPointer)
+ continue;
+
+ // Rebuild the scope specifier in-place.
+ CXXScopeSpec &SS = Chunk.Mem.Scope();
+ if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS))
+ return true;
+ }
+
+ return false;
+}
+
Sema::DeclPtrTy
Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
@@ -1851,35 +2018,47 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
- // If this is an out-of-line definition of a member of a class template
- // or class template partial specialization, we may need to rebuild the
- // type specifier in the declarator. See RebuildTypeInCurrentInstantiation()
- // for more information.
- // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can
- // handle expressions properly.
- DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec());
- if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() &&
- isDependentScopeSpecifier(D.getCXXScopeSpec()) &&
- (DS.getTypeSpecType() == DeclSpec::TST_typename ||
- DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
- DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
- DS.getTypeSpecType() == DeclSpec::TST_decltype)) {
- if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) {
- // FIXME: Preserve type source info.
- QualType T = GetTypeFromParser(DS.getTypeRep());
-
- DeclContext *SavedContext = CurContext;
- CurContext = DC;
- T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name);
- CurContext = SavedContext;
-
- if (T.isNull())
- return DeclPtrTy();
- DS.UpdateTypeRep(T.getAsOpaquePtr());
+ DeclContext *DC = CurContext;
+ if (D.getCXXScopeSpec().isInvalid())
+ D.setInvalidType();
+ else if (D.getCXXScopeSpec().isSet()) {
+ bool EnteringContext = !D.getDeclSpec().isFriendSpecified();
+ DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext);
+ if (!DC) {
+ // If we could not compute the declaration context, it's because the
+ // declaration context is dependent but does not refer to a class,
+ // class template, or class template partial specialization. Complain
+ // and return early, to avoid the coming semantic disaster.
+ Diag(D.getIdentifierLoc(),
+ diag::err_template_qualified_declarator_no_match)
+ << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getRange();
+ return DeclPtrTy();
+ }
+
+ bool IsDependentContext = DC->isDependentContext();
+
+ if (!IsDependentContext &&
+ RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
+ 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();
+ }
+
+ // Check whether we need to rebuild the type of the given
+ // declaration in the current instantiation.
+ if (EnteringContext && IsDependentContext &&
+ TemplateParamLists.size() != 0) {
+ ContextRAII SavedContext(*this, DC);
+ if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name))
+ D.setInvalidType();
}
}
- DeclContext *DC;
NamedDecl *New;
TypeSourceInfo *TInfo = 0;
@@ -1889,10 +2068,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
ForRedeclaration);
// See if this is a redefinition of a variable in the same scope.
- if (D.getCXXScopeSpec().isInvalid()) {
- DC = CurContext;
- D.setInvalidType();
- } else if (!D.getCXXScopeSpec().isSet()) {
+ if (!D.getCXXScopeSpec().isSet()) {
bool IsLinkageLookup = false;
// If the declaration we're planning to build will be a function
@@ -1913,34 +2089,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
if (IsLinkageLookup)
Previous.clear(LookupRedeclarationWithLinkage);
- DC = CurContext;
LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup);
} else { // Something like "int foo::x;"
- DC = computeDeclContext(D.getCXXScopeSpec(), true);
-
- if (!DC) {
- // If we could not compute the declaration context, it's because the
- // declaration context is dependent but does not refer to a class,
- // class template, or class template partial specialization. Complain
- // and return early, to avoid the coming semantic disaster.
- Diag(D.getIdentifierLoc(),
- diag::err_template_qualified_declarator_no_match)
- << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
- << D.getCXXScopeSpec().getRange();
- return DeclPtrTy();
- }
-
- 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);
// Don't consider using declarations as previous declarations for
@@ -2298,24 +2448,20 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (getLangOptions().CPlusPlus)
CheckExtraCXXDefaultArguments(D);
- VarDecl *NewVD;
- VarDecl::StorageClass SC;
- switch (D.getDeclSpec().getStorageClassSpec()) {
- default: assert(0 && "Unknown storage class!");
- case DeclSpec::SCS_unspecified: SC = VarDecl::None; break;
- case DeclSpec::SCS_extern: SC = VarDecl::Extern; break;
- case DeclSpec::SCS_static: SC = VarDecl::Static; break;
- case DeclSpec::SCS_auto: SC = VarDecl::Auto; break;
- case DeclSpec::SCS_register: SC = VarDecl::Register; break;
- case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
- case DeclSpec::SCS_mutable:
+ DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
+ assert(SCSpec != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class VarDecl.");
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
D.setInvalidType();
SC = VarDecl::None;
- break;
}
+ SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+ VarDecl::StorageClass SCAsWritten
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -2367,6 +2513,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
TemplateParamLists.size(),
+ /*never a friend*/ false,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// There is no such thing as a variable template.
@@ -2388,8 +2535,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
- NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
- II, R, TInfo, SC);
+ VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
+ II, R, TInfo, SC, SCAsWritten);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -2767,6 +2914,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+ DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
+ FunctionDecl::StorageClass SCAsWritten
+ = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC);
+
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
@@ -2827,7 +2978,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
- Name, R, TInfo, SC, isInline,
+ Name, R, TInfo, SC, SCAsWritten, isInline,
/*hasPrototype=*/true);
D.setInvalidType();
}
@@ -2876,7 +3027,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// This is a C++ method declaration.
NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R, TInfo,
- isStatic, isInline);
+ isStatic, SCAsWritten, isInline);
isVirtualOkay = !isStatic;
} else {
@@ -2893,7 +3044,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD = FunctionDecl::Create(Context, DC,
D.getIdentifierLoc(),
- Name, R, TInfo, SC, isInline, HasPrototype);
+ Name, R, TInfo, SC, SCAsWritten, isInline,
+ HasPrototype);
}
if (D.isInvalidType())
@@ -2917,6 +3069,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.getCXXScopeSpec(),
(TemplateParameterList**)TemplateParamLists.get(),
TemplateParamLists.size(),
+ isFriend,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -2935,7 +3088,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
- // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+ // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend && isFunctionTemplateSpecialization) {
// We want to remove the "template<>", found here.
SourceRange RemoveRange = TemplateParams->getSourceRange();
@@ -3015,10 +3168,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (FunctionTemplate) {
FunctionTemplate->setObjectOfFriendDecl(false);
FunctionTemplate->setAccess(AS_public);
- } else {
- NewFD->setObjectOfFriendDecl(false);
}
-
+ NewFD->setObjectOfFriendDecl(false);
NewFD->setAccess(AS_public);
}
@@ -3072,6 +3223,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
assert(Param->getDeclContext() != NewFD && "Was set before ?");
Param->setDeclContext(NewFD);
Params.push_back(Param);
+
+ if (Param->isInvalidDecl())
+ NewFD->setInvalidDecl();
}
}
@@ -3091,6 +3245,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
SourceLocation(), 0,
*AI, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
Param->setImplicit();
Params.push_back(Param);
@@ -3139,24 +3294,39 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
}
+ } else if (isFriend && isFunctionTemplateSpecialization) {
+ // This combination is only possible in a recovery case; the user
+ // wrote something like:
+ // template <> friend void foo(int);
+ // which we're recovering from as if the user had written:
+ // friend void foo<>(int);
+ // Go ahead and fake up a template id.
+ HasExplicitTemplateArgs = true;
+ TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
+ TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
+ }
+
+ // If it's a friend (and only if it's a friend), it's possible
+ // that either the specialized function type or the specialized
+ // template is dependent, and therefore matching will fail. In
+ // this case, don't check the specialization yet.
+ if (isFunctionTemplateSpecialization && isFriend &&
+ (NewFD->getType()->isDependentType() || DC->isDependentContext())) {
+ assert(HasExplicitTemplateArgs &&
+ "friend function specialization without template args");
+ if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,
+ Previous))
+ NewFD->setInvalidDecl();
+ } else if (isFunctionTemplateSpecialization) {
+ if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ Previous))
+ NewFD->setInvalidDecl();
+ } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
+ if (CheckMemberSpecialization(NewFD, Previous))
+ NewFD->setInvalidDecl();
}
- if (isFunctionTemplateSpecialization) {
- if (isFriend && NewFD->getType()->isDependentType()) {
- // FIXME: When we see a friend of a function template
- // specialization with a dependent type, we can't match it now;
- // for now, we just drop it, until we have a reasonable way to
- // represent the parsed-but-not-matched friend function template
- // specialization in the AST.
- return 0;
- } else if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
- Previous))
- NewFD->setInvalidDecl();
- } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
- CheckMemberSpecialization(NewFD, Previous))
- NewFD->setInvalidDecl();
-
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
@@ -3166,17 +3336,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ NamedDecl *PrincipalDecl = (FunctionTemplate
+ ? cast<NamedDecl>(FunctionTemplate)
+ : NewFD);
+
if (isFriend && Redeclaration) {
- AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess();
- if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(true);
- FunctionTemplate->setAccess(Access);
- } else {
- NewFD->setObjectOfFriendDecl(true);
- }
+ AccessSpecifier Access = AS_public;
+ if (!NewFD->isInvalidDecl())
+ Access = NewFD->getPreviousDeclaration()->getAccess();
+
NewFD->setAccess(Access);
+ if (FunctionTemplate) FunctionTemplate->setAccess(Access);
+
+ PrincipalDecl->setObjectOfFriendDecl(true);
}
+ if (NewFD->isOverloadedOperator() && !DC->isRecord() &&
+ PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ PrincipalDecl->setNonMemberOperator();
+
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
@@ -3286,7 +3464,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// FIXME: Also include static functions declared but not defined.
if (!NewFD->isInvalidDecl() && IsFunctionDefinition
&& !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage
- && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>())
+ && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>()
+ && !NewFD->hasAttr<ConstructorAttr>()
+ && !NewFD->hasAttr<DestructorAttr>())
UnusedStaticFuncs.push_back(NewFD);
return NewFD;
@@ -3761,7 +3941,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
}
}
} else if (VDecl->isFileVarDecl()) {
- if (VDecl->getStorageClass() == VarDecl::Extern)
+ if (VDecl->getStorageClass() == VarDecl::Extern &&
+ (!getLangOptions().CPlusPlus ||
+ !Context.getBaseElementType(VDecl->getType()).isConstQualified()))
Diag(VDecl->getLocation(), diag::warn_extern_init);
if (!VDecl->isInvalidDecl()) {
InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1);
@@ -4030,8 +4212,10 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
VarDecl::StorageClass StorageClass = VarDecl::None;
+ VarDecl::StorageClass StorageClassAsWritten = VarDecl::None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
StorageClass = VarDecl::Register;
+ StorageClassAsWritten = VarDecl::Register;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -4084,55 +4268,24 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
}
}
- // Parameters can not be abstract class types.
- // For record types, this is done by the AbstractClassUsageDiagnoser once
- // the class has been completely parsed.
- if (!CurContext->isRecord() &&
- RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
- diag::err_abstract_type_in_decl,
- AbstractParamType))
- D.setInvalidType(true);
-
- QualType T = adjustParameterType(parmDeclType);
-
// Temporarily put parameter variables in the translation unit, not
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
- DeclContext *DC = Context.getTranslationUnitDecl();
-
- ParmVarDecl *New
- = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
- T, TInfo, StorageClass, 0);
+ ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
+ TInfo, parmDeclType, II,
+ D.getIdentifierLoc(),
+ StorageClass, StorageClassAsWritten);
if (D.isInvalidType())
- New->setInvalidDecl();
-
- // Parameter declarators cannot be interface types. All ObjC objects are
- // passed by reference.
- if (T->isObjCInterfaceType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
- New->setInvalidDecl();
- }
-
+ New->setInvalidDecl();
+
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
New->setInvalidDecl();
}
-
- // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
- // duration shall not be qualified by an address-space qualifier."
- // Since all parameters have automatic store duration, they can not have
- // an address space.
- if (T.getAddressSpace() != 0) {
- Diag(D.getIdentifierLoc(),
- diag::err_arg_with_address_space);
- New->setInvalidDecl();
- }
-
-
+
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (II)
@@ -4146,9 +4299,43 @@ 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);
+ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
+ TypeSourceInfo *TSInfo, QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ VarDecl::StorageClass StorageClass,
+ VarDecl::StorageClass StorageClassAsWritten) {
+ ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
+ adjustParameterType(T), TSInfo,
+ StorageClass, StorageClassAsWritten,
+ 0);
+
+ // Parameters can not be abstract class types.
+ // For record types, this is done by the AbstractClassUsageDiagnoser once
+ // the class has been completely parsed.
+ if (!CurContext->isRecord() &&
+ RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl,
+ AbstractParamType))
+ New->setInvalidDecl();
+
+ // Parameter declarators cannot be interface types. All ObjC objects are
+ // passed by reference.
+ if (T->isObjCInterfaceType()) {
+ Diag(NameLoc,
+ diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
+ New->setInvalidDecl();
+ }
+
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
+
+ return New;
}
void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
@@ -4692,7 +4879,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParameterLists,
@@ -4711,6 +4898,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
+ TUK == TUK_Friend,
isExplicitSpecialization)) {
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
@@ -4761,12 +4949,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
IsDependent = true;
return DeclPtrTy();
}
+ } else {
+ DC = computeDeclContext(SS, true);
+ if (!DC) {
+ Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
+ << SS.getRange();
+ return DeclPtrTy();
+ }
}
- if (RequireCompleteDeclContext(SS))
+ if (RequireCompleteDeclContext(SS, DC))
return DeclPtrTy::make((Decl *)0);
- DC = computeDeclContext(SS, true);
SearchDC = DC;
// Look-up name inside 'foo::'.
LookupQualifiedName(Previous, DC);
@@ -4891,17 +5085,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// class or function, the friend class or function is a member of
// the innermost enclosing namespace.
SearchDC = SearchDC->getEnclosingNamespaceContext();
-
- // Look up through our scopes until we find one with an entity which
- // matches our declaration context.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
- S = S->getParent();
- assert(S && "No enclosing scope matching the enclosing namespace.");
- }
}
- // In C++, look for a shadow friend decl.
+ // In C++, we need to do a redeclaration lookup to properly
+ // diagnose some problems.
if (getLangOptions().CPlusPlus) {
Previous.setRedeclarationKind(ForRedeclaration);
LookupQualifiedName(Previous, SearchDC);
@@ -4909,8 +5096,32 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
if (!Previous.empty()) {
- assert(Previous.isSingleResult());
- NamedDecl *PrevDecl = Previous.getFoundDecl();
+ NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+
+ // It's okay to have a tag decl in the same scope as a typedef
+ // which hides a tag decl in the same scope. Finding this
+ // insanity with a redeclaration lookup can only actually happen
+ // in C++.
+ //
+ // This is also okay for elaborated-type-specifiers, which is
+ // technically forbidden by the current standard but which is
+ // okay according to the likely resolution of an open issue;
+ // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
+ if (getLangOptions().CPlusPlus) {
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) {
+ if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ TagDecl *Tag = TT->getDecl();
+ if (Tag->getDeclName() == Name &&
+ Tag->getDeclContext()->getLookupContext()
+ ->Equals(TD->getDeclContext()->getLookupContext())) {
+ PrevDecl = Tag;
+ Previous.clear();
+ Previous.addDecl(Tag);
+ }
+ }
+ }
+ }
+
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
// If this is a use of a previous tag, or if the tag is already declared
// in the same scope (so that the definition/declaration completes or
@@ -5002,23 +5213,61 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If we get here, we're going to create a new Decl. If PrevDecl
// is non-NULL, it's a definition of the tag declared by
// PrevDecl. If it's NULL, we have a new definition.
+
+
+ // Otherwise, PrevDecl is not a tag, but was found with tag
+ // lookup. This is only actually possible in C++, where a few
+ // things like templates still live in the tag namespace.
} else {
- // PrevDecl is a namespace, template, or anything else
- // that lives in the IDNS_Tag identifier namespace.
- if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S)) {
- // The tag name clashes with a namespace name, issue an error and
- // recover by making this tag be anonymous.
+ assert(getLangOptions().CPlusPlus);
+
+ // Use a better diagnostic if an elaborated-type-specifier
+ // found the wrong kind of type on the first
+ // (non-redeclaration) lookup.
+ if ((TUK == TUK_Reference || TUK == TUK_Friend) &&
+ !Previous.isForRedeclaration()) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_declared_at);
+ Invalid = true;
+
+ // Otherwise, only diagnose if the declaration is in scope.
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+ // do nothing
+
+ // Diagnose implicit declarations introduced by elaborated types.
+ } else if (TUK == TUK_Reference || TUK == TUK_Friend) {
+ unsigned Kind = 0;
+ if (isa<TypedefDecl>(PrevDecl)) Kind = 1;
+ else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2;
+ Diag(NameLoc, diag::err_tag_reference_conflict) << Kind;
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise it's a declaration. Call out a particularly common
+ // case here.
+ } else if (isa<TypedefDecl>(PrevDecl)) {
+ Diag(NameLoc, diag::err_tag_definition_of_typedef)
+ << Name
+ << cast<TypedefDecl>(PrevDecl)->getUnderlyingType();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ Invalid = true;
+
+ // Otherwise, diagnose.
+ } else {
+ // The tag name clashes with something else in the target scope,
+ // issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Name = 0;
- Previous.clear();
Invalid = true;
- } else {
- // The existing declaration isn't relevant to us; we're in a
- // new scope, so clear out the previous declaration.
- Previous.clear();
}
+
+ // The existing declaration isn't relevant to us; we're in a
+ // new scope, so clear out the previous declaration.
+ Previous.clear();
}
}
@@ -5089,28 +5338,6 @@ CreateNewDecl:
New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8));
}
- if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
- // C++ [dcl.typedef]p3:
- // [...] Similarly, in a given scope, a class or enumeration
- // shall not be declared with the same name as a typedef-name
- // that is declared in that scope and refers to a type other
- // than the class or enumeration itself.
- LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName,
- ForRedeclaration);
- LookupName(Lookup, S);
- TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>();
- NamedDecl *PrevTypedefNamed = PrevTypedef;
- if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) &&
- Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
- Context.getCanonicalType(Context.getTypeDeclType(New))) {
- Diag(Loc, diag::err_tag_definition_of_typedef)
- << Context.getTypeDeclType(New)
- << PrevTypedef->getUnderlyingType();
- Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
- Invalid = true;
- }
- }
-
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
@@ -5175,7 +5402,7 @@ CreateNewDecl:
void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
-
+
// Enter the tag context.
PushDeclContext(S, Tag);
}
@@ -5321,11 +5548,23 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
if (!FieldTy->isDependentType()) {
uint64_t TypeSize = Context.getTypeSize(FieldTy);
if (Value.getZExtValue() > TypeSize) {
+ if (!getLangOptions().CPlusPlus) {
+ if (FieldName)
+ return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
+ << FieldName << (unsigned)Value.getZExtValue()
+ << (unsigned)TypeSize;
+
+ return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size)
+ << (unsigned)Value.getZExtValue() << (unsigned)TypeSize;
+ }
+
if (FieldName)
- return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
- << FieldName << (unsigned)TypeSize;
- return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size)
- << (unsigned)TypeSize;
+ Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size)
+ << FieldName << (unsigned)Value.getZExtValue()
+ << (unsigned)TypeSize;
+ else
+ Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size)
+ << (unsigned)Value.getZExtValue() << (unsigned)TypeSize;
}
}
@@ -5363,7 +5602,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
@@ -5506,21 +5745,17 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// because otherwise we'll never get complaints about
// copy constructors.
- const CXXSpecialMember invalid = (CXXSpecialMember) -1;
-
- CXXSpecialMember member;
+ CXXSpecialMember member = CXXInvalid;
if (!RDecl->hasTrivialCopyConstructor())
member = CXXCopyConstructor;
else if (!RDecl->hasTrivialConstructor())
- member = CXXDefaultConstructor;
+ member = CXXConstructor;
else if (!RDecl->hasTrivialCopyAssignment())
member = CXXCopyAssignment;
else if (!RDecl->hasTrivialDestructor())
member = CXXDestructor;
- else
- member = invalid;
- if (member != invalid) {
+ if (member != CXXInvalid) {
Diag(Loc, diag::err_illegal_union_member) << Name << member;
DiagnoseNontrivial(RT, member);
NewFD->setInvalidDecl();
@@ -5562,14 +5797,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
// Check whether the member was user-declared.
switch (member) {
- case CXXDefaultConstructor:
+ case CXXInvalid:
+ break;
+
+ case CXXConstructor:
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){
const FunctionDecl *body = 0;
ci->getBody(body);
- if (!body ||
- !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) {
+ if (!body || !cast<CXXConstructorDecl>(body)->isImplicitlyDefined()) {
SourceLocation CtorLoc = ci->getLocation();
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
@@ -5637,7 +5874,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
bool (CXXRecordDecl::*hasTrivial)() const;
switch (member) {
- case CXXDefaultConstructor:
+ case CXXConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
case CXXCopyConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
@@ -5727,10 +5964,13 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// validate II.
}
-
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_ivar_reference_type);
+ D.setInvalidType();
+ }
// C99 6.7.2.1p8: A member of a structure or union may have any type other
// than a variably modified type.
- if (T->isVariablyModifiedType()) {
+ else if (T->isVariablyModifiedType()) {
Diag(Loc, diag::err_typecheck_ivar_variable_size);
D.setInvalidType();
}
@@ -5747,8 +5987,16 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
// Case of ivar declared in an implementation. Context is that of its class.
EnclosingContext = IMPDecl->getClassInterface();
assert(EnclosingContext && "Implementation has no class interface!");
- } else
+ } else {
+ if (ObjCCategoryDecl *CDecl =
+ dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
+ if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) {
+ Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
+ return DeclPtrTy();
+ }
+ }
EnclosingContext = EnclosingDecl;
+ }
// Construct the decl.
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context,
@@ -5756,7 +6004,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S,
TInfo, ac, (Expr *)BitfieldWidth);
if (II) {
- NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName,
+ NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName,
ForRedeclaration);
if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S)
&& !isa<TagDecl>(PrevDecl)) {
@@ -5926,16 +6174,14 @@ void Sema::ActOnFields(Scope* S,
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
} else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
- if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension())
- Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
- else {
- // FIXME. Class extension does not have a LocEnd field.
- // CDecl->setLocEnd(RBrac);
- // Add ivar's to class extension's DeclContext.
- for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
- ClsFields[i]->setLexicalDeclContext(CDecl);
- CDecl->addDecl(ClsFields[i]);
- }
+ // case of ivars in class extension; all other cases have been
+ // reported as errors elsewhere.
+ // FIXME. Class extension does not have a LocEnd field.
+ // CDecl->setLocEnd(RBrac);
+ // Add ivar's to class extension's DeclContext.
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ ClsFields[i]->setLexicalDeclContext(CDecl);
+ CDecl->addDecl(ClsFields[i]);
}
}
}
@@ -5950,7 +6196,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
llvm::APSInt &Value,
QualType T) {
assert(T->isIntegralType() && "Integral type required!");
- unsigned BitWidth = Context.getTypeSize(T);
+ unsigned BitWidth = Context.getIntWidth(T);
if (Value.isUnsigned() || Value.isNonNegative())
return Value.getActiveBits() < BitWidth;
@@ -6083,7 +6329,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// value, then increment.
EnumVal = LastEnumConst->getInitVal();
EnumVal.setIsSigned(EltTy->isSignedIntegerType());
- EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
++EnumVal;
// If we're not in C++, diagnose the overflow of enumerator values,
@@ -6105,7 +6351,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (!EltTy->isDependentType()) {
// Make the enumerator value match the signedness and size of the
// enumerator's type.
- EnumVal.zextOrTrunc(Context.getTypeSize(EltTy));
+ EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
EnumVal.setIsSigned(EltTy->isSignedIntegerType());
}
@@ -6131,7 +6377,7 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// Verify that there isn't already something declared with this name in this
// scope.
- NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName,
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName,
ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
@@ -6357,6 +6603,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy,
CastExpr::CK_IntegralCast,
ECD->getInitExpr(),
+ CXXBaseSpecifierArray(),
/*isLvalue=*/false));
if (getLangOptions().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
@@ -6383,7 +6630,7 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
- Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
PrevDecl->addAttr(::new (Context) WeakAttr());
@@ -6399,7 +6646,8 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc,
SourceLocation AliasNameLoc) {
- Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc,
+ LookupOrdinaryName);
WeakInfo W = WeakInfo(Name, NameLoc);
if (PrevDecl) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index cc24735c4adb..90aa9c1c130d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -118,7 +118,7 @@ static bool isFunctionOrMethodVariadic(const Decl *d) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d))
- return BD->IsVariadic();
+ return BD->isVariadic();
else {
return cast<ObjCMethodDecl>(d)->isVariadic();
}
@@ -490,16 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // NOTE: We don't add the attribute to a FunctionDecl because the noreturn
- // trait will be part of the function's type.
-
- // 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());
+ /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */
+ assert(Attr.isInvalid() == false);
+ d->addAttr(::new (S.Context) NoReturnAttr());
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
@@ -900,9 +893,12 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// We ignore weak import on properties and methods
return;
} else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
+ // Don't issue the warning for darwin as target; yet, ignore the attribute.
+ if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin ||
+ !isa<ObjCInterfaceDecl>(D))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << 2 /*variable and function*/;
+ return;
}
// Merge should handle any subsequent violations.
@@ -1022,8 +1018,11 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
// Look up the function
+ // FIXME: Lookup probably isn't looking in the right place
+ // FIXME: The lookup source location should be in the attribute, not the
+ // start of the attribute.
NamedDecl *CleanupDecl
- = S.LookupSingleName(S.TUScope, Attr.getParameterName(),
+ = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(),
Sema::LookupOrdinaryName);
if (!CleanupDecl) {
S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) <<
@@ -1643,6 +1642,27 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) GNUInlineAttr());
}
+static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // Diagnostic is emitted elsewhere: here we store the (valid) Attr
+ // in the Decl node for syntactic reasoning, e.g., pretty-printing.
+ assert(Attr.isInvalid() == false);
+
+ switch (Attr.getKind()) {
+ case AttributeList::AT_fastcall:
+ d->addAttr(::new (S.Context) FastCallAttr());
+ return;
+ case AttributeList::AT_stdcall:
+ d->addAttr(::new (S.Context) StdCallAttr());
+ return;
+ case AttributeList::AT_cdecl:
+ d->addAttr(::new (S.Context) CDeclAttr());
+ return;
+ default:
+ llvm_unreachable("unexpected attribute kind");
+ return;
+ }
+}
+
static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 1) {
@@ -1843,6 +1863,9 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
static void ProcessDeclAttribute(Scope *scope, Decl *D,
const AttributeList &Attr, Sema &S) {
+ if (Attr.isInvalid())
+ return;
+
if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr))
// FIXME: Try to deal with other __declspec attributes!
return;
@@ -1927,7 +1950,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
- // These are all treated as type attributes.
+ HandleCallConvAttr(D, Attr, S);
break;
default:
// Ask target about the attribute.
@@ -1972,7 +1995,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) {
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
- VD->getStorageClass());
+ VD->getStorageClass(),
+ VD->getStorageClassAsWritten());
if (VD->getQualifier()) {
VarDecl *NewVD = cast<VarDecl>(NewD);
NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange());
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 39e3739878f9..6259b85af480 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -16,12 +16,13 @@
#include "Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Template.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
<< OldParam->getDefaultArgRange();
Invalid = true;
} else if (OldParam->hasDefaultArg()) {
- // Merge the old default argument into the new parameter
+ // Merge the old default argument into the new parameter.
+ // It's important to use getInit() here; getDefaultArg()
+ // strips off any top-level CXXExprWithTemporaries.
NewParam->setHasInheritedDefaultArg();
if (OldParam->hasUninstantiatedDefaultArg())
NewParam->setUninstantiatedDefaultArg(
OldParam->getUninstantiatedDefaultArg());
else
- NewParam->setDefaultArg(OldParam->getDefaultArg());
+ NewParam->setDefaultArg(OldParam->getInit());
} else if (NewParam->hasDefaultArg()) {
if (New->getDescribedFunctionTemplate()) {
// Paragraph 4, quoted above, only applies to non-template functions.
@@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
return DerivedRD->isDerivedFrom(BaseRD, Paths);
}
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+ CXXBaseSpecifierArray &BasePathArray) {
+ assert(BasePathArray.empty() && "Base path array must be empty!");
+ assert(Paths.isRecordingPaths() && "Must record paths!");
+
+ const CXXBasePath &Path = Paths.front();
+
+ // We first go backward and check if we have a virtual base.
+ // FIXME: It would be better if CXXBasePath had the base specifier for
+ // the nearest virtual base.
+ unsigned Start = 0;
+ for (unsigned I = Path.size(); I != 0; --I) {
+ if (Path[I - 1].Base->isVirtual()) {
+ Start = I - 1;
+ break;
+ }
+ }
+
+ // Now add all bases.
+ for (unsigned I = Start, E = Path.size(); I != E; ++I)
+ BasePathArray.push_back(Path[I].Base);
+}
+
/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
/// conversion (where Derived and Base are class types) is
/// well-formed, meaning that the conversion is unambiguous (and
@@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
- DeclarationName Name) {
+ DeclarationName Name,
+ CXXBaseSpecifierArray *BasePath) {
// First, determine whether the path from Derived to Base is
// ambiguous. This is slightly more expensive than checking whether
// the Derived to Base conversion exists, because here we need to
@@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (!InaccessibleBaseID)
- return false;
-
- // Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
- InaccessibleBaseID)) {
- case AR_accessible: return false;
- case AR_inaccessible: return true;
- case AR_dependent: return false;
- case AR_delayed: return false;
+ if (InaccessibleBaseID) {
+ // Check that the base class can be accessed.
+ switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+ InaccessibleBaseID)) {
+ case AR_inaccessible:
+ return true;
+ case AR_accessible:
+ case AR_dependent:
+ case AR_delayed:
+ break;
+ }
}
+
+ // Build a base path if necessary.
+ if (BasePath)
+ BuildBasePathArray(Paths, *BasePath);
+ return false;
}
// We know that the derived-to-base conversion is ambiguous, and
@@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
SourceLocation Loc, SourceRange Range,
+ CXXBaseSpecifierArray *BasePath,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
IgnoreAccess ? 0
: diag::err_upcast_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
- Loc, Range, DeclarationName());
+ Loc, Range, DeclarationName(),
+ BasePath);
}
@@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef,
Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *MemberOrBase,
TypeTy *TemplateTypeTy,
SourceLocation IdLoc,
@@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
+ // We don't want access-control diagnostics here.
+ R.suppressDiagnostics();
+
if (SS.isSet() && isDependentScopeSpecifier(SS)) {
bool NotUnknownSpecialization = false;
DeclContext *DC = computeDeclContext(SS, false);
@@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name.
- BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ BaseType = CheckTypenameType(ETK_None,
+ (NestedNameSpecifier *)SS.getScopeRep(),
*MemberOrBase, SS.getRange());
if (BaseType.isNull())
return true;
@@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// If no results were found, try to correct typos.
if (R.empty() && BaseType.isNull() &&
- CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
+ CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) &&
+ R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
@@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
QualType FieldType = Member->getType();
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
FieldType = Array->getElementType();
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
if (FieldType->isDependentType() || HasDependentArg) {
// Can't check initialization for a member of dependent type or when
// any of the arguments are type-dependent expressions.
@@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
ExprTemporaries.end());
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ /*IsVirtual=*/false,
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
@@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// mem-initializer is ill-formed.
if (!DirectBaseSpec && !VirtualBaseSpec)
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << ClassDecl->getNameAsCString()
+ << BaseType << Context.getTypeDeclType(ClassDecl)
<< BaseTInfo->getTypeLoc().getSourceRange();
CXXBaseSpecifier *BaseSpec
@@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// Initialize the base.
InitializedEntity BaseEntity =
- InitializedEntity::InitializeBase(Context, BaseSpec);
+ InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec);
InitializationKind Kind =
InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc);
@@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
= Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
RParenLoc));
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
Init.takeAs<Expr>(),
RParenLoc);
}
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
+ BaseSpec->isVirtual(),
LParenLoc,
BaseInit.takeAs<Expr>(),
RParenLoc);
}
+/// ImplicitInitializerKind - How an implicit base or member initializer should
+/// initialize its base or member.
+enum ImplicitInitializerKind {
+ IIK_Default,
+ IIK_Copy,
+ IIK_Move
+};
+
+static bool
+BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ CXXBaseSpecifier *BaseSpec,
+ bool IsInheritedVirtualBase,
+ CXXBaseOrMemberInitializer *&CXXBaseInit) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec,
+ IsInheritedVirtualBase);
+
+ Sema::OwningExprResult BaseInit(SemaRef);
+
+ switch (ImplicitInitKind) {
+ case IIK_Default: {
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ break;
+ }
+
+ case IIK_Copy: {
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *CopyCtorArg =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ Constructor->getLocation(), ParamType, 0);
+
+ // Cast to the base class to avoid ambiguities.
+ QualType ArgTy =
+ SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
+ ParamType.getQualifiers());
+ SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true,
+ CXXBaseSpecifierArray(BaseSpec));
+
+ InitializationKind InitKind
+ = InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef,
+ (void**)&CopyCtorArg, 1));
+ break;
+ }
+
+ case IIK_Move:
+ assert(false && "Unhandled initializer kind!");
+ }
+
+ BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid())
+ return true;
+
+ CXXBaseInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(),
+ SourceLocation()),
+ BaseSpec->isVirtual(),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+
+ return false;
+}
+
+static bool
+BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
+ ImplicitInitializerKind ImplicitInitKind,
+ FieldDecl *Field,
+ CXXBaseOrMemberInitializer *&CXXMemberInit) {
+ if (ImplicitInitKind == IIK_Copy) {
+ // FIXME: We should not return early here, but will do so until
+ // we know how to handle copy initialization of arrays.
+ CXXMemberInit = 0;
+ return false;
+
+ ParmVarDecl *Param = Constructor->getParamDecl(0);
+ QualType ParamType = Param->getType().getNonReferenceType();
+
+ Expr *MemberExprBase =
+ DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param,
+ SourceLocation(), ParamType, 0);
+
+
+ Expr *CopyCtorArg =
+ MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false,
+ 0, SourceRange(), Field,
+ DeclAccessPair::make(Field, Field->getAccess()),
+ SourceLocation(), 0,
+ Field->getType().getNonReferenceType());
+
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDirect(Constructor->getLocation(),
+ SourceLocation(), SourceLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ &CopyCtorArg, 1);
+
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0);
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit = 0;
+ return false;
+ }
+
+ assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+
+ QualType FieldBaseElementType =
+ SemaRef.Context.getBaseElementType(Field->getType());
+
+ if (FieldBaseElementType->isRecordType()) {
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(Constructor->getLocation());
+
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(SemaRef, InitEntity, InitKind,
+ Sema::MultiExprArg(SemaRef, 0, 0));
+ MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ if (MemberInit.isInvalid())
+ return true;
+
+ CXXMemberInit =
+ new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ return false;
+ }
+
+ if (FieldBaseElementType->isReferenceType()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 0 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ if (FieldBaseElementType.isConstQualified()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 1 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ // Nothing to initialize.
+ CXXMemberInit = 0;
+ return false;
+}
+
bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
bool AnyErrors) {
- if (Constructor->isDependentContext()) {
+ if (Constructor->getDeclContext()->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
if (NumInitializers > 0) {
@@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
return false;
}
+ ImplicitInitializerKind ImplicitInitKind = IIK_Default;
+
+ // FIXME: Handle implicit move constructors.
+ if (Constructor->isImplicit() && Constructor->isCopyConstructor())
+ ImplicitInitKind = IIK_Copy;
+
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
@@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
AllBaseFields[Member->getMember()] = Member;
}
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
+ // Keep track of the direct virtual bases.
+ llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases;
+ for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); I != E; ++I) {
+ if (I->isVirtual())
+ DirectVBases.insert(I);
+ }
// Push virtual bases before others.
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
@@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} 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()) {
+ bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ VBase, IsInheritedVirtualBase,
+ CXXBaseInit)) {
HadError = true;
continue;
}
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
+
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
= AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
AllToInit.push_back(Value);
} 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()) {
+ CXXBaseOrMemberInitializer *CXXBaseInit;
+ if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind,
+ Base, /*IsInheritedVirtualBase=*/false,
+ CXXBaseInit)) {
HadError = true;
continue;
}
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
AllToInit.push_back(CXXBaseInit);
}
}
@@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
continue;
}
- if ((*Field)->getType()->isDependentType() || AnyErrors)
+ if (AnyErrors)
continue;
- QualType FT = Context.getBaseElementType((*Field)->getType());
- 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;
- }
-
- // Don't attach synthesized member initializers in a dependent
- // context; they'll be regenerated a template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *Member =
- new (Context) CXXBaseOrMemberInitializer(Context,
- *Field, SourceLocation(),
- SourceLocation(),
- MemberInit.takeAs<Expr>(),
- SourceLocation());
-
- AllToInit.push_back(Member);
- }
- else if (FT->isReferenceType()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 0 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
- HadError = true;
- }
- else if (FT.isConstQualified()) {
- Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
- << 1 << (*Field)->getDeclName();
- Diag((*Field)->getLocation(), diag::note_declared_at);
+ CXXBaseOrMemberInitializer *Member;
+ if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind,
+ *Field, Member)) {
HadError = true;
+ continue;
}
+
+ // If the member doesn't need to be initialized, it will be null.
+ if (Member)
+ AllToInit.push_back(Member);
}
NumInitializers = AllToInit.size();
@@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context,
if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
Field = Member->getAnonUnionMember();
- // If the field is a member of an anonymous union, we use record decl of the
- // union as the key.
+ // If the field is a member of an anonymous struct or union, our key
+ // is the anonymous record decl that's a direct child of the class.
RecordDecl *RD = Field->getParent();
- if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ if (RD->isAnonymousStructOrUnion()) {
+ while (true) {
+ RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
+ if (Parent->isAnonymousStructOrUnion())
+ RD = Parent;
+ else
+ break;
+ }
+
return static_cast<void *>(RD);
+ }
return static_cast<void *>(Field);
}
@@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context,
static void
DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
const CXXConstructorDecl *Constructor,
- CXXBaseOrMemberInitializer **MemInits,
- unsigned NumMemInits) {
- if (Constructor->isDependentContext())
+ CXXBaseOrMemberInitializer **Inits,
+ unsigned NumInits) {
+ if (Constructor->getDeclContext()->isDependentContext())
return;
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
- Diagnostic::Ignored &&
- SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
- Diagnostic::Ignored)
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order)
+ == Diagnostic::Ignored)
return;
- // Also issue warning if order of ctor-initializer list does not match order
- // of 1) base class declarations and 2) order of non-static data members.
- llvm::SmallVector<const void*, 32> AllBaseOrMembers;
+ // Build the list of bases and members in the order that they'll
+ // actually be initialized. The explicit initializers should be in
+ // this same order but may be missing things.
+ llvm::SmallVector<const void*, 32> IdealInitKeys;
const CXXRecordDecl *ClassDecl = Constructor->getParent();
- // Push virtual bases before others.
+ // 1. Virtual bases.
for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- VBase->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType()));
+ // 2. Non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are alread in the virtual base list and are constructed
- // first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
- Base->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType()));
}
+ // 3. Direct fields.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field)
- AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field));
+ IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
- int Last = AllBaseOrMembers.size();
- int curIndex = 0;
- CXXBaseOrMemberInitializer *PrevMember = 0;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
- void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
+ unsigned NumIdealInits = IdealInitKeys.size();
+ unsigned IdealIndex = 0;
+
+ CXXBaseOrMemberInitializer *PrevInit = 0;
+ for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ CXXBaseOrMemberInitializer *Init = Inits[InitIndex];
+ void *InitKey = GetKeyForMember(SemaRef.Context, Init, true);
- for (; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+ // Scan forward to try to find this initializer in the idealized
+ // initializers list.
+ for (; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
- if (curIndex == Last) {
- assert(PrevMember && "Member not in member list?!");
- // Initializer as specified in ctor-initializer list is out of order.
- // Issue a warning diagnostic.
- if (PrevMember->isBaseInitializer()) {
- // Diagnostics is for an initialized base class.
- Type *BaseClass = PrevMember->getBaseClass();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
- << QualType(BaseClass, 0);
- } else {
- FieldDecl *Field = PrevMember->getMember();
- SemaRef.Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
- << Field->getNameAsString();
- }
- // Also the note!
- if (FieldDecl *Field = Member->getMember())
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
- << Field->getNameAsString();
- else {
- Type *BaseClass = Member->getBaseClass();
- SemaRef.Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 1
- << QualType(BaseClass, 0);
- }
- for (curIndex = 0; curIndex < Last; curIndex++)
- if (MemberInCtorList == AllBaseOrMembers[curIndex])
+
+ // If we didn't find this initializer, it must be because we
+ // scanned past it on a previous iteration. That can only
+ // happen if we're out of order; emit a warning.
+ if (IdealIndex == NumIdealInits) {
+ assert(PrevInit && "initializer not found in initializer list");
+
+ Sema::SemaDiagnosticBuilder D =
+ SemaRef.Diag(PrevInit->getSourceLocation(),
+ diag::warn_initializer_out_of_order);
+
+ if (PrevInit->isMemberInitializer())
+ D << 0 << PrevInit->getMember()->getDeclName();
+ else
+ D << 1 << PrevInit->getBaseClassInfo()->getType();
+
+ if (Init->isMemberInitializer())
+ D << 0 << Init->getMember()->getDeclName();
+ else
+ D << 1 << Init->getBaseClassInfo()->getType();
+
+ // Move back to the initializer's location in the ideal list.
+ for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex)
+ if (InitKey == IdealInitKeys[IdealIndex])
break;
+
+ assert(IdealIndex != NumIdealInits &&
+ "initializer not found in initializer list");
}
- PrevMember = Member;
+
+ PrevInit = Init;
}
}
+namespace {
+bool CheckRedundantInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ CXXBaseOrMemberInitializer *&PrevInit) {
+ if (!PrevInit) {
+ PrevInit = Init;
+ return false;
+ }
+
+ if (FieldDecl *Field = Init->getMember())
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ else {
+ Type *BaseClass = Init->getBaseClass();
+ assert(BaseClass && "neither field nor base");
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_base_initialization)
+ << QualType(BaseClass, 0)
+ << Init->getSourceRange();
+ }
+ S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << PrevInit->getSourceRange();
+
+ return true;
+}
+
+typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry;
+typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap;
+
+bool CheckRedundantUnionInit(Sema &S,
+ CXXBaseOrMemberInitializer *Init,
+ RedundantUnionMap &Unions) {
+ FieldDecl *Field = Init->getMember();
+ RecordDecl *Parent = Field->getParent();
+ if (!Parent->isAnonymousStructOrUnion())
+ return false;
+
+ NamedDecl *Child = Field;
+ do {
+ if (Parent->isUnion()) {
+ UnionEntry &En = Unions[Parent];
+ if (En.first && En.first != Child) {
+ S.Diag(Init->getSourceLocation(),
+ diag::err_multiple_mem_union_initialization)
+ << Field->getDeclName()
+ << Init->getSourceRange();
+ S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
+ << 0 << En.second->getSourceRange();
+ return true;
+ } else if (!En.first) {
+ En.first = Child;
+ En.second = Init;
+ }
+ }
+
+ Child = Parent;
+ Parent = cast<RecordDecl>(Parent->getDeclContext());
+ } while (Parent->isAnonymousStructOrUnion());
+
+ return false;
+}
+}
+
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
SourceLocation ColonLoc,
@@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
CXXBaseOrMemberInitializer **MemInits =
reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
-
+
+ // Mapping for the duplicate initializers check.
+ // For member initializers, this is keyed with a FieldDecl*.
+ // For base initializers, this is keyed with a Type*.
llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+
+ // Mapping for the inconsistent anonymous-union initializers check.
+ RedundantUnionMap MemberUnions;
+
bool HadError = false;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member = MemInits[i];
+ CXXBaseOrMemberInitializer *Init = MemInits[i];
- void *KeyToMember = GetKeyForMember(Context, Member);
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
- }
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString()
- << Member->getSourceRange();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << QualType(BaseClass, 0)
- << Member->getSourceRange();
+ if (Init->isMemberInitializer()) {
+ FieldDecl *Field = Init->getMember();
+ if (CheckRedundantInit(*this, Init, Members[Field]) ||
+ CheckRedundantUnionInit(*this, Init, MemberUnions))
+ HadError = true;
+ } else {
+ void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ if (CheckRedundantInit(*this, Init, Members[Key]))
+ HadError = true;
}
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- HadError = true;
}
if (HadError)
@@ -2060,12 +2298,12 @@ namespace {
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
-void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
+void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (!Record || Record->isInvalidDecl())
return;
if (!Record->isDependentType())
- AddImplicitlyDeclaredMembersToClass(Record);
+ AddImplicitlyDeclaredMembersToClass(S, Record);
if (Record->isInvalidDecl())
return;
@@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
+
+ // If this is not an aggregate type and has no user-declared constructor,
+ // complain about any non-static data members of reference or const scalar
+ // type, since they will never get initializers.
+ if (!Record->isInvalidDecl() && !Record->isDependentType() &&
+ !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) {
+ bool Complained = false;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F) {
+ if (F->getType()->isReferenceType() ||
+ (F->getType().isConstQualified() && F->getType()->isScalarType())) {
+ if (!Complained) {
+ Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst)
+ << Record->getTagKind() << Record;
+ Complained = true;
+ }
+
+ Diag(F->getLocation(), diag::note_refconst_member_not_initialized)
+ << F->getType()->isReferenceType()
+ << F->getDeclName();
+ }
+ }
+ }
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
@@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
(DeclPtrTy*)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(
+ CheckCompletedCXXClass(S,
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
}
@@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// constructor, or destructor, to the given C++ class (C++
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
-void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
+///
+/// The scope, if provided, is the class scope.
+void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
+ CXXRecordDecl *ClassDecl) {
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
@@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
DefaultCon->setAccess(AS_public);
DefaultCon->setImplicit();
DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
- ClassDecl->addDecl(DefaultCon);
+ if (S)
+ PushOnScopeChains(DefaultCon, S, true);
+ else
+ ClassDecl->addDecl(DefaultCon);
}
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
@@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->getLocation(),
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyConstructor->setParams(&FromParam, 1);
- ClassDecl->addDecl(CopyConstructor);
+ if (S)
+ PushOnScopeChains(CopyConstructor, S, true);
+ else
+ ClassDecl->addDecl(CopyConstructor);
}
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
@@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
/*FIXME:*/false,
false, 0, 0,
FunctionType::ExtInfo()),
- /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
+ /*TInfo=*/0, /*isStatic=*/false,
+ /*StorageClassAsWritten=*/FunctionDecl::None,
+ /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassDecl->getLocation(),
- /*IdentifierInfo=*/0,
+ /*Id=*/0,
ArgType, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
CopyAssignment->setParams(&FromParam, 1);
// Don't call addedAssignmentOperator. There is no way to distinguish an
// implicit from an explicit assignment operator.
- ClassDecl->addDecl(CopyAssignment);
+ if (S)
+ PushOnScopeChains(CopyAssignment, S, true);
+ else
+ ClassDecl->addDecl(CopyAssignment);
AddOverriddenMethods(ClassDecl, CopyAssignment);
}
@@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
- ClassDecl->addDecl(Destructor);
+ if (S)
+ PushOnScopeChains(Destructor, S, true);
+ else
+ ClassDecl->addDecl(Destructor);
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
@@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
}
}
- // Notify the class that we've added a constructor.
- ClassDecl->addedConstructor(Context, Constructor);
+ // Notify the class that we've added a constructor. In principle we
+ // don't need to do this for out-of-line declarations; in practice
+ // we only instantiate the most recent declaration of a method, so
+ // we have to call this for everything but friends.
+ if (!Constructor->getFriendObjectKind())
+ ClassDecl->addedConstructor(Context, Constructor);
}
/// CheckDestructor - Checks a fully-formed destructor for well-formedness,
@@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
SC = FunctionDecl::None;
}
+
+ QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
+
if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
// Conversion functions don't have return types, but the parser will
// happily parse something like:
@@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
+ D.setInvalidType();
}
+ const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+
// Make sure we don't have any parameters.
- if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) {
+ if (Proto->getNumArgs() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
D.getTypeObject(0).Fun.freeArgs();
D.setInvalidType();
+ } else if (Proto->isVariadic()) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ D.setInvalidType();
}
- // Make sure the conversion function isn't variadic.
- if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) {
- Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
+ // Diagnose "&operator bool()" and other such nonsense. This
+ // is actually a gcc extension which we don't support.
+ if (Proto->getResultType() != ConvType) {
+ Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl)
+ << Proto->getResultType();
D.setInvalidType();
+ ConvType = Proto->getResultType();
}
// C++ [class.conv.fct]p4:
// The conversion-type-id shall not represent a function type nor
// an array type.
- QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId);
if (ConvType->isArrayType()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array);
ConvType = Context.getPointerType(ConvType);
@@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Rebuild the function type "R" without any parameters (in case any
// of the errors above fired) and with the conversion type as the
// return type.
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
- R = Context.getFunctionType(ConvType, 0, 0, false,
- Proto->getTypeQuals(),
- Proto->hasExceptionSpec(),
- Proto->hasAnyExceptionSpec(),
- Proto->getNumExceptions(),
- Proto->exception_begin(),
- Proto->getExtInfo());
+ if (D.isInvalidType()) {
+ R = Context.getFunctionType(ConvType, 0, 0, false,
+ Proto->getTypeQuals(),
+ Proto->hasExceptionSpec(),
+ Proto->hasAnyExceptionSpec(),
+ Proto->getNumExceptions(),
+ Proto->exception_begin(),
+ Proto->getExtInfo());
+ }
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// in that declarative region, it is treated as an original-namespace-name.
NamedDecl *PrevDecl
- = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName,
+ = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName,
ForRedeclaration);
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
@@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) {
Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S,
SourceLocation UsingLoc,
SourceLocation NamespcLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *NamespcName,
AttributeList *AttrList) {
@@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool IsTypeName,
@@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
/// the lookup differently for these declarations.
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
DeclarationName Name,
AttributeList *AttrList,
@@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (!LookupContext) return D;
UsingDecl *UD = cast<UsingDecl>(D);
- if (RequireCompleteDeclContext(SS)) {
+ if (RequireCompleteDeclContext(SS, LookupContext)) {
UD->setInvalidDecl();
return UD;
}
@@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
SourceLocation NamespaceLoc,
SourceLocation AliasLoc,
IdentifierInfo *Alias,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
SourceLocation IdentLoc,
IdentifierInfo *Ident) {
@@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
LookupParsedName(R, S, &SS);
// Check if we have a previous declaration with the same name.
- if (NamedDecl *PrevDecl
- = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) {
+ NamedDecl *PrevDecl
+ = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
+ ForRedeclaration);
+ if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ PrevDecl = 0;
+
+ if (PrevDecl) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
@@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
return DeclPtrTy::make(AliasDecl);
}
+namespace {
+ /// \brief Scoped object used to handle the state changes required in Sema
+ /// to implicitly define the body of a C++ member function;
+ class ImplicitlyDefinedFunctionScope {
+ Sema &S;
+ DeclContext *PreviousContext;
+
+ public:
+ ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method)
+ : S(S), PreviousContext(S.CurContext)
+ {
+ S.CurContext = Method;
+ S.PushFunctionScope();
+ S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ }
+
+ ~ImplicitlyDefinedFunctionScope() {
+ S.PopExpressionEvaluationContext();
+ S.PopFunctionOrBlockScope();
+ S.CurContext = PreviousContext;
+ }
+ };
+}
+
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
!Constructor->isUsed()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Constructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Constructor);
if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
} else {
Constructor->setUsed();
}
- CurContext = PreviousContext;
}
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
@@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = Destructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, Destructor);
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
@@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
<< CXXDestructor << Context.getTagDeclType(ClassDecl);
Destructor->setInvalidDecl();
- CurContext = PreviousContext;
-
return;
}
- CurContext = PreviousContext;
Destructor->setUsed();
}
-void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
- CXXMethodDecl *MethodDecl) {
- assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal &&
- !MethodDecl->isUsed()) &&
- "DefineImplicitOverloadedAssign - call it for implicit assignment op");
+/// \brief Builds a statement that copies the given entity from \p From to
+/// \c To.
+///
+/// This routine is used to copy the members of a class with an
+/// implicitly-declared copy assignment operator. When the entities being
+/// copied are arrays, this routine builds for loops to copy them.
+///
+/// \param S The Sema object used for type-checking.
+///
+/// \param Loc The location where the implicit copy is being generated.
+///
+/// \param T The type of the expressions being copied. Both expressions must
+/// have this type.
+///
+/// \param To The expression we are copying to.
+///
+/// \param From The expression we are copying from.
+///
+/// \param Depth Internal parameter recording the depth of the recursion.
+///
+/// \returns A statement or a loop that copies the expressions.
+static Sema::OwningStmtResult
+BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+ Sema::OwningExprResult To, Sema::OwningExprResult From,
+ unsigned Depth = 0) {
+ typedef Sema::OwningStmtResult OwningStmtResult;
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ // C++0x [class.copy]p30:
+ // Each subobject is assigned in the manner appropriate to its type:
+ //
+ // - if the subobject is of class type, the copy assignment operator
+ // for the class is used (as if by explicit qualification; that is,
+ // ignoring any possible virtual overriding functions in more derived
+ // classes);
+ if (const RecordType *RecordTy = T->getAs<RecordType>()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+
+ // Look for operator=.
+ DeclarationName Name
+ = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
+ S.LookupQualifiedName(OpLookup, ClassDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = OpLookup.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Create the nested-name-specifier that will be used to qualify the
+ // reference to operator=; this is required to suppress the virtual
+ // call mechanism.
+ CXXScopeSpec SS;
+ SS.setRange(Loc);
+ SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false,
+ T.getTypePtr()));
+
+ // Create the reference to operator=.
+ OwningExprResult OpEqualRef
+ = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS,
+ /*FirstQualifierInScope=*/0, OpLookup,
+ /*TemplateArgs=*/0,
+ /*SuppressQualifierCheck=*/true);
+ if (OpEqualRef.isInvalid())
+ return S.StmtError();
+
+ // Build the call to the assignment operator.
+ Expr *FromE = From.takeAs<Expr>();
+ OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
+ OpEqualRef.takeAs<Expr>(),
+ Loc, &FromE, 1, 0, Loc);
+ if (Call.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Call.takeAs<Stmt>());
+ }
+
+ // - if the subobject is of scalar type, the built-in assignment
+ // operator is used.
+ const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
+ if (!ArrayTy) {
+ OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc,
+ BinaryOperator::Assign,
+ To.takeAs<Expr>(),
+ From.takeAs<Expr>());
+ if (Assignment.isInvalid())
+ return S.StmtError();
+
+ return S.Owned(Assignment.takeAs<Stmt>());
+ }
+
+ // - if the subobject is an array, each element is assigned, in the
+ // manner appropriate to the element type;
+
+ // Construct a loop over the array bounds, e.g.,
+ //
+ // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
+ //
+ // that will copy each of the array elements.
+ QualType SizeType = S.Context.getSizeType();
+
+ // Create the iteration variable.
+ IdentifierInfo *IterationVarName = 0;
+ {
+ llvm::SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "__i" << Depth;
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc,
+ IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
+ VarDecl::None, VarDecl::None);
+
+ // Initialize the iteration variable to zero.
+ llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
+ IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc));
+
+ // Create a reference to the iteration variable; we'll use this several
+ // times throughout.
+ Expr *IterationVarRef
+ = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>();
+ assert(IterationVarRef && "Reference to invented variable cannot fail!");
+
+ // Create the DeclStmt that holds the iteration variable.
+ Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
+
+ // Create the comparison against the array bound.
+ llvm::APInt Upper = ArrayTy->getSize();
+ Upper.zextOrTrunc(S.Context.getTypeSize(SizeType));
+ OwningExprResult Comparison
+ = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(),
+ new (S.Context) IntegerLiteral(Upper, SizeType, Loc),
+ BinaryOperator::NE, S.Context.BoolTy, Loc));
+
+ // Create the pre-increment of the iteration variable.
+ OwningExprResult Increment
+ = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(),
+ UnaryOperator::PreInc,
+ SizeType, Loc));
+
+ // Subscript the "from" and "to" expressions with the iteration variable.
+ From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc,
+ S.Owned(IterationVarRef->Retain()),
+ Loc);
+ assert(!From.isInvalid() && "Builtin subscripting can't fail!");
+ assert(!To.isInvalid() && "Builtin subscripting can't fail!");
+
+ // Build the copy for an individual element of the array.
+ OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc,
+ ArrayTy->getElementType(),
+ move(To), move(From), Depth+1);
+ if (Copy.isInvalid()) {
+ InitStmt->Destroy(S.Context);
+ return S.StmtError();
+ }
+
+ // Construct the loop that copies all elements of this array.
+ return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt),
+ S.MakeFullExpr(Comparison),
+ Sema::DeclPtrTy(),
+ S.MakeFullExpr(Increment),
+ Loc, move(Copy));
+}
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(MethodDecl->getDeclContext());
+void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
+ CXXMethodDecl *CopyAssignOperator) {
+ assert((CopyAssignOperator->isImplicit() &&
+ CopyAssignOperator->isOverloadedOperator() &&
+ CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
+ !CopyAssignOperator->isUsed()) &&
+ "DefineImplicitCopyAssignment called for wrong function");
+
+ CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
- DeclContext *PreviousContext = CurContext;
- CurContext = MethodDecl;
+ if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ CopyAssignOperator->setUsed();
- // C++[class.copy] p12
- // Before the implicitly-declared copy assignment operator for a class is
- // implicitly defined, all implicitly-declared copy assignment operators
- // for its direct base classes and its nonstatic data members shall have
- // been implicitly defined.
- bool err = false;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator);
+
+ // C++0x [class.copy]p30:
+ // The implicitly-defined or explicitly-defaulted copy assignment operator
+ // for a non-union class X performs memberwise copy assignment of its
+ // subobjects. The direct base classes of X are assigned first, in the
+ // order of their declaration in the base-specifier-list, and then the
+ // immediate non-static data members of X are assigned, in the order in
+ // which they were declared in the class definition.
+
+ // The statements that form the synthesized function body.
+ ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this);
+
+ // The parameter for the "other" object, which we are copying from.
+ ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0);
+ Qualifiers OtherQuals = Other->getType().getQualifiers();
+ QualType OtherRefType = Other->getType();
+ if (const LValueReferenceType *OtherRef
+ = OtherRefType->getAs<LValueReferenceType>()) {
+ OtherRefType = OtherRef->getPointeeType();
+ OtherQuals = OtherRefType.getQualifiers();
+ }
+
+ // Our location for everything implicitly-generated.
+ SourceLocation Loc = CopyAssignOperator->getLocation();
+
+ // Construct a reference to the "other" object. We'll be using this
+ // throughout the generated ASTs.
+ Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>();
+ assert(OtherRef && "Reference to parameter cannot fail!");
+
+ // Construct the "this" pointer. We'll be using this throughout the generated
+ // ASTs.
+ Expr *This = ActOnCXXThis(Loc).takeAs<Expr>();
+ assert(This && "Reference to this cannot fail!");
+
+ // Assign base classes.
+ bool Invalid = false;
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXMethodDecl *BaseAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- BaseClassDecl)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseAssignOpMethod,
- PDiag(diag::err_access_assign_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ // Form the assignment:
+ // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other));
+ QualType BaseType = Base->getType().getUnqualifiedType();
+ CXXRecordDecl *BaseClassDecl = 0;
+ if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>())
+ BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl());
+ else {
+ Invalid = true;
+ continue;
+ }
+
+ // Construct the "from" expression, which is an implicit cast to the
+ // appropriately-qualified base type.
+ Expr *From = OtherRef->Retain();
+ ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals),
+ CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true,
+ CXXBaseSpecifierArray(Base));
+
+ // Dereference "this".
+ OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ // Implicitly cast "this" to the appropriately-qualified base type.
+ Expr *ToE = To.takeAs<Expr>();
+ ImpCastExprToType(ToE,
+ Context.getCVRQualifiedType(BaseType,
+ CopyAssignOperator->getTypeQualifiers()),
+ CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/true, CXXBaseSpecifierArray(Base));
+ To = Owned(ToE);
+
+ // Build the copy.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
+ move(To), Owned(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
}
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Expr>());
}
+
+ // \brief Reference to the __builtin_memcpy function.
+ Expr *BuiltinMemCpyRef = 0;
+
+ // Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXMethodDecl *FieldAssignOpMethod =
- getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- FieldClassDecl)) {
- CheckDirectMemberAccess(Field->getLocation(),
- FieldAssignOpMethod,
- PDiag(diag::err_access_assign_field)
- << Field->getDeclName() << Field->getType());
-
- MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
- }
- } else if (FieldType->isReferenceType()) {
+ FieldEnd = ClassDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ // Check for members of reference type; we can't copy those.
+ if (Field->getType()->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
- } else if (FieldType.isConstQualified()) {
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
+ }
+
+ // Check for members of const-qualified, non-class type.
+ QualType BaseType = Context.getBaseElementType(Field->getType());
+ if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
- << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
+ << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName();
Diag(Field->getLocation(), diag::note_declared_at);
- Diag(CurrentLocation, diag::note_first_required_here);
- err = true;
+ Diag(Loc, diag::note_first_required_here);
+ Invalid = true;
+ continue;
}
+
+ QualType FieldType = Field->getType().getNonReferenceType();
+
+ // Build references to the field in the object we're copying from and to.
+ CXXScopeSpec SS; // Intentionally empty
+ LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
+ LookupMemberName);
+ MemberLookup.addDecl(*Field);
+ MemberLookup.resolveKind();
+ OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()),
+ OtherRefType,
+ Loc, /*IsArrow=*/false,
+ SS, 0, MemberLookup, 0);
+ OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()),
+ This->getType(),
+ Loc, /*IsArrow=*/true,
+ SS, 0, MemberLookup, 0);
+ assert(!From.isInvalid() && "Implicit field reference cannot fail");
+ assert(!To.isInvalid() && "Implicit field reference cannot fail");
+
+ // If the field should be copied with __builtin_memcpy rather than via
+ // explicit assignments, do so. This optimization only applies for arrays
+ // of scalars and arrays of class type with trivial copy-assignment
+ // operators.
+ if (FieldType->isArrayType() &&
+ (!BaseType->isRecordType() ||
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
+ ->hasTrivialCopyAssignment())) {
+ // Compute the size of the memory buffer to be copied.
+ QualType SizeType = Context.getSizeType();
+ llvm::APInt Size(Context.getTypeSize(SizeType),
+ Context.getTypeSizeInChars(BaseType).getQuantity());
+ for (const ConstantArrayType *Array
+ = Context.getAsConstantArrayType(FieldType);
+ Array;
+ Array = Context.getAsConstantArrayType(Array->getElementType())) {
+ llvm::APInt ArraySize = Array->getSize();
+ ArraySize.zextOrTrunc(Size.getBitWidth());
+ Size *= ArraySize;
+ }
+
+ // Take the address of the field references for "from" and "to".
+ From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From));
+ To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To));
+
+ // Create a reference to the __builtin_memcpy builtin function.
+ if (!BuiltinMemCpyRef) {
+ LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
+ LookupOrdinaryName);
+ LookupName(R, TUScope, true);
+
+ FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
+ if (!BuiltinMemCpy) {
+ // Something went horribly wrong earlier, and we will have complained
+ // about it.
+ Invalid = true;
+ continue;
+ }
+
+ BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
+ BuiltinMemCpy->getType(),
+ Loc, 0).takeAs<Expr>();
+ assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
+ }
+
+ ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this);
+ CallArgs.push_back(To.takeAs<Expr>());
+ CallArgs.push_back(From.takeAs<Expr>());
+ CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc));
+ llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly
+ Commas.push_back(Loc);
+ Commas.push_back(Loc);
+ OwningExprResult Call = ActOnCallExpr(/*Scope=*/0,
+ Owned(BuiltinMemCpyRef->Retain()),
+ Loc, move_arg(CallArgs),
+ Commas.data(), Loc);
+ assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
+ Statements.push_back(Call.takeAs<Expr>());
+ continue;
+ }
+
+ // Build the copy of this field.
+ OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
+ move(To), move(From));
+ if (Copy.isInvalid()) {
+ Invalid = true;
+ continue;
+ }
+
+ // Success! Record the copy.
+ Statements.push_back(Copy.takeAs<Stmt>());
}
- if (!err)
- MethodDecl->setUsed();
- CurContext = PreviousContext;
-}
+ if (!Invalid) {
+ // Add a "return *this;"
+ OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref,
+ Owned(This->Retain()));
+
+ OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj));
+ if (Return.isInvalid())
+ Invalid = true;
+ else {
+ Statements.push_back(Return.takeAs<Stmt>());
+ }
+ }
-CXXMethodDecl *
-Sema::getAssignOperatorMethod(SourceLocation CurrentLocation,
- ParmVarDecl *ParmDecl,
- CXXRecordDecl *ClassDecl) {
- QualType LHSType = Context.getTypeDeclType(ClassDecl);
- QualType RHSType(LHSType);
- // If class's assignment operator argument is const/volatile qualified,
- // look for operator = (const/volatile B&). Otherwise, look for
- // operator = (B&).
- RHSType = Context.getCVRQualifiedType(RHSType,
- ParmDecl->getType().getCVRQualifiers());
- ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl,
- LHSType,
- SourceLocation()));
- ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl,
- RHSType,
- CurrentLocation));
- Expr *Args[2] = { &*LHS, &*RHS };
- OverloadCandidateSet CandidateSet(CurrentLocation);
- AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2,
- CandidateSet);
- OverloadCandidateSet::iterator Best;
- if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success)
- return cast<CXXMethodDecl>(Best->Function);
- assert(false &&
- "getAssignOperatorMethod - copy assignment operator method not found");
- return 0;
+ if (Invalid) {
+ CopyAssignOperator->setInvalidDecl();
+ return;
+ }
+
+ OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements),
+ /*isStmtExpr=*/false);
+ assert(!Body.isInvalid() && "Compound statement creation cannot fail");
+ CopyAssignOperator->setBody(Body.takeAs<Stmt>());
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
@@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
!CopyConstructor->isUsed()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(CopyConstructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor");
- DeclContext *PreviousContext = CurContext;
- CurContext = CopyConstructor;
+ ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor);
- // C++ [class.copy] p209
- // Before the implicitly-declared copy constructor for a class is
- // implicitly defined, all the implicitly-declared copy constructors
- // for its base class and its non-static data members shall have been
- // implicitly defined.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
- CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
- BaseCopyCtor,
- PDiag(diag::err_access_copy_base)
- << Base->getType());
-
- MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
- }
+ if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) {
+ Diag(CurrentLocation, diag::note_member_synthesized_at)
+ << CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
+ CopyConstructor->setInvalidDecl();
+ } else {
+ CopyConstructor->setUsed();
}
+
+ // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of
+ // fields, this code below should be removed.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
Field != FieldEnd; ++Field) {
@@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
}
}
- CopyConstructor->setUsed();
-
- CurContext = PreviousContext;
}
Sema::OwningExprResult
@@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
bool Elidable = false;
// C++0x [class.copy]p34:
@@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, move(ExprArgs), RequiresZeroInit,
- BaseInitialization);
+ ConstructKind);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool RequiresZeroInit,
- bool BaseInitialization) {
+ CXXConstructExpr::ConstructionKind ConstructKind) {
unsigned NumExprs = ExprArgs.size();
Expr **Exprs = (Expr **)ExprArgs.release();
MarkDeclarationReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
- RequiresZeroInit, BaseInitialization));
+ RequiresZeroInit, ConstructKind));
}
bool Sema::InitializeVarWithConstructor(VarDecl *VD,
@@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl,
FinalizeVarWithDestructor(VDecl, Record);
}
-/// \brief Add the applicable constructor candidates for an initialization
-/// by constructor.
-static void AddConstructorInitializationCandidates(Sema &SemaRef,
- QualType ClassType,
- Expr **Args,
- unsigned NumArgs,
- InitializationKind Kind,
- OverloadCandidateSet &CandidateSet) {
- // C++ [dcl.init]p14:
- // If the initialization is direct-initialization, or if it is
- // copy-initialization where the cv-unqualified version of the
- // source type is the same class as, or a derived class of, the
- // class of the destination, constructors are considered. The
- // applicable constructors are enumerated (13.3.1.3), and the
- // best one is chosen through overload resolution (13.3). The
- // constructor so selected is called to initialize the object,
- // with the initializer expression(s) as its argument(s). If no
- // constructor applies, or the overload resolution is ambiguous,
- // the initialization is ill-formed.
- const RecordType *ClassRec = ClassType->getAs<RecordType>();
- assert(ClassRec && "Can only initialize a class type here");
-
- // FIXME: When we decide not to synthesize the implicitly-declared
- // constructors, we'll need to make them appear here.
-
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
- DeclarationName ConstructorName
- = SemaRef.Context.DeclarationNames.getCXXConstructorName(
- SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType());
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(*Con);
-
- if ((Kind.getKind() == InitializationKind::IK_Direct) ||
- (Kind.getKind() == InitializationKind::IK_Value) ||
- (Kind.getKind() == InitializationKind::IK_Copy &&
- Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) ||
- ((Kind.getKind() == InitializationKind::IK_Default) &&
- Constructor->isDefaultConstructor())) {
- if (ConstructorTmpl)
- SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet);
- else
- SemaRef.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet);
- }
- }
-}
-
-/// \brief Attempt to perform initialization by constructor
-/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or
-/// copy-initialization.
-///
-/// This routine determines whether initialization by constructor is possible,
-/// but it does not emit any diagnostics in the case where the initialization
-/// is ill-formed.
-///
-/// \param ClassType the type of the object being initialized, which must have
-/// class type.
-///
-/// \param Args the arguments provided to initialize the object
-///
-/// \param NumArgs the number of arguments provided to initialize the object
-///
-/// \param Kind the type of initialization being performed
-///
-/// \returns the constructor used to initialize the object, if successful.
-/// Otherwise, emits a diagnostic and returns NULL.
-CXXConstructorDecl *
-Sema::TryInitializationByConstructor(QualType ClassType,
- Expr **Args, unsigned NumArgs,
- SourceLocation Loc,
- InitializationKind Kind) {
- // Build the overload candidate set
- OverloadCandidateSet CandidateSet(Loc);
- AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind,
- CandidateSet);
-
- // Determine whether we found a constructor we can use.
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Loc, Best)) {
- case OR_Success:
- case OR_Deleted:
- // We found a constructor. Return it.
- return cast<CXXConstructorDecl>(Best->Function);
-
- case OR_No_Viable_Function:
- case OR_Ambiguous:
- // Overload resolution failed. Return nothing.
- return 0;
- }
-
- // Silence GCC warning
- return 0;
-}
-
/// \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.
@@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
return Invalid;
}
-/// CompareReferenceRelationship - Compare the two types T1 and T2 to
-/// determine whether they are reference-related,
-/// reference-compatible, reference-compatible with added
-/// qualification, or incompatible, for use in C++ initialization by
-/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
-/// type, and the first type (T1) is the pointee type of the reference
-/// type being initialized.
-Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc,
- QualType OrigT1, QualType OrigT2,
- bool& DerivedToBase) {
- assert(!OrigT1->isReferenceType() &&
- "T1 must be the pointee type of the reference type");
- assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
-
- QualType T1 = Context.getCanonicalType(OrigT1);
- QualType T2 = Context.getCanonicalType(OrigT2);
- Qualifiers T1Quals, T2Quals;
- QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
- QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
- // reference-related to "cv2 T2" if T1 is the same type as T2, or
- // T1 is a base class of T2.
- if (UnqualT1 == UnqualT2)
- DerivedToBase = false;
- else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
- !RequireCompleteType(Loc, OrigT2, PDiag()) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
- DerivedToBase = true;
- else
- return Ref_Incompatible;
-
- // At this point, we know that T1 and T2 are reference-related (at
- // least).
-
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = Context.getQualifiedType(UnqualT2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
- // reference-related to T2 and cv1 is the same cv-qualification
- // as, or greater cv-qualification than, cv2. For purposes of
- // overload resolution, cases for which cv1 is greater
- // cv-qualification than cv2 are identified as
- // reference-compatible with added qualification (see 13.3.3.2).
- if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
- return Ref_Compatible;
- else if (T1.isMoreQualifiedThan(T2))
- return Ref_Compatible_With_Added_Qualification;
- else
- return Ref_Related;
-}
-
-/// CheckReferenceInit - Check the initialization of a reference
-/// variable with the given initializer (C++ [dcl.init.ref]). Init is
-/// the initializer (either a simple initializer or an initializer
-/// list), and DeclType is the type of the declaration. When ICS is
-/// non-null, this routine will compute the implicit conversion
-/// sequence according to C++ [over.ics.ref] and will not produce any
-/// diagnostics; when ICS is null, it will emit diagnostics when any
-/// errors are found. Either way, a return value of true indicates
-/// that there was a failure, a return value of false indicates that
-/// the reference initialization succeeded.
-///
-/// When @p SuppressUserConversions, user-defined conversions are
-/// suppressed.
-/// When @p AllowExplicit, we also permit explicit user-defined
-/// conversion functions.
-/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
-/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion.
-/// This is used when this is called from a C-style cast.
-bool
-Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
- SourceLocation DeclLoc,
- bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue,
- ImplicitConversionSequence *ICS,
- bool IgnoreBaseAccess) {
- assert(DeclType->isReferenceType() && "Reference init needs a reference");
-
- QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
- QualType T2 = Init->getType();
-
- // If the initializer is the address of an overloaded function, try
- // to resolve the overloaded function. If all goes well, T2 is the
- // type of the resulting function.
- if (Context.getCanonicalType(T2) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0, Found);
- if (Fn) {
- // Since we're performing this reference-initialization for
- // real, update the initializer with the resulting function.
- if (!ICS) {
- if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
-
- CheckAddressOfMemberAccess(Init, Found);
- Init = FixOverloadedFunctionReference(Init, Found, Fn);
- }
-
- T2 = Fn->getType();
- }
- }
-
- // Compute some basic properties of the types and the initializer.
- bool isRValRef = DeclType->isRValueReferenceType();
- bool DerivedToBase = false;
- Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
- Init->isLvalue(Context);
- ReferenceCompareResult RefRelationship
- = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
-
- // Most paths end in a failed conversion.
- if (ICS) {
- ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType);
- }
-
- // C++ [dcl.init.ref]p5:
- // A reference to type "cv1 T1" is initialized by an expression
- // of type "cv2 T2" as follows:
-
- // -- If the initializer expression
-
- // Rvalue references cannot bind to lvalues (N2812).
- // There is absolutely no situation where they can. In particular, note that
- // this is ill-formed, even if B has a user-defined conversion to A&&:
- // B b;
- // A&& r = b;
- if (isRValRef && InitLvalue == Expr::LV_Valid) {
- if (!ICS)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- return true;
- }
-
- bool BindsDirectly = false;
- // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
- // reference-compatible with "cv2 T2," or
- //
- // Note that the bit-field check is skipped if we are just computing
- // the implicit conversion sequence (C++ [over.best.ics]p2).
- if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- BindsDirectly = true;
-
- if (ICS) {
- // C++ [over.ics.ref]p1:
- // When a parameter of reference type binds directly (8.5.3)
- // to an argument expression, the implicit conversion sequence
- // is the identity conversion, unless the argument expression
- // has a type that is a derived class of the parameter type,
- // in which case the implicit conversion sequence is a
- // derived-to-base Conversion (13.3.3.1).
- ICS->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.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;
- ICS->Standard.CopyConstructor = 0;
-
- // Nothing more to do: the inaccessibility/ambiguity check for
- // derived-to-base conversions is suppressed when we're
- // computing the implicit conversion sequence (C++
- // [over.best.ics]p2).
- return false;
- } else {
- // Perform the conversion.
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true);
- }
- }
-
- // -- has a class type (i.e., T2 is a class type) and can be
- // implicitly converted to an lvalue of type "cv3 T3,"
- // where "cv1 T1" is reference-compatible with "cv3 T3"
- // 92) (this conversion is selected by enumerating the
- // applicable conversion functions (13.3.1.6) and choosing
- // the best one through overload resolution (13.3)),
- if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
- !RequireCompleteType(DeclLoc, T2, 0)) {
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
-
- OverloadCandidateSet CandidateSet(DeclLoc);
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
- NamedDecl *D = *I;
- CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- FunctionTemplateDecl *ConvTemplate
- = dyn_cast<FunctionTemplateDecl>(D);
- CXXConversionDecl *Conv;
- if (ConvTemplate)
- Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
- else
- Conv = cast<CXXConversionDecl>(D);
-
- // If the conversion function doesn't return a reference type,
- // it can't be considered for this conversion.
- if (Conv->getConversionType()->isLValueReferenceType() &&
- (AllowExplicit || !Conv->isExplicit())) {
- if (ConvTemplate)
- AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
- Init, DeclType, CandidateSet);
- else
- AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
- DeclType, CandidateSet);
- }
- }
-
- OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, DeclLoc, Best)) {
- case OR_Success:
- // C++ [over.ics.ref]p1:
- //
- // [...] If the parameter binds directly to the result of
- // applying a conversion function to the argument
- // expression, the implicit conversion sequence is a
- // user-defined conversion sequence (13.3.3.1.2), with the
- // second standard conversion sequence either an identity
- // conversion or, if the conversion function returns an
- // entity of a type that is a derived class of the parameter
- // type, a derived-to-base Conversion.
- if (!Best->FinalConversion.DirectBinding)
- break;
-
- // This is a direct binding.
- BindsDirectly = true;
-
- if (ICS) {
- ICS->setUserDefined();
- ICS->UserDefined.Before = Best->Conversions[0].Standard;
- ICS->UserDefined.After = Best->FinalConversion;
- ICS->UserDefined.ConversionFunction = Best->Function;
- ICS->UserDefined.EllipsisConversion = false;
- assert(ICS->UserDefined.After.ReferenceBinding &&
- ICS->UserDefined.After.DirectBinding &&
- "Expected a direct reference binding!");
- return false;
- } else {
- OwningExprResult InitConversion =
- BuildCXXCastArgument(DeclLoc, QualType(),
- CastExpr::CK_UserDefinedConversion,
- cast<CXXMethodDecl>(Best->Function),
- Owned(Init));
- Init = InitConversion.takeAs<Expr>();
-
- if (CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion,
- /*isLvalue=*/true);
- }
- break;
-
- case OR_Ambiguous:
- if (ICS) {
- ICS->setAmbiguous();
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
- Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
- ICS->Ambiguous.addConversion(Cand->Function);
- break;
- }
- Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
- << Init->getSourceRange();
- PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1);
- return true;
-
- case OR_No_Viable_Function:
- case OR_Deleted:
- // There was no suitable conversion, or we found a deleted
- // conversion; continue with other checks.
- break;
- }
- }
-
- if (BindsDirectly) {
- // C++ [dcl.init.ref]p4:
- // [...] In all cases where the reference-related or
- // reference-compatible relationship of two types is used to
- // establish the validity of a reference binding, and T1 is a
- // base class of T2, a program that necessitates such a binding
- // is ill-formed if T1 is an inaccessible (clause 11) or
- // ambiguous (10.2) base class of T2.
- //
- // Note that we only check this condition when we're allowed to
- // complain about errors, because we should not be checking for
- // ambiguity (or inaccessibility) unless the reference binding
- // actually happens.
- if (DerivedToBase)
- return CheckDerivedToBaseConversion(T2, T1, DeclLoc,
- Init->getSourceRange(),
- IgnoreBaseAccess);
- else
- return false;
- }
-
- // -- Otherwise, the reference shall be to a 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 (!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;
- }
-
- // -- If the initializer expression is an rvalue, with T2 a
- // class type, and "cv1 T1" is reference-compatible with
- // "cv2 T2," the reference is bound in one of the
- // following ways (the choice is implementation-defined):
- //
- // -- The reference is bound to the object represented by
- // the rvalue (see 3.10) or to a sub-object within that
- // object.
- //
- // -- A temporary of type "cv1 T2" [sic] is created, and
- // a constructor is called to copy the entire rvalue
- // object into the temporary. The reference is bound to
- // the temporary or to a sub-object within the
- // temporary.
- //
- // The constructor that would be used to make the copy
- // shall be callable whether or not the copy is actually
- // done.
- //
- // Note that C++0x [dcl.init.ref]p5 takes away this implementation
- // freedom, so we will always take the first option and never build
- // a temporary in this case. FIXME: We will, however, have to check
- // for the presence of a copy constructor in C++98/03 mode.
- if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
- RefRelationship >= Ref_Compatible_With_Added_Qualification) {
- if (ICS) {
- ICS->setStandard();
- ICS->Standard.First = ICK_Identity;
- ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
- ICS->Standard.Third = ICK_Identity;
- ICS->Standard.FromTypePtr = T2.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;
- ICS->Standard.CopyConstructor = 0;
- } else {
- CastExpr::CastKind CK = CastExpr::CK_NoOp;
- if (DerivedToBase)
- CK = CastExpr::CK_DerivedToBase;
- else if(CheckExceptionSpecCompatibility(Init, T1))
- return true;
- ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false);
- }
- return false;
- }
-
- // -- Otherwise, a temporary of type "cv1 T1" is created and
- // initialized from the initializer expression using the
- // rules for a non-reference copy initialization (8.5). The
- // reference is then bound to the temporary. If T1 is
- // reference-related to T2, cv1 must be the same
- // cv-qualification as, or greater cv-qualification than,
- // cv2; otherwise, the program is ill-formed.
- if (RefRelationship == Ref_Related) {
- // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
- // we would be reference-compatible or reference-compatible with
- // added qualification. But that wasn't the case, so the reference
- // initialization fails.
- if (!ICS)
- Diag(DeclLoc, diag::err_reference_init_drops_quals)
- << T1 << int(InitLvalue != Expr::LV_Valid)
- << T2 << Init->getSourceRange();
- return true;
- }
-
- // If at least one of the types is a class type, the types are not
- // related, and we aren't allowed any user conversions, the
- // reference binding fails. This case is important for breaking
- // recursion, since TryImplicitConversion below will attempt to
- // create a temporary through the use of a copy constructor.
- if (SuppressUserConversions && RefRelationship == Ref_Incompatible &&
- (T1->isRecordType() || T2->isRecordType())) {
- if (!ICS)
- Diag(DeclLoc, diag::err_typecheck_convert_incompatible)
- << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange();
- return true;
- }
-
- // Actually try to convert the initializer to T1.
- if (ICS) {
- // C++ [over.ics.ref]p2:
- //
- // When a parameter of reference type is not bound directly to
- // an argument expression, the conversion sequence is the one
- // required to convert the argument expression to the
- // underlying type of the reference according to
- // 13.3.3.1. Conceptually, this conversion sequence corresponds
- // to copy-initializing a temporary of the underlying type with
- // the argument expression. Any difference in top-level
- // cv-qualification is subsumed by the initialization itself
- // and does not constitute a conversion.
- *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- // Of course, that's still a reference binding.
- if (ICS->isStandard()) {
- ICS->Standard.ReferenceBinding = true;
- ICS->Standard.RRefBinding = isRValRef;
- } else if (ICS->isUserDefined()) {
- ICS->UserDefined.After.ReferenceBinding = true;
- ICS->UserDefined.After.RRefBinding = isRValRef;
- }
- return ICS->isBad();
- } else {
- ImplicitConversionSequence Conversions;
- bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
- false, false,
- Conversions);
- if (badConversion) {
- if (Conversions.isAmbiguous()) {
- Diag(DeclLoc,
- diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
- for (int j = Conversions.Ambiguous.conversions().size()-1;
- j >= 0; j--) {
- FunctionDecl *Func = Conversions.Ambiguous.conversions()[j];
- NoteOverloadCandidate(Func);
- }
- }
- else {
- if (isRValRef)
- Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref)
- << Init->getSourceRange();
- else
- Diag(DeclLoc, diag::err_invalid_initialization)
- << DeclType << Init->getType() << Init->getSourceRange();
- }
- }
- return badConversion;
- }
-}
-
static inline bool
CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef,
const FunctionDecl *FnDecl) {
@@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
bool Valid = false;
- // FIXME: Check for the one valid template signature
- // template <char...> type operator "" name();
-
- if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ // template <char...> type operator "" name() is the only valid template
+ // signature, and the only valid signature with no parameters.
+ if (FnDecl->param_size() == 0) {
+ if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) {
+ // Must have only one template parameter
+ TemplateParameterList *Params = TpDecl->getTemplateParameters();
+ if (Params->size() == 1) {
+ NonTypeTemplateParmDecl *PmDecl =
+ cast<NonTypeTemplateParmDecl>(Params->getParam(0));
+
+ // The template parameter must be a char parameter pack.
+ // FIXME: This test will always fail because non-type parameter packs
+ // have not been implemented.
+ if (PmDecl && PmDecl->isTemplateParameterPack() &&
+ Context.hasSameType(PmDecl->getType(), Context.CharTy))
+ Valid = true;
+ }
+ }
+ } else {
// Check the first parameter
+ FunctionDecl::param_iterator Param = FnDecl->param_begin();
+
QualType T = (*Param)->getType();
- // unsigned long long int and long double are allowed, but only
- // alone.
- // We also allow any character type; their omission seems to be a bug
- // in n3000
+ // unsigned long long int, long double, and any character type are allowed
+ // as the only parameters.
if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
Context.hasSameType(T, Context.LongDoubleTy) ||
Context.hasSameType(T, Context.CharTy) ||
@@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
goto FinishedParams;
}
- // Otherwise it must be a pointer to const; let's strip those.
+ // Otherwise it must be a pointer to const; let's strip those qualifiers.
const PointerType *PT = T->getAs<PointerType>();
if (!PT)
goto FinishedParams;
@@ -5121,13 +5186,12 @@ FinishedParams:
Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
SourceLocation ExternLoc,
SourceLocation LangLoc,
- const char *Lang,
- unsigned StrSize,
+ llvm::StringRef Lang,
SourceLocation LBraceLoc) {
LinkageSpecDecl::LanguageIDs Language;
- if (strncmp(Lang, "\"C\"", StrSize) == 0)
+ if (Lang == "\"C\"")
Language = LinkageSpecDecl::lang_c;
- else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
+ else if (Lang == "\"C++\"")
Language = LinkageSpecDecl::lang_cxx;
else {
Diag(LangLoc, diag::err_bad_language);
@@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType,
Invalid = true;
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc,
- Name, ExDeclType, TInfo, VarDecl::None);
-
+ Name, ExDeclType, TInfo, VarDecl::None,
+ VarDecl::None);
+ ExDecl->setExceptionVariable(true);
+
if (!Invalid) {
if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) {
// C++ [except.handle]p16:
@@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
IdentifierInfo *II = D.getIdentifier();
- if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) {
+ if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(),
+ LookupOrdinaryName,
+ ForRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
// it contains any previous declaration.
assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl)));
@@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
return DeclPtrTy::make(Decl);
}
+/// \brief Perform semantic analysis of the given friend type declaration.
+///
+/// \returns A friend declaration that.
+FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc,
+ TypeSourceInfo *TSInfo) {
+ assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
+
+ QualType T = TSInfo->getType();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
+
+ if (!getLangOptions().CPlusPlus0x) {
+ // C++03 [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ //
+ // * The class-key of the elaborated-type-specifier is required.
+ if (!ActiveTemplateInstantiations.empty()) {
+ // Do not complain about the form of friend template types during
+ // template instantiation; we will already have complained when the
+ // template was declared.
+ } else if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
+
+ std::string InsertionText = std::string(" ") + RD->getKindName();
+
+ Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc, diag::ext_nonclass_type_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ } else if (T->getAs<EnumType>()) {
+ Diag(FriendLoc, diag::ext_enum_friend)
+ << T
+ << SourceRange(FriendLoc, TypeRange.getEnd());
+ }
+ }
+
+ // C++0x [class.friend]p3:
+ // If the type specifier in a friend declaration designates a (possibly
+ // cv-qualified) class type, that class is declared as a friend; otherwise,
+ // the friend declaration is ignored.
+
+ // FIXME: C++0x has some syntactic restrictions on friend type declarations
+ // in [class.friend]p3 that we do not implement.
+
+ return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc);
+}
+
/// Handle a friend type declaration. This works in tandem with
/// ActOnTag.
///
@@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
+ if (!TSI)
+ TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin());
+
// This is definitely an error in C++98. It's probably meant to
// be forbidden in C++0x, too, but the specification is just
// poorly written.
@@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< DS.getSourceRange();
return DeclPtrTy();
}
-
- // C++ [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- // * The class-key of the elaborated-type-specifier is required.
- // This is one of the rare places in Clang where it's legitimate to
- // ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
- Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << SourceRange(DS.getFriendSpecLoc())
- << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
- return DeclPtrTy();
- }else {
- Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
- << DS.getSourceRange();
- return DeclPtrTy();
- }
- }
-
- // Enum types cannot be friends.
- if (T->getAs<EnumType>()) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
- << SourceRange(DS.getFriendSpecLoc());
- return DeclPtrTy();
- }
-
+
// C++98 [class.friend]p1: A friend of a class is a function
// or class that is not a member of the class . . .
// This is fixed in DR77, which just barely didn't make the C++03
@@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (TempParams.size())
+ if (unsigned NumTempParamLists = TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
- TempParams.size(),
+ NumTempParamLists,
(TemplateParameterList**) TempParams.release(),
TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, TSI,
- DS.getFriendSpecLoc());
+ D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI);
+
+ if (!D)
+ return DeclPtrTy();
+
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName,
ForRedeclaration);
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
- // FIXME: RequireCompleteDeclContext
DC = computeDeclContext(ScopeQual);
// FIXME: handle dependent contexts
if (!DC) return DeclPtrTy();
+ if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy();
LookupQualifiedName(Previous, DC);
@@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
FrD->setAccess(AS_public);
CurContext->addDecl(FrD);
- if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
- FrD->setSpecialization(true);
-
return DeclPtrTy::make(ND);
}
@@ -5701,10 +5794,10 @@ 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,
- diag::err_covariant_return_ambiguous_derived_to_base_conv,
- // FIXME: Should this point to the return type?
- New->getLocation(), SourceRange(), New->getDeclName())) {
+ diag::err_covariant_return_inaccessible_base,
+ diag::err_covariant_return_ambiguous_derived_to_base_conv,
+ // FIXME: Should this point to the return type?
+ New->getLocation(), SourceRange(), New->getDeclName(), 0)) {
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
@@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) {
return Dcl;
}
-static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
+static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) {
// Ignore dependent types.
if (MD->isDependentContext())
return false;
@@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
// We will need to mark all of the virtual members as referenced to build the
// vtable.
- if (!needsVtable(MD, Context))
+ if (!needsVTable(MD, Context))
return;
TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
@@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
MarkVirtualMembersReferenced(Loc, Base);
}
}
+
+/// SetIvarInitializers - This routine builds initialization ASTs for the
+/// Objective-C implementation whose ivars need be initialized.
+void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
+ if (!getLangOptions().CPlusPlus)
+ return;
+ if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) {
+ llvm::SmallVector<ObjCIvarDecl*, 8> ivars;
+ CollectIvarsToConstructOrDestruct(OID, ivars);
+ if (ivars.empty())
+ return;
+ llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+ for (unsigned i = 0; i < ivars.size(); i++) {
+ FieldDecl *Field = ivars[i];
+ CXXBaseOrMemberInitializer *Member;
+ InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field);
+ InitializationKind InitKind =
+ InitializationKind::CreateDefault(ObjCImplementation->getLocation());
+
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ Sema::OwningExprResult MemberInit =
+ InitSeq.Perform(*this, InitEntity, InitKind,
+ Sema::MultiExprArg(*this, 0, 0));
+ MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit));
+ // Note, MemberInit could actually come back empty if no initialization
+ // is required (e.g., because it would call a trivial default constructor)
+ if (!MemberInit.get() || MemberInit.isInvalid())
+ continue;
+
+ Member =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Field, SourceLocation(),
+ SourceLocation(),
+ MemberInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(Member);
+ }
+ ObjCImplementation->setIvarInitializers(Context,
+ AllToInit.data(), AllToInit.size());
+ }
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 0c47e63d99eb..d446cc13da26 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -66,13 +66,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
- NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
- if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl);
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
- }
+ NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc,
+ LookupOrdinaryName, ForRedeclaration);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
@@ -98,6 +93,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Since this ObjCInterfaceDecl was created by a forward declaration,
// we now add it to the DeclContext since it wasn't added before
// (see ActOnForwardClassDeclaration).
+ IDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(IDecl);
if (AttrList)
@@ -114,12 +110,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+ PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
+ LookupOrdinaryName);
if (!PrevDecl) {
// Try to correct for a typo in the superclass name.
LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
@@ -198,7 +195,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
IdentifierInfo *ClassName,
SourceLocation ClassLocation) {
// Look for previous declaration of alias name
- NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName);
+ NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation,
+ LookupOrdinaryName, ForRedeclaration);
if (ADecl) {
if (isa<ObjCCompatibleAliasDecl>(ADecl))
Diag(AliasLocation, diag::warn_previous_alias_decl);
@@ -208,13 +206,15 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return DeclPtrTy();
}
// Check for class declaration
- NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
+ LookupOrdinaryName, ForRedeclaration);
if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCInterfaceType()) {
if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) {
ClassName = IDecl->getIdentifier();
- CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
+ LookupOrdinaryName, ForRedeclaration);
}
}
}
@@ -243,7 +243,8 @@ void Sema::CheckForwardProtocolDeclarationForCircularDependency(
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
- if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) {
+ if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(),
+ Ploc)) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
@@ -265,7 +266,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
AttributeList *AttrList) {
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName);
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
if (PDecl) {
// Protocol already seen. Better be a forward protocol declaration
if (!PDecl->isForwardDecl()) {
@@ -312,11 +313,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
unsigned NumProtocols,
llvm::SmallVectorImpl<DeclPtrTy> &Protocols) {
for (unsigned i = 0; i != NumProtocols; ++i) {
- ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first);
+ ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
+ ProtocolId[i].second);
if (!PDecl) {
LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
LookupObjCProtocolName);
- if (CorrectTypo(R, TUScope, 0) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first << R.getLookupName();
@@ -382,7 +384,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
- ObjCProtocolDecl *PDecl = LookupProtocol(Ident);
+ ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second);
if (PDecl == 0) { // Not already seen?
PDecl = ObjCProtocolDecl::Create(Context, CurContext,
IdentList[i].second, Ident);
@@ -413,7 +415,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl = 0;
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
@@ -491,7 +493,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
ObjCCategoryDecl *CatIDecl = 0;
if (IDecl) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
@@ -539,7 +541,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
ObjCInterfaceDecl* IDecl = 0;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
- = LookupSingleName(TUScope, ClassName, LookupOrdinaryName);
+ = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
@@ -553,7 +556,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
// We did not find anything with the name ClassName; try to correct for
// typos in the class name.
LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
- if (CorrectTypo(R, TUScope, 0) &&
+ if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
(IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
// Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in
@@ -576,7 +579,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
ObjCInterfaceDecl* SDecl = 0;
if (SuperClassname) {
// Check if a different kind of symbol declared in this scope.
- PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName);
+ PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc,
+ LookupOrdinaryName);
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(SuperClassLoc, diag::err_redefinition_different_kind)
<< SuperClassname;
@@ -1003,7 +1007,8 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
for (unsigned i = 0; i != NumElts; ++i) {
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
- = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName);
+ = LookupSingleName(TUScope, IdentList[i], IdentLocs[i],
+ LookupOrdinaryName, ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl);
@@ -1436,6 +1441,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
IDecl = IDecl->getSuperClass();
}
}
+ SetIvarInitializers(IC);
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
CatImplClass->setAtEndRange(AtEnd);
@@ -1487,6 +1493,16 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
return ret;
}
+static inline
+bool containsInvalidMethodImplAttribute(const AttributeList *A) {
+ // The 'ibaction' attribute is allowed on method definitions because of
+ // how the IBAction macro is used on both method declarations and definitions.
+ // If the method definitions contains any other attributes, return true.
+ while (A && A->getKind() == AttributeList::AT_IBAction)
+ A = A->getNext();
+ return A != NULL;
+}
+
Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, DeclPtrTy classDecl,
@@ -1495,7 +1511,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
- llvm::SmallVectorImpl<Declarator> &Cdecls,
+ DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args
AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
bool isVariadic) {
Decl *ClassDecl = classDecl.getAs<Decl>();
@@ -1550,7 +1566,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
ParmVarDecl* Param
= ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType, DI,
- VarDecl::None, 0);
+ VarDecl::None, VarDecl::None, 0);
if (ArgType->isObjCInterfaceType()) {
Diag(ArgInfo[i].NameLoc,
@@ -1568,7 +1584,27 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
Params.push_back(Param);
}
- ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs());
+ for (unsigned i = 0, e = CNumArgs; i != e; ++i) {
+ ParmVarDecl *Param = CParamInfo[i].Param.getAs<ParmVarDecl>();
+ QualType ArgType = Param->getType();
+ if (ArgType.isNull())
+ ArgType = Context.getObjCIdType();
+ else
+ // Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
+ ArgType = adjustParameterType(ArgType);
+ if (ArgType->isObjCInterfaceType()) {
+ Diag(Param->getLocation(),
+ diag::err_object_cannot_be_passed_returned_by_value)
+ << 1 << ArgType;
+ Param->setInvalidDecl();
+ }
+ Param->setDeclContext(ObjCMethod);
+ IdResolver.RemoveDecl(Param);
+ Params.push_back(Param);
+ }
+
+ ObjCMethod->setMethodParams(Context, Params.data(), Params.size(),
+ Sel.getNumArgs());
ObjCMethod->setObjCDeclQualifier(
CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier()));
const ObjCMethodDecl *PrevMethod = 0;
@@ -1593,7 +1629,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
}
InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
MethodType == tok::minus);
- if (AttrList)
+ if (containsInvalidMethodImplAttribute(AttrList))
Diag(EndLoc, diag::warn_attribute_method_def);
} else if (ObjCCategoryImplDecl *CatImpDecl =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
@@ -1604,7 +1640,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration(
PrevMethod = CatImpDecl->getClassMethod(Sel);
CatImpDecl->addClassMethod(ObjCMethod);
}
- if (AttrList)
+ if (containsInvalidMethodImplAttribute(AttrList))
Diag(EndLoc, diag::warn_attribute_method_def);
}
if (PrevMethod) {
@@ -1638,7 +1674,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclPtrTy> &Decls) {
// Check that ClassName is a valid class
- ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart);
if (!Class) {
Diag(DeclStart, diag::err_undef_interface) << ClassName;
return;
@@ -1672,3 +1708,146 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
}
}
+/// \brief Build a type-check a new Objective-C exception variable declaration.
+VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo,
+ QualType T,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool Invalid) {
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // duration shall not be qualified by an address-space qualifier."
+ // Since all parameters have automatic store duration, they can not have
+ // an address space.
+ if (T.getAddressSpace() != 0) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ Invalid = true;
+ }
+
+ // An @catch parameter must be an unqualified object pointer type;
+ // FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"?
+ if (Invalid) {
+ // Don't do any further checking.
+ } else if (T->isDependentType()) {
+ // Okay: we don't know what this type will instantiate to.
+ } else if (!T->isObjCObjectPointerType()) {
+ Invalid = true;
+ Diag(NameLoc ,diag::err_catch_param_not_objc_type);
+ } else if (T->isObjCQualifiedIdType()) {
+ Invalid = true;
+ Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm);
+ }
+
+ VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo,
+ VarDecl::None, VarDecl::None);
+ New->setExceptionVariable(true);
+
+ if (Invalid)
+ New->setInvalidDecl();
+ return New;
+}
+
+Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ // We allow the "register" storage class on exception variables because
+ // GCC did, but we drop it completely. Any other storage class is an error.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
+ Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm)
+ << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc()));
+ } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
+ Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
+ << DS.getStorageClassSpec();
+ }
+ if (D.getDeclSpec().isThreadSpecified())
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+
+ DiagnoseFunctionSpecifiers(D);
+
+ // Check that there are no default arguments inside the type of this
+ // exception object (C++ only).
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ TypeSourceInfo *TInfo = 0;
+ TagDecl *OwnedDecl = 0;
+ QualType ExceptionType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl);
+
+ if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) {
+ // Objective-C++: Types shall not be defined in exception types.
+ Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type)
+ << Context.getTypeDeclType(OwnedDecl);
+ }
+
+ VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(),
+ D.getIdentifierLoc(),
+ D.isInvalidType());
+
+ // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
+ if (D.getCXXScopeSpec().isSet()) {
+ Diag(D.getIdentifierLoc(), diag::err_qualified_objc_catch_parm)
+ << D.getCXXScopeSpec().getRange();
+ New->setInvalidDecl();
+ }
+
+ // Add the parameter declaration into this scope.
+ S->AddDecl(DeclPtrTy::make(New));
+ if (D.getIdentifier())
+ IdResolver.AddDecl(New);
+
+ ProcessDeclAttributes(S, New, D);
+
+ if (New->hasAttr<BlocksAttr>())
+ Diag(New->getLocation(), diag::err_block_on_nonlocal);
+ return DeclPtrTy::make(New);
+}
+
+/// CollectIvarsToConstructOrDestruct - Collect those ivars which require
+/// initialization.
+void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI,
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
+ E = OI->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+
+ // Find ivars to construct/destruct in class extension.
+ if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
+ for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
+ E = CDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+ }
+
+ // Also add any ivar defined in this class's implementation. This
+ // includes synthesized ivars.
+ if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) {
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *Iv = (*I);
+ QualType QT = Context.getBaseElementType(Iv->getType());
+ if (isa<RecordType>(QT))
+ Ivars.push_back(*I);
+ }
+ }
+}
+
+void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
+ CXXBaseOrMemberInitializer ** initializers,
+ unsigned numInitializers) {
+ if (numInitializers > 0) {
+ NumIvarInitializers = numInitializers;
+ CXXBaseOrMemberInitializer **ivarInitializers =
+ new (C) CXXBaseOrMemberInitializer*[NumIvarInitializers];
+ memcpy(ivarInitializers, initializers,
+ numInitializers * sizeof(CXXBaseOrMemberInitializer*));
+ IvarInitializers = ivarInitializers;
+ }
+}
+
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2dfb95435dda..c4ab03facb52 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -16,10 +16,13 @@
#include "Lookup.h"
#include "AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -80,6 +83,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
const SentinelAttr *attr = D->getAttr<SentinelAttr>();
if (!attr)
return;
+
+ // FIXME: In C++0x, if any of the arguments are parameter pack
+ // expansions, we can't check for the sentinel now.
int sentinelPos = attr->getSentinel();
int nullPos = attr->getNullPos();
@@ -155,6 +161,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) &&
+ !sentinelExpr->isTypeDependent() &&
+ !sentinelExpr->isValueDependent() &&
(!sentinelExpr->getType()->isPointerType() ||
!sentinelExpr->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)))) {
@@ -454,7 +462,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
}
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
+ if (isa<NonTypeTemplateParmDecl>(VD)) {
+ // Non-type template parameters can be referenced anywhere they are
+ // visible.
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function)
@@ -769,24 +780,6 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
return true;
}
-/// Determines if this is an instance member of a class.
-static bool IsInstanceMember(NamedDecl *D) {
- assert(D->isCXXClassMember() &&
- "checking whether non-member is instance member");
-
- if (isa<FieldDecl>(D)) return true;
-
- if (isa<CXXMethodDecl>(D))
- return !cast<CXXMethodDecl>(D)->isStatic();
-
- if (isa<FunctionTemplateDecl>(D)) {
- D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
- return !cast<CXXMethodDecl>(D)->isStatic();
- }
-
- return false;
-}
-
enum IMAKind {
/// The reference is definitely not an instance member access.
IMA_Static,
@@ -846,8 +839,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
bool hasNonInstance = false;
llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = (*I)->getUnderlyingDecl();
- if (IsInstanceMember(D)) {
+ NamedDecl *D = *I;
+ if (D->isCXXInstanceMember()) {
CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
// If this is a member of an anonymous record, move out to the
@@ -913,7 +906,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef,
/// Diagnose an empty lookup.
///
/// \return false if new lookup candidates were found
-bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
+bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS,
LookupResult &R) {
DeclarationName Name = R.getLookupName();
@@ -964,43 +957,55 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
}
// We didn't find anything, so try to correct for a typo.
- if (S && CorrectTypo(R, S, &SS)) {
- if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
- if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- else
- Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
- << SS.getRange()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
- if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
- Diag(ND->getLocation(), diag::note_previous_decl)
- << ND->getDeclName();
-
- // Tell the callee to try to recover.
- return false;
- }
+ DeclarationName Corrected;
+ if (S && (Corrected = CorrectTypo(R, S, &SS))) {
+ if (!R.empty()) {
+ if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange()
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+
+ // Tell the callee to try to recover.
+ return false;
+ }
+
+ if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+ // FIXME: If we ended up with a typo for a type name or
+ // Objective-C class name, we're in trouble because the parser
+ // is in the wrong place to recover. Suggest the typo
+ // correction, but don't make it a fix-it since we're not going
+ // to recover well anyway.
+ if (SS.isEmpty())
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ else
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << Name << computeDeclContext(SS, false) << R.getLookupName()
+ << SS.getRange();
- if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
- // FIXME: If we ended up with a typo for a type name or
- // Objective-C class name, we're in trouble because the parser
- // is in the wrong place to recover. Suggest the typo
- // correction, but don't make it a fix-it since we're not going
- // to recover well anyway.
+ // Don't try to recover; it won't work.
+ return true;
+ }
+ } else {
+ // FIXME: We found a keyword. Suggest it, but don't provide a fix-it
+ // because we aren't able to recover.
if (SS.isEmpty())
- Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+ Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
- << Name << computeDeclContext(SS, false) << R.getLookupName()
- << SS.getRange();
-
- // Don't try to recover; it won't work.
+ << Name << computeDeclContext(SS, false) << Corrected
+ << SS.getRange();
return true;
}
-
R.clear();
}
@@ -1019,7 +1024,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
}
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Id,
bool HasTrailingLParen,
bool isAddressOfOperand) {
@@ -1064,6 +1069,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
if (TemplateArgs) {
// Just re-use the lookup done by isTemplateName.
DecomposeTemplateName(R, Id);
+
+ // Re-derive the naming class.
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (const Type *Ty = Qualifier->getAsType())
+ if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ }
} else {
bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
@@ -1123,16 +1137,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Warn about constructs like:
// if (void *X = foo()) { ... } else { X }.
// In the else block, the pointer is always false.
-
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
Scope *CheckS = S;
while (CheckS && CheckS->getControlParent()) {
- if (CheckS->isWithinElse() &&
+ if ((CheckS->getFlags() & Scope::ElseScope) &&
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
ExprError(Diag(NameLoc, diag::warn_value_always_zero)
<< Var->getDeclName()
- << (Var->getType()->isPointerType()? 2 :
- Var->getType()->isBooleanType()? 1 : 0));
+ << (Var->getType()->isPointerType() ? 2 :
+ Var->getType()->isBooleanType() ? 1 : 0));
break;
}
@@ -1218,15 +1231,16 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
/// There's a large number of things which don't need to be done along
/// this path.
Sema::OwningExprResult
-Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
+Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc) {
DeclContext *DC;
- if (!(DC = computeDeclContext(SS, false)) ||
- DC->isDependentContext() ||
- RequireCompleteDeclContext(SS))
+ if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0);
+ if (RequireCompleteDeclContext(SS, DC))
+ return ExprError();
+
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
LookupQualifiedName(R, DC);
@@ -1251,9 +1265,9 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
/// Returns a null sentinel to indicate trivial success.
Sema::OwningExprResult
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II,
- bool AllowBuiltinCreation) {
+ IdentifierInfo *II, bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -1264,7 +1278,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
// If we're in a class method, we don't normally want to look for
// ivars. But if we don't find anything else, and there's an
// ivar, that's an error.
- bool IsClassMethod = getCurMethodDecl()->isClassMethod();
+ bool IsClassMethod = CurMethod->isClassMethod();
bool LookForIvars;
if (Lookup.empty())
@@ -1276,7 +1290,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
ObjCInterfaceDecl *IFace = 0;
if (LookForIvars) {
- IFace = getCurMethodDecl()->getClassInterface();
+ IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
// Diagnose using an ivar in a class method.
@@ -1311,9 +1325,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
}
- } else if (getCurMethodDecl()->isInstanceMethod()) {
+ } else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
- ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+ ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) {
if (IV->getAccessControl() != ObjCIvarDecl::Private ||
@@ -1322,17 +1336,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
}
}
- // Needed to implement property "super.method" notation.
- if (Lookup.empty() && II->isStr("super")) {
- QualType T;
-
- if (getCurMethodDecl()->isInstanceMethod())
- T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType(
- getCurMethodDecl()->getClassInterface()));
- else
- T = Context.getObjCClassType();
- return Owned(new (Context) ObjCSuperExpr(Loc, T));
- }
if (Lookup.empty() && II && AllowBuiltinCreation) {
// FIXME. Consolidate this with similar code in LookupName.
if (unsigned BuiltinID = II->getBuiltinID()) {
@@ -1449,14 +1452,15 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// type of the object type, in which case we just ignore it.
// Otherwise build the appropriate casts.
if (IsDerivedFrom(FromRecordType, QRecordType)) {
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
- FromLoc, FromRange))
+ FromLoc, FromRange, &BasePath))
return true;
if (PointerConversions)
QType = Context.getPointerType(QType);
ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
FromType = QType;
FromRecordType = QRecordType;
@@ -1484,15 +1488,16 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// conversion is non-trivial.
if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) {
assert(IsDerivedFrom(FromRecordType, URecordType));
+ CXXBaseSpecifierArray BasePath;
if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
- FromLoc, FromRange))
+ FromLoc, FromRange, &BasePath))
return true;
-
+
QualType UType = URecordType;
if (PointerConversions)
UType = Context.getPointerType(UType);
ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
FromType = UType;
FromRecordType = URecordType;
}
@@ -1502,23 +1507,22 @@ Sema::PerformObjectMemberConversion(Expr *&From,
IgnoreAccess = true;
}
- if (CheckDerivedToBaseConversion(FromRecordType,
- DestRecordType,
- FromLoc,
- FromRange,
+ CXXBaseSpecifierArray BasePath;
+ if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType,
+ FromLoc, FromRange, &BasePath,
IgnoreAccess))
return true;
ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
- /*isLvalue=*/ !PointerConversions);
+ /*isLvalue=*/!PointerConversions, BasePath);
return false;
}
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
const CXXScopeSpec &SS, ValueDecl *Member,
- NamedDecl *FoundDecl, SourceLocation Loc,
- QualType Ty,
+ DeclAccessPair FoundDecl,
+ SourceLocation Loc, QualType Ty,
const TemplateArgumentListInfo *TemplateArgs = 0) {
NestedNameSpecifier *Qualifier = 0;
SourceRange QualifierRange;
@@ -2484,7 +2488,8 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
}
}
- assert(BaseType->isDependentType() || Name.isDependentName());
+ assert(BaseType->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS));
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
@@ -2510,11 +2515,8 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef,
if (!BaseExpr)
return DiagnoseInstanceReference(SemaRef, SS, R);
- // FIXME: this is an exceedingly lame diagnostic for some of the more
- // complicated cases here.
- DeclContext *DC = R.getRepresentativeDecl()->getDeclContext();
- SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual)
- << SS.getRange() << DC << BaseType;
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated)
+ << SS.getRange() << R.getRepresentativeDecl() << BaseType;
}
// Check whether the declarations we found through a nested-name
@@ -2545,7 +2547,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
// non-instance member, it's not an error.
- if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl()))
+ if (!BaseExpr && !(*I)->isCXXInstanceMember())
return false;
// Note that we use the DC of the decl, not the underlying decl.
@@ -2567,7 +2569,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
static bool
LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange, const RecordType *RTy,
- SourceLocation OpLoc, const CXXScopeSpec &SS) {
+ SourceLocation OpLoc, CXXScopeSpec &SS) {
RecordDecl *RDecl = RTy->getDecl();
if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
@@ -2580,7 +2582,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// nested-name-specifier.
DC = SemaRef.computeDeclContext(SS, false);
- if (SemaRef.RequireCompleteDeclContext(SS)) {
+ if (SemaRef.RequireCompleteDeclContext(SS, DC)) {
SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag)
<< SS.getRange() << DC;
return true;
@@ -2604,7 +2606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
- if (SemaRef.CorrectTypo(R, 0, &SS, DC) &&
+ if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
+ !R.empty() &&
(isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << R.getLookupName() << SS.getRange()
@@ -2624,7 +2627,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
Sema::OwningExprResult
Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name, SourceLocation NameLoc,
const TemplateArgumentListInfo *TemplateArgs) {
@@ -2675,13 +2678,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool SuppressQualifierCheck) {
Expr *BaseExpr = Base.takeAs<Expr>();
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
BaseType = BaseType->getAs<PointerType>()->getPointeeType();
}
+ R.setBaseObjectType(BaseType);
NestedNameSpecifier *Qualifier =
static_cast<NestedNameSpecifier*>(SS.getScopeRep());
@@ -2713,6 +2718,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
if ((SS.isSet() || !BaseExpr ||
(isa<CXXThisExpr>(BaseExpr) &&
cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ !SuppressQualifierCheck &&
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
@@ -2742,7 +2748,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
assert(R.isSingleResult());
- NamedDecl *FoundDecl = *R.begin();
+ DeclAccessPair FoundDecl = R.begin().getPair();
NamedDecl *MemberDecl = R.getFoundDecl();
// FIXME: diagnose the presence of template arguments now.
@@ -2756,7 +2762,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
// Handle the implicit-member-access case.
if (!BaseExpr) {
// If this is not an instance member, convert to a non-member access.
- if (!IsInstanceMember(MemberDecl))
+ if (!MemberDecl->isCXXInstanceMember())
return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
SourceLocation Loc = R.getNameLoc();
@@ -2833,16 +2839,18 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Owned(BaseExpr);
+ // We found something that we didn't expect. Complain.
if (isa<TypeDecl>(MemberDecl))
- return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
- << MemberName << int(IsArrow));
+ Diag(MemberLoc,diag::err_typecheck_member_reference_type)
+ << MemberName << BaseType << int(IsArrow);
+ else
+ Diag(MemberLoc, diag::err_typecheck_member_reference_unknown)
+ << MemberName << BaseType << int(IsArrow);
- // We found a declaration kind that we didn't expect. This is a
- // generic error message that tells the user that she can't refer
- // to this member with '.' or '->'.
- return ExprError(Diag(MemberLoc,
- diag::err_typecheck_member_reference_unknown)
- << MemberName << int(IsArrow));
+ Diag(MemberDecl->getLocation(), diag::note_member_declared_here)
+ << MemberName;
+ R.suppressDiagnostics();
+ return ExprError();
}
/// Look up the given member of the given non-type-dependent
@@ -2858,7 +2866,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
Sema::OwningExprResult
Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool &IsArrow, SourceLocation OpLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
DeclPtrTy ObjCImpDecl) {
assert(BaseExpr && "no base expression");
@@ -3060,7 +3068,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// Attempt to correct for typos in ivar names.
LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
LookupMemberName);
- if (CorrectTypo(Res, 0, 0, IDecl) &&
+ if (CorrectTypo(Res, 0, 0, IDecl, false, CTC_MemberLookup) &&
(IV = Res.getAsSingle<ObjCIvarDecl>())) {
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
@@ -3145,117 +3153,23 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel,
- OMD->getResultType(),
- OMD, OpLoc, MemberLoc,
- NULL, 0));
+ return Owned(ObjCMessageExpr::Create(Context,
+ OMD->getResultType().getNonReferenceType(),
+ OpLoc, BaseExpr, Sel,
+ OMD, NULL, 0, MemberLoc));
}
}
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
+
// Handle Objective-C property access, which is "Obj.property" where Obj is a
// pointer to a (potentially qualified) interface type.
- const ObjCObjectPointerType *OPT;
- if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) {
- const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
- ObjCInterfaceDecl *IFace = IFaceT->getDecl();
- IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
-
- // Search for a declared property first.
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
- QualType ResTy = PD->getType();
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
- ResTy = Getter->getResultType();
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
- MemberLoc, BaseExpr));
- }
- // Check protocols on qualified interfaces.
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
- // Check whether we can reference this property.
- if (DiagnoseUseOfDecl(PD, MemberLoc))
- return ExprError();
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
- MemberLoc, BaseExpr));
- }
- // If that failed, look for an "implicit" property by seeing if the nullary
- // selector is implemented.
-
- // FIXME: The logic for looking up nullary and unary selectors should be
- // shared with the code in ActOnInstanceMessage.
-
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
-
- // If this reference is in an @implementation, check for 'private' methods.
- if (!Getter)
- Getter = IFace->lookupPrivateInstanceMethod(Sel);
-
- // Look through local category implementations associated with the class.
- if (!Getter)
- Getter = IFace->getCategoryInstanceMethod(Sel);
- if (Getter) {
- // Check if we can reference this property.
- if (DiagnoseUseOfDecl(Getter, MemberLoc))
- return ExprError();
- }
- // If we found a getter then this may be a valid dot-reference, we
- // will look for the matching setter, in case it is needed.
- Selector SetterSel =
- SelectorTable::constructSetterName(PP.getIdentifierTable(),
- PP.getSelectorTable(), Member);
- ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
- if (!Setter) {
- // If this reference is in an @implementation, also check for 'private'
- // methods.
- Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
- }
- // Look through local category implementations associated with the class.
- if (!Setter)
- Setter = IFace->getCategoryInstanceMethod(SetterSel);
-
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
- return ExprError();
-
- if (Getter) {
- QualType PType;
- PType = Getter->getResultType();
- return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
- Setter, MemberLoc, BaseExpr));
- }
-
- // Attempt to correct for typos in property names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupOrdinaryName);
- if (CorrectTypo(Res, 0, 0, IFace, false, OPT) &&
- Res.getAsSingle<ObjCPropertyDecl>()) {
- Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
- << MemberName << BaseType << Res.getLookupName()
- << FixItHint::CreateReplacement(R.getNameLoc(),
- Res.getLookupName().getAsString());
- ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
- Diag(Property->getLocation(), diag::note_previous_decl)
- << Property->getDeclName();
-
- return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl);
- }
- Diag(MemberLoc, diag::err_property_not_found)
- << MemberName << BaseType;
- if (Setter && !Getter)
- Diag(Setter->getLocation(), diag::note_getter_unavailable)
- << MemberName << BaseExpr->getSourceRange();
- return ExprError();
- }
+ if (!IsArrow)
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc);
// Handle the following exceptional case (*Obj).isa.
if (!IsArrow &&
@@ -3296,7 +3210,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Id,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
@@ -3323,7 +3237,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
- if (Base->getType()->isDependentType() || Name.isDependentName()) {
+ if (Base->getType()->isDependentType() || Name.isDependentName() ||
+ isDependentScopeSpecifier(SS)) {
Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
@@ -3334,6 +3249,21 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
if (TemplateArgs) {
// Re-use the lookup done for the template name.
DecomposeTemplateName(R, Id);
+
+ // Re-derive the naming class.
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier
+ = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ if (const Type *Ty = Qualifier->getAsType())
+ if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ } else {
+ QualType BaseType = Base->getType();
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>())
+ BaseType = Ptr->getPointeeType();
+ if (CXXRecordDecl *NamingClass = BaseType->getAsCXXRecordDecl())
+ R.setNamingClass(NamingClass);
+ }
} else {
Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
SS, ObjCImpDecl);
@@ -3443,7 +3373,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (NumArgs < NumArgsInProto) {
if (!FDecl || NumArgs < FDecl->getMinRequiredArguments())
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args)
- << Fn->getType()->isBlockPointerType() << Fn->getSourceRange();
+ << Fn->getType()->isBlockPointerType()
+ << NumArgsInProto << NumArgs << Fn->getSourceRange();
Call->setNumArgs(Context, NumArgsInProto);
}
@@ -3453,7 +3384,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
if (!Proto->isVariadic()) {
Diag(Args[NumArgsInProto]->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << Fn->getType()->isBlockPointerType() << Fn->getSourceRange()
+ << Fn->getType()->isBlockPointerType()
+ << NumArgsInProto << NumArgs << Fn->getSourceRange()
<< SourceRange(Args[NumArgsInProto]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
// This deletes the extra arguments.
@@ -3613,7 +3545,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// declarations (all methods or method templates) or a single
// method template.
assert((MemE->getNumDecls() > 1) ||
- isa<FunctionTemplateDecl>(*MemE->decls_begin()));
+ isa<FunctionTemplateDecl>(
+ (*MemE->decls_begin())->getUnderlyingDecl()));
(void)MemE;
return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
@@ -3666,7 +3599,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Expr *NakedFn = Fn->IgnoreParens();
if (isa<UnresolvedLookupExpr>(NakedFn)) {
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn);
- return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs,
+ return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
}
@@ -3851,8 +3784,8 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
- InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit,
- RBraceLoc);
+ InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList,
+ NumInit, RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
return Owned(E);
}
@@ -3895,11 +3828,11 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context,
/// CheckCastTypes - Check type constraints for casting between types.
bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
CastExpr::CastKind& Kind,
- CXXMethodDecl *& ConversionDecl,
+ CXXBaseSpecifierArray &BasePath,
bool FunctionalStyle) {
if (getLangOptions().CPlusPlus)
- return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle,
- ConversionDecl);
+ return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath,
+ FunctionalStyle);
DefaultFunctionArrayLvalueConversion(castExpr);
@@ -3962,9 +3895,6 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr,
if (castExpr->getType()->isVectorType())
return CheckVectorCast(TyR, castExpr->getType(), castType, Kind);
- if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr))
- return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR;
-
if (isa<ObjCSelectorExpr>(castExpr))
return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr);
@@ -4062,27 +3992,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
SourceLocation RParenLoc, ExprArg Op) {
Expr *castExpr = static_cast<Expr*>(Op.get());
- CXXMethodDecl *Method = 0;
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ CXXBaseSpecifierArray BasePath;
if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
- Kind, Method))
+ Kind, BasePath))
return ExprError();
- if (Method) {
- // FIXME: preserve type source info here
- OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(),
- Kind, Method, move(Op));
-
- if (CastArg.isInvalid())
- return ExprError();
-
- castExpr = CastArg.takeAs<Expr>();
- } else {
- Op.release();
- }
-
+ Op.release();
return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
- Kind, castExpr, Ty,
+ Kind, castExpr, BasePath, Ty,
LParenLoc, RParenLoc));
}
@@ -4126,7 +4044,8 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
// FIXME: This means that pretty-printing the final AST will produce curly
// braces instead of the original commas.
Op.release();
- InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
+ InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc,
+ &initExprs[0],
initExprs.size(), RParenLoc);
E->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E));
@@ -4856,7 +4775,7 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
QualType UnionType, FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
- InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(),
+ InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
&E, 1,
SourceLocation());
Initializer->setType(UnionType);
@@ -5419,11 +5338,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
DiagRuntimeBehavior(Loc,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange()
- << FixItHint::CreateReplacement(SourceRange(Loc), ", ")
- << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(")
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()),
- resultComparison));
+ << literalString->getSourceRange());
}
}
@@ -5480,7 +5395,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(lex, rex,
+ QualType T = FindCompositePointerType(Loc, lex, rex,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
@@ -5553,7 +5468,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// that is the union of the cv-qualification signatures of the operand
// types.
bool NonStandardCompositeType = false;
- QualType T = FindCompositePointerType(lex, rex,
+ QualType T = FindCompositePointerType(Loc, lex, rex,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (T.isNull()) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
@@ -5944,7 +5859,7 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) {
/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
- bool isInc) {
+ bool isInc, bool isPrefix) {
if (Op->isTypeDependent())
return Context.DependentTy;
@@ -6007,7 +5922,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, *this))
return QualType();
- return ResType;
+ // In C++, a prefix increment is the same type as the operand. Otherwise
+ // (in C or with postfix), the increment is the unqualified type of the
+ // operand.
+ return isPrefix && getLangOptions().CPlusPlus
+ ? ResType : ResType.getUnqualifiedType();
}
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@@ -6395,33 +6314,37 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
- SourceRange ParenRange,
- const PartialDiagnostic &SecondPD,
+ const PartialDiagnostic &FirstNote,
+ SourceRange FirstParenRange,
+ const PartialDiagnostic &SecondNote,
SourceRange SecondParenRange) {
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
- if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, PD);
+ Self.Diag(Loc, PD);
+
+ if (!FirstNote.getDiagID())
+ return;
+
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
+ if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just return.
return;
}
- Self.Diag(Loc, PD)
- << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ Self.Diag(Loc, FirstNote)
+ << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
- if (!SecondPD.getDiagID())
+ if (!SecondNote.getDiagID())
return;
EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
// warning/error and return.
- Self.Diag(Loc, SecondPD);
+ Self.Diag(Loc, SecondNote);
return;
}
- Self.Diag(Loc, SecondPD)
+ Self.Diag(Loc, SecondNote)
<< FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
<< FixItHint::CreateInsertion(EndLoc, ")");
}
@@ -6455,19 +6378,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
- lhs->getSourceRange(),
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
+ SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()),
+ Self.PDiag(diag::note_precedence_bitwise_silence)
+ << BinOp::getOpcodeStr(lhsopc),
+ lhs->getSourceRange());
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
- rhs->getSourceRange(),
Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
- SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
+ SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()),
+ Self.PDiag(diag::note_precedence_bitwise_silence)
+ << BinOp::getOpcodeStr(rhsopc),
+ rhs->getSourceRange());
}
/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky
@@ -6532,14 +6459,16 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UnaryOperator::OffsetOf:
assert(false && "Invalid unary operator");
break;
-
+
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
resultType = CheckIncrementDecrementOperand(Input, OpLoc,
Opc == UnaryOperator::PreInc ||
- Opc == UnaryOperator::PostInc);
+ Opc == UnaryOperator::PostInc,
+ Opc == UnaryOperator::PreInc ||
+ Opc == UnaryOperator::PreDec);
break;
case UnaryOperator::AddrOf:
resultType = CheckAddressOfOperand(Input, OpLoc);
@@ -6690,6 +6619,157 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt,
return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
}
+Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ TypeSourceInfo *TInfo,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ QualType ArgTy = TInfo->getType();
+ bool Dependent = ArgTy->isDependentType();
+ SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange();
+
+ // We must have at least one component that refers to the type, and the first
+ // one is known to be a field designator. Verify that the ArgTy represents
+ // a struct/union/class.
+ if (!Dependent && !ArgTy->isRecordType())
+ return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type)
+ << ArgTy << TypeRange);
+
+ // Type must be complete per C99 7.17p3 because a declaring a variable
+ // with an incomplete type would be ill-formed.
+ if (!Dependent
+ && RequireCompleteType(BuiltinLoc, ArgTy,
+ PDiag(diag::err_offsetof_incomplete_type)
+ << TypeRange))
+ return ExprError();
+
+ // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
+ // GCC extension, diagnose them.
+ // FIXME: This diagnostic isn't actually visible because the location is in
+ // a system header!
+ if (NumComponents != 1)
+ Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
+ << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+
+ bool DidWarnAboutNonPOD = false;
+ QualType CurrentType = ArgTy;
+ typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
+ llvm::SmallVector<OffsetOfNode, 4> Comps;
+ llvm::SmallVector<Expr*, 4> Exprs;
+ for (unsigned i = 0; i != NumComponents; ++i) {
+ const OffsetOfComponent &OC = CompPtr[i];
+ if (OC.isBrackets) {
+ // Offset of an array sub-field. TODO: Should we allow vector elements?
+ if (!CurrentType->isDependentType()) {
+ const ArrayType *AT = Context.getAsArrayType(CurrentType);
+ if(!AT)
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
+ << CurrentType);
+ CurrentType = AT->getElementType();
+ } else
+ CurrentType = Context.DependentTy;
+
+ // The expression must be an integral expression.
+ // FIXME: An integral constant expression?
+ Expr *Idx = static_cast<Expr*>(OC.U.E);
+ if (!Idx->isTypeDependent() && !Idx->isValueDependent() &&
+ !Idx->getType()->isIntegerType())
+ return ExprError(Diag(Idx->getLocStart(),
+ diag::err_typecheck_subscript_not_integer)
+ << Idx->getSourceRange());
+
+ // Record this array index.
+ Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd));
+ Exprs.push_back(Idx);
+ continue;
+ }
+
+ // Offset of a field.
+ if (CurrentType->isDependentType()) {
+ // We have the offset of a field, but we can't look into the dependent
+ // type. Just record the identifier of the field.
+ Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd));
+ CurrentType = Context.DependentTy;
+ continue;
+ }
+
+ // We need to have a complete type to look into.
+ if (RequireCompleteType(OC.LocStart, CurrentType,
+ diag::err_offsetof_incomplete_type))
+ return ExprError();
+
+ // Look for the designated field.
+ const RecordType *RC = CurrentType->getAs<RecordType>();
+ if (!RC)
+ return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
+ << CurrentType);
+ RecordDecl *RD = RC->getDecl();
+
+ // C++ [lib.support.types]p5:
+ // The macro offsetof accepts a restricted set of type arguments in this
+ // International Standard. type shall be a POD structure or a POD union
+ // (clause 9).
+ if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
+ DiagRuntimeBehavior(BuiltinLoc,
+ PDiag(diag::warn_offsetof_non_pod_type)
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << CurrentType))
+ DidWarnAboutNonPOD = true;
+ }
+
+ // Look for the field.
+ LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
+ LookupQualifiedName(R, RD);
+ FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
+ if (!MemberDecl)
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart,
+ OC.LocEnd));
+
+ // C99 7.17p3:
+ // (If the specified member is a bit-field, the behavior is undefined.)
+ //
+ // We diagnose this as an error.
+ if (MemberDecl->getBitWidth()) {
+ Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+ << MemberDecl->getDeclName()
+ << SourceRange(BuiltinLoc, RParenLoc);
+ Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+ return ExprError();
+ }
+
+ // If the member was found in a base class, introduce OffsetOfNodes for
+ // the base class indirections.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(CurrentType,
+ Context.getTypeDeclType(MemberDecl->getParent()),
+ Paths)) {
+ CXXBasePath &Path = Paths.front();
+ for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end();
+ B != BEnd; ++B)
+ Comps.push_back(OffsetOfNode(B->Base));
+ }
+
+ if (cast<RecordDecl>(MemberDecl->getDeclContext())->
+ isAnonymousStructOrUnion()) {
+ llvm::SmallVector<FieldDecl*, 4> Path;
+ BuildAnonymousStructUnionMemberPath(MemberDecl, Path);
+ unsigned n = Path.size();
+ for (int j = n - 1; j > -1; --j)
+ Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd));
+ } else {
+ Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd));
+ }
+ CurrentType = MemberDecl->getType().getNonReferenceType();
+ }
+
+ return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc,
+ TInfo, Comps.data(), Comps.size(),
+ Exprs.data(), Exprs.size(), RParenLoc));
+}
+
Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
SourceLocation BuiltinLoc,
SourceLocation TypeLoc,
@@ -6697,45 +6777,56 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
OffsetOfComponent *CompPtr,
unsigned NumComponents,
SourceLocation RPLoc) {
- // FIXME: This function leaks all expressions in the offset components on
- // error.
- // FIXME: Preserve type source info.
- QualType ArgTy = GetTypeFromParser(argty);
- assert(!ArgTy.isNull() && "Missing type argument!");
- bool Dependent = ArgTy->isDependentType();
+ TypeSourceInfo *ArgTInfo;
+ QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo);
+ if (ArgTy.isNull())
+ return ExprError();
+ if (getLangOptions().CPlusPlus) {
+ if (!ArgTInfo)
+ ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc);
+
+ return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents,
+ RPLoc);
+ }
+
+ // FIXME: The code below is marked for death, once we have proper CodeGen
+ // support for non-constant OffsetOf expressions.
+
+ bool Dependent = ArgTy->isDependentType();
+
// We must have at least one component that refers to the type, and the first
// one is known to be a field designator. Verify that the ArgTy represents
// a struct/union/class.
if (!Dependent && !ArgTy->isRecordType())
return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy);
-
+
// FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
// with an incomplete type would be illegal.
-
+
// Otherwise, create a null pointer as the base, and iteratively process
// the offsetof designators.
QualType ArgTyPtr = Context.getPointerType(ArgTy);
Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr);
Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
ArgTy, SourceLocation());
-
+
// offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
// GCC extension, diagnose them.
// FIXME: This diagnostic isn't actually visible because the location is in
// a system header!
if (NumComponents != 1)
Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
- << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
-
+ << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+
if (!Dependent) {
bool DidWarnAboutNonPOD = false;
-
+
if (RequireCompleteType(TypeLoc, Res->getType(),
diag::err_offsetof_incomplete_type))
return ExprError();
-
+
// FIXME: Dependent case loses a lot of information here. And probably
// leaks like a sieve.
for (unsigned i = 0; i != NumComponents; ++i) {
@@ -6746,71 +6837,83 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
if (!AT) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
- << Res->getType());
+ << Res->getType());
}
-
+
// FIXME: C++: Verify that operator[] isn't overloaded.
-
+
// Promote the array so it looks more like a normal array subscript
// expression.
DefaultFunctionArrayLvalueConversion(Res);
-
+
// C99 6.5.2.1p1
Expr *Idx = static_cast<Expr*>(OC.U.E);
// FIXME: Leaks Res
if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
return ExprError(Diag(Idx->getLocStart(),
diag::err_typecheck_subscript_not_integer)
- << Idx->getSourceRange());
-
+ << Idx->getSourceRange());
+
Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
OC.LocEnd);
continue;
}
-
+
const RecordType *RC = Res->getType()->getAs<RecordType>();
if (!RC) {
Res->Destroy(Context);
return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
- << Res->getType());
+ << Res->getType());
}
-
+
// Get the decl corresponding to this.
RecordDecl *RD = RC->getDecl();
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
DiagRuntimeBehavior(BuiltinLoc,
PDiag(diag::warn_offsetof_non_pod_type)
- << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
- << Res->getType()))
+ << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+ << Res->getType()))
DidWarnAboutNonPOD = true;
}
-
+
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
LookupQualifiedName(R, RD);
-
+
FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
// FIXME: Leaks Res
if (!MemberDecl)
return ExprError(Diag(BuiltinLoc, diag::err_no_member)
- << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
-
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
+
+ // C99 7.17p3:
+ // (If the specified member is a bit-field, the behavior is undefined.)
+ //
+ // We diagnose this as an error.
+ if (MemberDecl->getBitWidth()) {
+ Diag(OC.LocEnd, diag::err_offsetof_bitfield)
+ << MemberDecl->getDeclName()
+ << SourceRange(BuiltinLoc, RPLoc);
+ Diag(MemberDecl->getLocation(), diag::note_bitfield_decl);
+ return ExprError();
+ }
+
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
Res = BuildAnonymousStructUnionMemberReference(
- OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
+ OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
PerformObjectMemberConversion(Res, /*Qualifier=*/0,
*R.begin(), MemberDecl);
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
- MemberDecl->getType().getNonReferenceType());
+ MemberDecl->getType().getNonReferenceType());
}
}
}
-
+
return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
Context.getSizeType(), BuiltinLoc));
}
@@ -7127,7 +7230,7 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
-static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
+static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
Expr *SrcExpr, FixItHint &Hint) {
if (!SemaRef.getLangOptions().ObjC1)
return;
@@ -7155,7 +7258,11 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SourceLocation Loc,
QualType DstType, QualType SrcType,
- Expr *SrcExpr, AssignmentAction Action) {
+ Expr *SrcExpr, AssignmentAction Action,
+ bool *Complained) {
+ if (Complained)
+ *Complained = false;
+
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
@@ -7218,8 +7325,30 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
break;
}
- Diag(Loc, DiagKind) << DstType << SrcType << Action
+ QualType FirstType, SecondType;
+ switch (Action) {
+ case AA_Assigning:
+ case AA_Initializing:
+ // The destination type comes first.
+ FirstType = DstType;
+ SecondType = SrcType;
+ break;
+
+ case AA_Returning:
+ case AA_Passing:
+ case AA_Converting:
+ case AA_Sending:
+ case AA_Casting:
+ // The source type comes first.
+ FirstType = SrcType;
+ SecondType = DstType;
+ break;
+ }
+
+ Diag(Loc, DiagKind) << FirstType << SecondType << Action
<< SrcExpr->getSourceRange() << Hint;
+ if (Complained)
+ *Complained = true;
return isInvalid;
}
@@ -7328,8 +7457,13 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and
// -Wunused-parameters)
if (isa<ParmVarDecl>(D) ||
- (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod()))
+ (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) {
D->setUsed(true);
+ return;
+ }
+
+ if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
+ return;
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
@@ -7375,7 +7509,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed())
- DefineImplicitOverloadedAssign(Loc, MethodDecl);
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
}
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -7536,12 +7670,12 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
SourceLocation Open = E->getSourceRange().getBegin();
SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd());
- Diag(Loc, diagnostic)
- << E->getSourceRange()
- << FixItHint::CreateInsertion(Open, "(")
- << FixItHint::CreateInsertion(Close, ")");
+ Diag(Loc, diagnostic) << E->getSourceRange();
Diag(Loc, diag::note_condition_assign_to_comparison)
<< FixItHint::CreateReplacement(Loc, "==");
+ Diag(Loc, diag::note_condition_assign_silence)
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 501c877c3ddd..425fc2d15aa5 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -29,7 +29,7 @@ using namespace clang;
Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II,
SourceLocation NameLoc,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
TypeTy *ObjectTypePtr,
bool EnteringContext) {
// Determine where to perform name lookup.
@@ -261,7 +261,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Range = SourceRange(NameLoc);
}
- return CheckTypenameType(NNS, II, Range).getAsOpaquePtr();
+ return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr();
}
if (ObjectTypePtr)
@@ -273,89 +273,107 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
return 0;
}
-/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
+/// \brief Build a C++ typeid expression with a type operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
+ SourceLocation RParenLoc) {
+ // C++ [expr.typeid]p4:
+ // The top-level cv-qualifiers of the lvalue expression or the type-id
+ // that is the operand of typeid are always ignored.
+ // If the type of the type-id is a class type or a reference to a class
+ // type, the class shall be completely-defined.
+ QualType T = Operand->getType().getNonReferenceType();
+ if (T->getAs<RecordType>() &&
+ RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
+ return ExprError();
+
+ return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+ Operand,
+ SourceRange(TypeidLoc, RParenLoc)));
+}
+
+/// \brief Build a C++ typeid expression with an expression operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ ExprArg Operand,
+ SourceLocation RParenLoc) {
+ bool isUnevaluatedOperand = true;
+ Expr *E = static_cast<Expr *>(Operand.get());
+ if (E && !E->isTypeDependent()) {
+ QualType T = E->getType();
+ 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(TypeidLoc, 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;
+ }
+
+ // C++ [expr.typeid]p4:
+ // [...] If the type of the type-id is a reference to a possibly
+ // cv-qualified type, the result of the typeid expression refers to a
+ // std::type_info object representing the cv-unqualified referenced
+ // type.
+ if (T.hasQualifiers()) {
+ ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
+ E->isLvalue(Context));
+ Operand.release();
+ Operand = Owned(E);
+ }
+ }
+
+ // If this is an unevaluated operand, clear out the set of
+ // declaration references we have been computing and eliminate any
+ // temporaries introduced in its computation.
+ if (isUnevaluatedOperand)
+ ExprEvalContexts.back().Context = Unevaluated;
+
+ return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+ Operand.takeAs<Expr>(),
+ SourceRange(TypeidLoc, RParenLoc)));
+}
+
+/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression);
Action::OwningExprResult
Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
+ // Find the std::type_info type.
if (!StdNamespace)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
- if (isType) {
- // C++ [expr.typeid]p4:
- // The top-level cv-qualifiers of the lvalue expression or the type-id
- // that is the operand of typeid are always ignored.
- // FIXME: Preserve type source info.
- // FIXME: Preserve the type before we stripped the cv-qualifiers?
- QualType T = GetTypeFromParser(TyOrExpr);
- if (T.isNull())
- return ExprError();
-
- // C++ [expr.typeid]p4:
- // If the type of the type-id is a class type or a reference to a class
- // type, the class shall be completely-defined.
- QualType CheckT = T;
- if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>())
- CheckT = RefType->getPointeeType();
-
- if (CheckT->getAs<RecordType>() &&
- RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid))
- return ExprError();
-
- TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr();
- }
-
IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
LookupQualifiedName(R, StdNamespace);
RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>();
if (!TypeInfoRecordDecl)
return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+
QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
+
+ if (isType) {
+ // The operand is a type; handle it as such.
+ TypeSourceInfo *TInfo = 0;
+ QualType T = GetTypeFromParser(TyOrExpr, &TInfo);
+ if (T.isNull())
+ return ExprError();
+
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc);
- if (!isType) {
- bool isUnevaluatedOperand = true;
- Expr *E = static_cast<Expr *>(TyOrExpr);
- if (E && !E->isTypeDependent()) {
- QualType T = E->getType();
- 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;
- }
-
- // C++ [expr.typeid]p4:
- // [...] If the type of the type-id is a reference to a possibly
- // cv-qualified type, the result of the typeid expression refers to a
- // std::type_info object representing the cv-unqualified referenced
- // type.
- if (T.hasQualifiers()) {
- ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
- E->isLvalue(Context));
- TyOrExpr = E;
- }
- }
-
- // If this is an unevaluated operand, clear out the set of
- // declaration references we have been computing and eliminate any
- // temporaries introduced in its computation.
- if (isUnevaluatedOperand)
- ExprEvalContexts.back().Context = Unevaluated;
+ return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc);
}
- return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
- TypeInfoType.withConst(),
- SourceRange(OpLoc, RParenLoc)));
+ // The operand is an expression.
+ return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc);
}
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
@@ -399,10 +417,10 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
QualType Ty = E->getType();
- int isPointer = 0;
+ bool isPointer = false;
if (const PointerType* Ptr = Ty->getAs<PointerType>()) {
Ty = Ptr->getPointeeType();
- isPointer = 1;
+ isPointer = true;
}
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
@@ -411,20 +429,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) {
<< E->getSourceRange()))
return true;
- // FIXME: This is just a hack to mark the copy constructor referenced.
- // This should go away when the next FIXME is fixed.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT)
- return false;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
- return false;
- CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0);
- MarkDeclarationReferenced(ThrowLoc, CopyCtor);
+ if (RequireNonAbstractType(ThrowLoc, E->getType(),
+ PDiag(diag::err_throw_abstract_type)
+ << E->getSourceRange()))
+ return true;
}
- // FIXME: Construct a temporary here.
+ // Initialize the exception result. This implicitly weeds out
+ // abstract types or types with inaccessible copy constructors.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeException(ThrowLoc, E->getType());
+ OwningExprResult Res = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(E));
+ if (Res.isInvalid())
+ return true;
+ E = Res.takeAs<Expr>();
return false;
}
@@ -499,25 +519,17 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
//
if (NumExprs == 1) {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- CXXMethodDecl *Method = 0;
- if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method,
+ CXXBaseSpecifierArray BasePath;
+ if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath,
/*FunctionalStyle=*/true))
return ExprError();
exprs.release();
- if (Method) {
- OwningExprResult CastArg
- = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(),
- Kind, Method, Owned(Exprs[0]));
- if (CastArg.isInvalid())
- return ExprError();
-
- Exprs[0] = CastArg.takeAs<Expr>();
- }
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
TInfo, TyBeginLoc, Kind,
- Exprs[0], RParenLoc));
+ Exprs[0], BasePath,
+ RParenLoc));
}
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -708,10 +720,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
OperatorNew->getType()->getAs<FunctionProtoType>();
VariadicCallType CallType =
Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
- bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew,
- Proto, 1, PlaceArgs, NumPlaceArgs,
- AllPlaceArgs, CallType);
- if (Invalid)
+
+ if (GatherArgumentsForCall(PlacementLParen, OperatorNew,
+ Proto, 1, PlaceArgs, NumPlaceArgs,
+ AllPlaceArgs, CallType))
return ExprError();
NumPlaceArgs = AllPlaceArgs.size();
@@ -726,6 +738,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this);
+ // Array 'new' can't have any initializers.
+ if (NumConsArgs && ArraySize) {
+ SourceRange InitRange(ConsArgs[0]->getLocStart(),
+ ConsArgs[NumConsArgs - 1]->getLocEnd());
+
+ Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
+ return ExprError();
+ }
+
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
// C++0x [expr.new]p15:
@@ -892,6 +913,13 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
return true;
}
+ // We don't need an operator delete if we're running under
+ // -fno-exceptions.
+ if (!getLangOptions().Exceptions) {
+ OperatorDelete = 0;
+ return false;
+ }
+
// FindAllocationOverload can change the passed in arguments, so we need to
// copy them back.
if (NumPlaceArgs > 0)
@@ -1214,7 +1242,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FunctionType::ExtInfo());
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
- FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
+ FnType, /*TInfo=*/0, FunctionDecl::None,
+ FunctionDecl::None, false, true);
Alloc->setImplicit();
if (AddMallocAttr)
@@ -1222,6 +1251,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
0, Argument, /*TInfo=*/0,
+ VarDecl::None,
VarDecl::None, 0);
Alloc->setParams(&Param, 1);
@@ -1258,8 +1288,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
F != FEnd; ++F) {
- Diag((*F)->getLocation(),
- diag::note_delete_member_function_declared_here)
+ Diag((*F)->getLocation(), diag::note_member_declared_here)
<< Name;
}
@@ -1396,6 +1425,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
}
+ MarkDeclarationReferenced(StartLoc, OperatorDelete);
+
// FIXME: Check access and ambiguity of operator delete and destructor.
}
@@ -1469,45 +1500,43 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
return false;
}
-/// PerformImplicitConversion - Perform an implicit conversion of the
-/// expression From to the type ToType. Returns true if there was an
-/// error, false otherwise. The expression From is replaced with the
-/// converted expression. Flavor is the kind of conversion we're
-/// performing, used in the error message. If @p AllowExplicit,
-/// explicit user-defined conversions are permitted. @p Elidable should be true
-/// when called for copies which may be elided (C++ 12.8p15). C++0x overload
-/// resolution works differently in that case.
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit,
- bool Elidable) {
- ImplicitConversionSequence ICS;
- return PerformImplicitConversion(From, ToType, Action, AllowExplicit,
- Elidable, ICS);
-}
-
-bool
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
- AssignmentAction Action, bool AllowExplicit,
- bool Elidable,
- ImplicitConversionSequence& ICS) {
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- if (Elidable && getLangOptions().CPlusPlus0x) {
- ICS = TryImplicitConversion(From, ToType,
- /*SuppressUserConversions=*/false,
- AllowExplicit,
- /*ForceRValue=*/true,
- /*InOverloadResolution=*/false);
- }
- if (ICS.isBad()) {
- ICS = TryImplicitConversion(From, ToType,
- /*SuppressUserConversions=*/false,
- AllowExplicit,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- }
- return PerformImplicitConversion(From, ToType, ICS, Action);
-}
+static Sema::OwningExprResult BuildCXXCastArgument(Sema &S,
+ SourceLocation CastLoc,
+ QualType Ty,
+ CastExpr::CastKind Kind,
+ CXXMethodDecl *Method,
+ Sema::ExprArg Arg) {
+ Expr *From = Arg.takeAs<Expr>();
+
+ switch (Kind) {
+ default: assert(0 && "Unhandled cast kind!");
+ case CastExpr::CK_ConstructorConversion: {
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+
+ if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
+ Sema::MultiExprArg(S, (void **)&From, 1),
+ CastLoc, ConstructorArgs))
+ return S.ExprError();
+
+ Sema::OwningExprResult Result =
+ S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ move_arg(ConstructorArgs));
+ if (Result.isInvalid())
+ return S.ExprError();
+
+ return S.MaybeBindToTemporary(Result.takeAs<Expr>());
+ }
+
+ case CastExpr::CK_UserDefinedConversion: {
+ assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
+
+ // Create an implicit call expr that calls it.
+ // FIXME: pass the FoundDecl for the user-defined conversion here
+ CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method);
+ return S.MaybeBindToTemporary(CE);
+ }
+ }
+}
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType using the pre-computed implicit
@@ -1560,7 +1589,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
}
OwningExprResult CastArg
- = BuildCXXCastArgument(From->getLocStart(),
+ = BuildCXXCastArgument(*this,
+ From->getLocStart(),
ToType.getNonReferenceType(),
CastKind, cast<CXXMethodDecl>(FD),
Owned(From));
@@ -1639,6 +1669,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return false;
}
+ // Resolve overloaded function references.
+ if (Context.hasSameType(FromType, Context.OverloadTy)) {
+ DeclAccessPair Found;
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
+ true, Found);
+ if (!Fn)
+ return true;
+
+ if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+ return true;
+
+ From = FixOverloadedFunctionReference(From, Found, Fn);
+ FromType = From->getType();
+ }
+
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -1652,25 +1697,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
case ICK_Function_To_Pointer:
- if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
- true, Found);
- if (!Fn)
- return true;
-
- if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
- return true;
-
- From = FixOverloadedFunctionReference(From, Found, Fn);
- FromType = From->getType();
-
- // If there's already an address-of operator in the expression, we have
- // the right type already, and the code below would just introduce an
- // invalid additional pointer level.
- if (FromType->isPointerType() || FromType->isMemberFunctionPointerType())
- break;
- }
FromType = Context.getPointerType(FromType);
ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
@@ -1741,19 +1767,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess))
return true;
- ImpCastExprToType(From, ToType, Kind);
+ ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath);
break;
}
case ICK_Pointer_Member: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
- if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess))
+ CXXBaseSpecifierArray BasePath;
+ if (CheckMemberPointerConversion(From, ToType, Kind, BasePath,
+ IgnoreBaseAccess))
return true;
if (CheckExceptionSpecCompatibility(From, ToType))
return true;
- ImpCastExprToType(From, ToType, Kind);
+ ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath);
break;
}
case ICK_Boolean_Conversion: {
@@ -1769,7 +1798,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
if (CheckDerivedToBaseConversion(From->getType(),
ToType.getNonReferenceType(),
From->getLocStart(),
- From->getSourceRange(),
+ From->getSourceRange(), 0,
IgnoreBaseAccess))
return true;
ImpCastExprToType(From, ToType.getNonReferenceType(),
@@ -1790,8 +1819,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
// references.
ImpCastExprToType(From, ToType.getNonReferenceType(),
- CastExpr::CK_NoOp,
- ToType->isLValueReferenceType());
+ CastExpr::CK_NoOp, ToType->isLValueReferenceType());
if (SCS.DeprecatedStringLiteralToCharPtr)
Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
@@ -1847,6 +1875,9 @@ QualType Sema::CheckPointerToMemberOperands(
QualType Class(MemPtr->getClass(), 0);
+ if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete))
+ return QualType();
+
// C++ 5.5p2
// [...] to its first operand, which shall be of class T or of a class of
// which T is an unambiguous and accessible base class. [p3: a pointer to
@@ -1864,7 +1895,12 @@ QualType Sema::CheckPointerToMemberOperands(
}
if (!Context.hasSameUnqualifiedType(Class, LType)) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ // If we want to check the hierarchy, we need a complete type.
+ if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs)
+ << OpSpelling << (int)isIndirect)) {
+ return QualType();
+ }
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
// FIXME: Would it be useful to print full ambiguity paths, or is that
// overkill?
@@ -1877,7 +1913,11 @@ QualType Sema::CheckPointerToMemberOperands(
// Cast LHS to type of use.
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid;
- ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue);
+
+ CXXBaseSpecifierArray BasePath;
+ BuildBasePathArray(Paths, BasePath);
+ ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue,
+ BasePath);
}
if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) {
@@ -2201,7 +2241,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// shall match the cv-qualification of either the second or the third
// operand. The result is of the common type.
bool NonStandardCompositeType = false;
- QualType Composite = FindCompositePointerType(LHS, RHS,
+ QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS,
isSFINAEContext()? 0 : &NonStandardCompositeType);
if (!Composite.isNull()) {
if (NonStandardCompositeType)
@@ -2231,11 +2271,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
/// type and returns it.
/// It does not emit diagnostics.
///
+/// \param Loc The location of the operator requiring these two expressions to
+/// be converted to the composite pointer type.
+///
/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
/// a non-standard (but still sane) composite type to which both expressions
/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
/// will be set true.
-QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
+QualType Sema::FindCompositePointerType(SourceLocation Loc,
+ Expr *&E1, Expr *&E2,
bool *NonStandardCompositeType) {
if (NonStandardCompositeType)
*NonStandardCompositeType = false;
@@ -2372,48 +2416,70 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
}
}
- ImplicitConversionSequence E1ToC1 =
- TryImplicitConversion(E1, Composite1,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- ImplicitConversionSequence E2ToC1 =
- TryImplicitConversion(E2, Composite1,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
-
- bool ToC2Viable = false;
- ImplicitConversionSequence E1ToC2, E2ToC2;
- if (Context.getCanonicalType(Composite1) !=
- Context.getCanonicalType(Composite2)) {
- E1ToC2 = TryImplicitConversion(E1, Composite2,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- E2ToC2 = TryImplicitConversion(E2, Composite2,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
- }
-
- bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
- if (ToC1Viable && !ToC2Viable) {
- if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
- !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
- return Composite1;
- }
- if (ToC2Viable && !ToC1Viable) {
- if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) &&
- !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting))
- return Composite2;
+ // Try to convert to the first composite pointer type.
+ InitializedEntity Entity1
+ = InitializedEntity::InitializeTemporary(Composite1);
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(Loc, SourceLocation());
+ InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1);
+ InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1);
+
+ if (E1ToC1 && E2ToC1) {
+ // Conversion to Composite1 is viable.
+ if (!Context.hasSameType(Composite1, Composite2)) {
+ // Composite2 is a different type from Composite1. Check whether
+ // Composite2 is also viable.
+ InitializedEntity Entity2
+ = InitializedEntity::InitializeTemporary(Composite2);
+ InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1);
+ InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1);
+ if (E1ToC2 && E2ToC2) {
+ // Both Composite1 and Composite2 are viable and are different;
+ // this is an ambiguity.
+ return QualType();
+ }
+ }
+
+ // Convert E1 to Composite1
+ OwningExprResult E1Result
+ = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E1,1));
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.takeAs<Expr>();
+
+ // Convert E2 to Composite1
+ OwningExprResult E2Result
+ = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E2,1));
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.takeAs<Expr>();
+
+ return Composite1;
}
- return QualType();
+
+ // Check whether Composite2 is viable.
+ InitializedEntity Entity2
+ = InitializedEntity::InitializeTemporary(Composite2);
+ InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1);
+ InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1);
+ if (!E1ToC2 || !E2ToC2)
+ return QualType();
+
+ // Convert E1 to Composite2
+ OwningExprResult E1Result
+ = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E1, 1));
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.takeAs<Expr>();
+
+ // Convert E2 to Composite2
+ OwningExprResult E2Result
+ = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E2, 1));
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.takeAs<Expr>();
+
+ return Composite2;
}
Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
@@ -2450,8 +2516,12 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) {
RD->getDestructor(Context));
ExprTemporaries.push_back(Temp);
if (CXXDestructorDecl *Destructor =
- const_cast<CXXDestructorDecl*>(RD->getDestructor(Context)))
+ const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
+ CheckDestructorAccess(E->getExprLoc(), Destructor,
+ PDiag(diag::err_access_dtor_temp)
+ << E->getType());
+ }
// FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
@@ -2701,7 +2771,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
@@ -2869,43 +2939,6 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
return CE;
}
-Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
- QualType Ty,
- CastExpr::CastKind Kind,
- CXXMethodDecl *Method,
- ExprArg Arg) {
- Expr *From = Arg.takeAs<Expr>();
-
- switch (Kind) {
- default: assert(0 && "Unhandled cast kind!");
- case CastExpr::CK_ConstructorConversion: {
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
-
- if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method),
- MultiExprArg(*this, (void **)&From, 1),
- CastLoc, ConstructorArgs))
- return ExprError();
-
- OwningExprResult Result =
- BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- move_arg(ConstructorArgs));
- if (Result.isInvalid())
- return ExprError();
-
- return MaybeBindToTemporary(Result.takeAs<Expr>());
- }
-
- case CastExpr::CK_UserDefinedConversion: {
- assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
-
- // Create an implicit call expr that calls it.
- // FIXME: pass the FoundDecl for the user-defined conversion here
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method);
- return MaybeBindToTemporary(CE);
- }
- }
-}
-
Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
Expr *FullExpr = Arg.takeAs<Expr>();
if (FullExpr)
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index d5a22ca15fae..db9a2e238f95 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -12,9 +12,12 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
+#include "SemaInit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
#include "clang/Lex/Preprocessor.h"
@@ -75,9 +78,25 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
QualType Ty = Context.getObjCConstantStringInterface();
if (!Ty.isNull()) {
Ty = Context.getObjCObjectPointerType(Ty);
+ } else if (getLangOptions().NoConstantCFStrings) {
+ IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString");
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ LookupOrdinaryName);
+ if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
+ Context.setObjCConstantStringInterface(StrIF);
+ Ty = Context.getObjCConstantStringInterface();
+ Ty = Context.getObjCObjectPointerType(Ty);
+ } else {
+ // If there is no NSConstantString interface defined then treat this
+ // as error and recover from it.
+ Diag(S->getLocStart(), diag::err_no_nsconstant_string_class) << NSIdent
+ << S->getSourceRange();
+ Ty = Context.getObjCIdType();
+ }
} else {
IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
- NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName);
+ NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0],
+ LookupOrdinaryName);
if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
Context.setObjCConstantStringInterface(StrIF);
Ty = Context.getObjCConstantStringInterface();
@@ -93,8 +112,9 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
}
Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
- QualType EncodedType,
+ TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc) {
+ QualType EncodedType = EncodedTypeInfo->getType();
QualType StrTy;
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
@@ -112,7 +132,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
ArrayType::Normal, 0);
}
- return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
+ return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc);
}
Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
@@ -121,9 +141,13 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
TypeTy *ty,
SourceLocation RParenLoc) {
// FIXME: Preserve type source info ?
- QualType EncodedType = GetTypeFromParser(ty);
+ TypeSourceInfo *TInfo;
+ QualType EncodedType = GetTypeFromParser(ty, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(EncodedType,
+ PP.getLocForEndOfToken(LParenLoc));
- return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc);
+ return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
}
Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
@@ -148,7 +172,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
SourceLocation ProtoLoc,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId);
+ ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc);
if (!PDecl) {
Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId;
return true;
@@ -168,8 +192,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
QualType &ReturnType) {
if (!Method) {
// Apply default argument promotion as for (C99 6.5.2.2p6).
- for (unsigned i = 0; i != NumArgs; i++)
+ for (unsigned i = 0; i != NumArgs; i++) {
+ if (Args[i]->isTypeDependent())
+ continue;
+
DefaultArgumentPromotion(Args[i]);
+ }
unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
diag::warn_inst_method_not_found;
@@ -179,50 +207,68 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
return false;
}
- ReturnType = Method->getResultType();
+ ReturnType = Method->getResultType().getNonReferenceType();
unsigned NumNamedArgs = Sel.getNumArgs();
- assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
+ // Method might have more arguments than selector indicates. This is due
+ // to addition of c-style arguments in method.
+ if (Method->param_size() > Sel.getNumArgs())
+ NumNamedArgs = Method->param_size();
+ // FIXME. This need be cleaned up.
+ if (NumArgs < NumNamedArgs) {
+ Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2
+ << NumNamedArgs << NumArgs;
+ return false;
+ }
bool IsError = false;
for (unsigned i = 0; i < NumNamedArgs; i++) {
- Expr *argExpr = Args[i];
- assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+ // We can't do any type-checking on a type-dependent argument.
+ if (Args[i]->isTypeDependent())
+ continue;
- QualType lhsType = Method->param_begin()[i]->getType();
- QualType rhsType = argExpr->getType();
+ Expr *argExpr = Args[i];
- // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
- if (lhsType->isArrayType())
- lhsType = Context.getArrayDecayedType(lhsType);
- else if (lhsType->isFunctionType())
- lhsType = Context.getPointerType(lhsType);
+ ParmVarDecl *Param = Method->param_begin()[i];
+ assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
- AssignConvertType Result =
- CheckSingleAssignmentConstraints(lhsType, argExpr);
- if (Args[i] != argExpr) // The expression was converted.
- Args[i] = argExpr; // Make sure we store the converted expression.
+ if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
+ Param->getType(),
+ PDiag(diag::err_call_incomplete_argument)
+ << argExpr->getSourceRange()))
+ return true;
- IsError |=
- DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
- argExpr, AA_Sending);
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Param);
+ OwningExprResult ArgE = PerformCopyInitialization(Entity,
+ SourceLocation(),
+ Owned(argExpr->Retain()));
+ if (ArgE.isInvalid())
+ IsError = true;
+ else
+ Args[i] = ArgE.takeAs<Expr>();
}
// Promote additional arguments to variadic methods.
if (Method->isVariadic()) {
- for (unsigned i = NumNamedArgs; i < NumArgs; ++i)
+ for (unsigned i = NumNamedArgs; i < NumArgs; ++i) {
+ if (Args[i]->isTypeDependent())
+ continue;
+
IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod);
+ }
} else {
// Check for extra arguments to non-variadic methods.
if (NumArgs != NumNamedArgs) {
Diag(Args[NumNamedArgs]->getLocStart(),
diag::err_typecheck_call_too_many_args)
- << 2 /*method*/ << Method->getSourceRange()
+ << 2 /*method*/ << NumNamedArgs << NumArgs
+ << Method->getSourceRange()
<< SourceRange(Args[NumNamedArgs]->getLocStart(),
Args[NumArgs-1]->getLocEnd());
}
}
+ DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
return IsError;
}
@@ -281,20 +327,147 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
return Method;
}
-Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
- IdentifierInfo &receiverName,
- IdentifierInfo &propertyName,
- SourceLocation &receiverNameLoc,
- SourceLocation &propertyNameLoc) {
+/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
+/// objective C interface. This is a property reference expression.
+Action::OwningExprResult Sema::
+HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
+ Expr *BaseExpr, DeclarationName MemberName,
+ SourceLocation MemberLoc) {
+ const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
+ ObjCInterfaceDecl *IFace = IFaceT->getDecl();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- IdentifierInfo *receiverNamePtr = &receiverName;
- ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
- if (!IFace) {
- Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ // Search for a declared property first.
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+ QualType ResTy = PD->getType();
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
+ if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
+ ResTy = Getter->getResultType();
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ MemberLoc, BaseExpr));
+ }
+ // Check protocols on qualified interfaces.
+ for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
+ E = OPT->qual_end(); I != E; ++I)
+ if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ // Check whether we can reference this property.
+ if (DiagnoseUseOfDecl(PD, MemberLoc))
+ return ExprError();
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ MemberLoc, BaseExpr));
+ }
+ // If that failed, look for an "implicit" property by seeing if the nullary
+ // selector is implemented.
+
+ // FIXME: The logic for looking up nullary and unary selectors should be
+ // shared with the code in ActOnInstanceMessage.
+
+ Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
+ ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
+
+ // If this reference is in an @implementation, check for 'private' methods.
+ if (!Getter)
+ Getter = IFace->lookupPrivateInstanceMethod(Sel);
+
+ // Look through local category implementations associated with the class.
+ if (!Getter)
+ Getter = IFace->getCategoryInstanceMethod(Sel);
+ if (Getter) {
+ // Check if we can reference this property.
+ if (DiagnoseUseOfDecl(Getter, MemberLoc))
+ return ExprError();
+ }
+ // If we found a getter then this may be a valid dot-reference, we
+ // will look for the matching setter, in case it is needed.
+ Selector SetterSel =
+ SelectorTable::constructSetterName(PP.getIdentifierTable(),
+ PP.getSelectorTable(), Member);
+ ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
+ if (!Setter) {
+ // If this reference is in an @implementation, also check for 'private'
+ // methods.
+ Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
+ }
+ // Look through local category implementations associated with the class.
+ if (!Setter)
+ Setter = IFace->getCategoryInstanceMethod(SetterSel);
+
+ if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
+
+ if (Getter) {
+ QualType PType;
+ PType = Getter->getResultType();
+ return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
+ Setter, MemberLoc, BaseExpr));
+ }
+
+ // Attempt to correct for typos in property names.
+ LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
+ if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
+ Res.getAsSingle<ObjCPropertyDecl>()) {
+ DeclarationName TypoResult = Res.getLookupName();
+ Diag(MemberLoc, diag::err_property_not_found_suggest)
+ << MemberName << QualType(OPT, 0) << TypoResult
+ << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
+ ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
+ Diag(Property->getLocation(), diag::note_previous_decl)
+ << Property->getDeclName();
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc);
+ }
+
+ Diag(MemberLoc, diag::err_property_not_found)
+ << MemberName << QualType(OPT, 0);
+ if (Setter && !Getter)
+ Diag(Setter->getLocation(), diag::note_getter_unavailable)
+ << MemberName << BaseExpr->getSourceRange();
+ return ExprError();
+}
+
+
+
+Action::OwningExprResult Sema::
+ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
+ IdentifierInfo &propertyName,
+ SourceLocation receiverNameLoc,
+ SourceLocation propertyNameLoc) {
+
+ IdentifierInfo *receiverNamePtr = &receiverName;
+ ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
+ receiverNameLoc);
+ if (IFace == 0) {
+ // If the "receiver" is 'super' in a method, handle it as an expression-like
+ // property reference.
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+ if (receiverNamePtr->isStr("super")) {
+ if (CurMethod->isInstanceMethod()) {
+ QualType T =
+ Context.getObjCInterfaceType(CurMethod->getClassInterface());
+ T = Context.getObjCObjectPointerType(T);
+ Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T);
+
+ return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
+ SuperExpr, &propertyName,
+ propertyNameLoc);
+ }
+
+ // Otherwise, if this is a class method, try dispatching to our
+ // superclass.
+ IFace = CurMethod->getClassInterface()->getSuperClass();
+ }
+
+ if (IFace == 0) {
+ Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ return ExprError();
+ }
}
- // Search for a declared property first.
+ // Search for a declared property first.
Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
@@ -351,329 +524,502 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
<< &propertyName << Context.getObjCInterfaceType(IFace));
}
+Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsSuper,
+ bool HasTrailingDot,
+ TypeTy *&ReceiverType) {
+ ReceiverType = 0;
+
+ // If the identifier is "super" and there is no trailing dot, we're
+ // messaging super.
+ if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope())
+ return ObjCSuperMessage;
+
+ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+ LookupName(Result, S);
+
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ // Normal name lookup didn't find anything. If we're in an
+ // Objective-C method, look for ivars. If we find one, we're done!
+ // FIXME: This is a hack. Ivar lookup should be part of normal lookup.
+ if (ObjCMethodDecl *Method = getCurMethodDecl()) {
+ ObjCInterfaceDecl *ClassDeclared;
+ if (Method->getClassInterface()->lookupInstanceVariable(Name,
+ ClassDeclared))
+ return ObjCInstanceMessage;
+ }
+
+ // Break out; we'll perform typo correction below.
+ break;
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ case LookupResult::Ambiguous:
+ Result.suppressDiagnostics();
+ return ObjCInstanceMessage;
+
+ case LookupResult::Found: {
+ // We found something. If it's a type, then we have a class
+ // message. Otherwise, it's an instance message.
+ NamedDecl *ND = Result.getFoundDecl();
+ QualType T;
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
+ T = Context.getObjCInterfaceType(Class);
+ else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ T = Context.getTypeDeclType(Type);
+ else
+ return ObjCInstanceMessage;
+
+ // We have a class message, and T is the type we're
+ // messaging. Build source-location information for it.
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr();
+ return ObjCClassMessage;
+ }
+ }
-// ActOnClassMessage - used for both unary and keyword messages.
-// ArgExprs is optional - if it is present, the number of expressions
-// is obtained from Sel.getNumArgs().
-Sema::ExprResult Sema::ActOnClassMessage(
- Scope *S,
- IdentifierInfo *receiverName, Selector Sel,
- SourceLocation lbrac, SourceLocation receiverLoc,
- SourceLocation selectorLoc, SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs) {
- assert(receiverName && "missing receiver class name");
-
- Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
- ObjCInterfaceDecl* ClassDecl = 0;
- bool isSuper = false;
-
- if (receiverName->isStr("super")) {
- if (getCurMethodDecl()) {
- isSuper = true;
- ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface();
- if (!OID)
- return Diag(lbrac, diag::error_no_super_class_message)
- << getCurMethodDecl()->getDeclName();
- ClassDecl = OID->getSuperClass();
- if (!ClassDecl)
- return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName();
- if (getCurMethodDecl()->isInstanceMethod()) {
- QualType superTy = Context.getObjCInterfaceType(ClassDecl);
- superTy = Context.getObjCObjectPointerType(superTy);
- ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(),
- superTy);
- // We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
- selectorLoc, rbrac, Args, NumArgs);
+ // Determine our typo-correction context.
+ CorrectTypoContext CTC = CTC_Expression;
+ if (ObjCMethodDecl *Method = getCurMethodDecl())
+ if (Method->getClassInterface() &&
+ Method->getClassInterface()->getSuperClass())
+ CTC = CTC_ObjCMessageReceiver;
+
+ if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
+ if (Result.isSingleResult()) {
+ // If we found a declaration, correct when it refers to an Objective-C
+ // class.
+ NamedDecl *ND = Result.getFoundDecl();
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Result.getLookupName()
+ << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ ND->getNameAsString());
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << Corrected;
+
+ QualType T = Context.getObjCInterfaceType(Class);
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
+ ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr();
+ return ObjCClassMessage;
}
- // We are sending a message to 'super' within a class method. Do nothing,
- // the receiver will pass through as 'super' (how convenient:-).
- } else {
- // 'super' has been used outside a method context. If a variable named
- // 'super' has been declared, redirect. If not, produce a diagnostic.
- NamedDecl *SuperDecl
- = LookupSingleName(S, receiverName, LookupOrdinaryName);
- ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl);
- if (VD) {
- ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(),
- receiverLoc);
- // We are really in an instance method, redirect.
- return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
- selectorLoc, rbrac, Args, NumArgs);
- }
- else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) {
- const ObjCInterfaceType *OCIT;
- OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
- if (!OCIT) {
- Diag(receiverLoc, diag::err_invalid_receiver_to_message);
- return true;
- }
- ClassDecl = OCIT->getDecl();
- }
- else
- return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
- }
- } else
- ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
-
- // The following code allows for the following GCC-ism:
- //
- // typedef XCElementDisplayRect XCElementGraphicsRect;
- //
- // @implementation XCRASlice
- // - whatever { // Note that XCElementGraphicsRect is a typedef name.
- // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init];
- // }
- //
- // If necessary, the following lookup could move to getObjCInterfaceDecl().
- if (!ClassDecl) {
- NamedDecl *IDecl
- = LookupSingleName(TUScope, receiverName, LookupOrdinaryName);
- if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl))
- if (const ObjCInterfaceType *OCIT
- = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>())
- ClassDecl = OCIT->getDecl();
-
- if (!ClassDecl) {
- Diag(receiverLoc, diag::err_invalid_receiver_to_message);
- return true;
+ } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
+ Corrected.getAsIdentifierInfo()->isStr("super")) {
+ // If we've found the keyword "super", this is a send to super.
+ Diag(NameLoc, diag::err_unknown_receiver_suggest)
+ << Name << Corrected
+ << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
+ Name = Corrected.getAsIdentifierInfo();
+ return ObjCSuperMessage;
}
}
- assert(ClassDecl && "missing interface declaration");
- ObjCMethodDecl *Method = 0;
- QualType returnType;
- if (ClassDecl->isForwardDecl()) {
- // A forward class used in messaging is tread as a 'Class'
- Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName();
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
- if (Method)
- Diag(Method->getLocation(), diag::note_method_sent_forward_class)
- << Method->getDeclName();
+
+ // Fall back: let the parser try to parse it as an instance message.
+ return ObjCInstanceMessage;
+}
+
+Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ // Determine whether we are inside a method or not.
+ ObjCMethodDecl *Method = getCurMethodDecl();
+ if (!Method) {
+ Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
+ return ExprError();
}
- if (!Method)
- Method = ClassDecl->lookupClassMethod(Sel);
- // If we have an implementation in scope, check "private" methods.
- if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ ObjCInterfaceDecl *Class = Method->getClassInterface();
+ if (!Class) {
+ Diag(SuperLoc, diag::error_no_super_class_message)
+ << Method->getDeclName();
+ return ExprError();
+ }
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
+ ObjCInterfaceDecl *Super = Class->getSuperClass();
+ if (!Super) {
+ // The current class does not have a superclass.
+ Diag(SuperLoc, diag::error_no_super_class) << Class->getIdentifier();
+ return ExprError();
+ }
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true,
- lbrac, rbrac, returnType))
- return true;
+ // We are in a method whose class has a superclass, so 'super'
+ // is acting as a keyword.
+ if (Method->isInstanceMethod()) {
+ // Since we are in an instance method, this is an instance
+ // message to the superclass instance.
+ QualType SuperTy = Context.getObjCInterfaceType(Super);
+ SuperTy = Context.getObjCObjectPointerType(SuperTy);
+ return BuildInstanceMessage(ExprArg(*this), SuperTy, SuperLoc,
+ Sel, /*Method=*/0, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ // Since we are in a class method, this is a class message to
+ // the superclass.
+ return BuildClassMessage(/*ReceiverTypeInfo=*/0,
+ Context.getObjCInterfaceType(Super),
+ SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc,
+ move(Args));
+}
+
+/// \brief Build an Objective-C class message expression.
+///
+/// This routine takes care of both normal class messages and
+/// class messages to the superclass.
+///
+/// \param ReceiverTypeInfo Type source information that describes the
+/// receiver of this message. This may be NULL, in which case we are
+/// sending to the superclass and \p SuperLoc must be a valid source
+/// location.
+
+/// \param ReceiverType The type of the object receiving the
+/// message. When \p ReceiverTypeInfo is non-NULL, this is the same
+/// type as that refers to. For a superclass send, this is the type of
+/// the superclass.
+///
+/// \param SuperLoc The location of the "super" keyword in a
+/// superclass message.
+///
+/// \param Sel The selector to which the message is being sent.
+///
+/// \param Method The method that this class message is invoking, if
+/// already known.
+///
+/// \param LBracLoc The location of the opening square bracket ']'.
+///
+/// \param RBrac The location of the closing square bracket ']'.
+///
+/// \param Args The message arguments.
+Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg ArgsIn) {
+ if (ReceiverType->isDependentType()) {
+ // If the receiver type is dependent, we can't type-check anything
+ // at this point. Build a dependent expression.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ assert(SuperLoc.isInvalid() && "Message to super with dependent type");
+ return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc,
+ ReceiverTypeInfo, Sel, /*Method=*/0,
+ Args, NumArgs, RBracLoc));
+ }
+
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc
+ : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin();
+
+ // Find the class to which we are sending this message.
+ ObjCInterfaceDecl *Class = 0;
+ if (const ObjCInterfaceType *ClassType
+ = ReceiverType->getAs<ObjCInterfaceType>())
+ Class = ClassType->getDecl();
+ else {
+ Diag(Loc, diag::err_invalid_receiver_class_message)
+ << ReceiverType;
+ return ExprError();
+ }
+ assert(Class && "We don't know which class we're messaging?");
+
+ // Find the method we are messaging.
+ if (!Method) {
+ if (Class->isForwardDecl()) {
+ // A forward class used in messaging is treated as a 'Class'
+ Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method)
+ Diag(Method->getLocation(), diag::note_method_sent_forward_class)
+ << Method->getDeclName();
+ }
+ if (!Method)
+ Method = Class->lookupClassMethod(Sel);
- returnType = returnType.getNonReferenceType();
-
- // If we have the ObjCInterfaceDecl* for the class that is receiving the
- // message, use that to construct the ObjCMessageExpr. Otherwise pass on the
- // IdentifierInfo* for the class.
- // FIXME: need to do a better job handling 'super' usage within a class. For
- // now, we simply pass the "super" identifier through (which isn't consistent
- // with instance methods.
- if (isSuper)
- return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc,
- Sel, returnType, Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- else
- return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc,
- Sel, returnType, Method, lbrac, rbrac,
- ArgExprs, NumArgs);
+ // If we have an implementation in scope, check "private" methods.
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, Class);
+
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
+ }
+
+ // Check the argument types and determine the result type.
+ QualType ReturnType;
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true,
+ LBracLoc, RBracLoc, ReturnType)) {
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+ return ExprError();
+ }
+
+ // Construct the appropriate ObjCMessageExpr.
+ if (SuperLoc.isValid())
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, Method, Args,
+ NumArgs, RBracLoc));
+
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ ReceiverTypeInfo, Sel, Method, Args,
+ NumArgs, RBracLoc));
}
-// ActOnInstanceMessage - used for both unary and keyword messages.
+// ActOnClassMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from Sel.getNumArgs().
-Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
- SourceLocation lbrac,
- SourceLocation receiverLoc,
- SourceLocation rbrac,
- ExprTy **Args, unsigned NumArgs) {
- assert(receiver && "missing receiver expression");
-
- Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
- Expr *RExpr = static_cast<Expr *>(receiver);
-
- // If necessary, apply function/array conversion to the receiver.
- // C99 6.7.5.3p[7,8].
- DefaultFunctionArrayLvalueConversion(RExpr);
-
- QualType returnType;
- QualType ReceiverCType =
- Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
-
- // Handle messages to 'super'.
- if (isa<ObjCSuperExpr>(RExpr)) {
- ObjCMethodDecl *Method = 0;
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- // If we have an interface in scope, check 'super' methods.
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) {
- Method = SuperDecl->lookupInstanceMethod(Sel);
+Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S,
+ TypeTy *Receiver,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ TypeSourceInfo *ReceiverTypeInfo;
+ QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo);
+ if (ReceiverType.isNull())
+ return ExprError();
- if (!Method)
- // If we have implementations in scope, check "private" methods.
- Method = LookupPrivateInstanceMethod(Sel, SuperDecl);
- }
- }
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
+ if (!ReceiverTypeInfo)
+ ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
+ return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
+ /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
+ LBracLoc, RBracLoc, move(Args));
+}
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- }
+/// \brief Build an Objective-C instance message expression.
+///
+/// This routine takes care of both normal instance messages and
+/// instance messages to the superclass instance.
+///
+/// \param Receiver The expression that computes the object that will
+/// receive this message. This may be empty, in which case we are
+/// sending to the superclass instance and \p SuperLoc must be a valid
+/// source location.
+///
+/// \param ReceiverType The (static) type of the object receiving the
+/// message. When a \p Receiver expression is provided, this is the
+/// same type as that expression. For a superclass instance send, this
+/// is a pointer to the type of the superclass.
+///
+/// \param SuperLoc The location of the "super" keyword in a
+/// superclass instance message.
+///
+/// \param Sel The selector to which the message is being sent.
+///
+/// \param Method The method that this instance message is invoking, if
+/// already known.
+///
+/// \param LBracLoc The location of the opening square bracket ']'.
+///
+/// \param RBrac The location of the closing square bracket ']'.
+///
+/// \param Args The message arguments.
+Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE,
+ QualType ReceiverType,
+ SourceLocation SuperLoc,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg ArgsIn) {
+ // If we have a receiver expression, perform appropriate promotions
+ // and determine receiver type.
+ Expr *Receiver = ReceiverE.takeAs<Expr>();
+ if (Receiver) {
+ if (Receiver->isTypeDependent()) {
+ // If the receiver is type-dependent, we can't type-check anything
+ // at this point. Build a dependent expression.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ assert(SuperLoc.isInvalid() && "Message to super with dependent type");
+ return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
+ LBracLoc, Receiver, Sel,
+ /*Method=*/0, Args, NumArgs,
+ RBracLoc));
+ }
- // Handle messages to id.
- if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() ||
- Context.isObjCNSObjectType(RExpr->getType())) {
- ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (!Method)
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac));
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
+ // If necessary, apply function/array conversion to the receiver.
+ // C99 6.7.5.3p[7,8].
+ DefaultFunctionArrayLvalueConversion(Receiver);
+ ReceiverType = Receiver->getType();
}
- // Handle messages to Class.
- if (ReceiverCType->isObjCClassType() ||
- ReceiverCType->isObjCQualifiedClassType()) {
- ObjCMethodDecl *Method = 0;
+ // The location of the receiver.
+ SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart();
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
- // First check the public methods in the class interface.
- Method = ClassDecl->lookupClassMethod(Sel);
+ if (!Method) {
+ // Handle messages to id.
+ if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType() ||
+ (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (!Method)
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ } else if (ReceiverType->isObjCClassType() ||
+ ReceiverType->isObjCQualifiedClassType()) {
+ // Handle messages to Class.
+ if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
+ if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) {
+ // First check the public methods in the class interface.
+ Method = ClassDecl->lookupClassMethod(Sel);
- if (!Method)
- Method = LookupPrivateClassMethod(Sel, ClassDecl);
+ if (!Method)
+ Method = LookupPrivateClassMethod(Sel, ClassDecl);
- // FIXME: if we still haven't found a method, we need to look in
- // protocols (if we have qualifiers).
+ // FIXME: if we still haven't found a method, we need to look in
+ // protocols (if we have qualifiers).
+ }
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
}
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
- }
- if (!Method) {
- // If not messaging 'self', look for any factory method named 'Sel'.
- if (!isSelfExpr(RExpr)) {
- Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac));
- if (!Method) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (Method)
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(lbrac, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(lbrac, rbrac);
- }
+ if (!Method) {
+ // If not messaging 'self', look for any factory method named 'Sel'.
+ if (!Receiver || !isSelfExpr(Receiver)) {
+ Method = LookupFactoryMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (!Method) {
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method)
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(Loc, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(LBracLoc, RBracLoc);
+ }
+ }
}
}
- }
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType,
- Method, lbrac, rbrac,
- ArgExprs, NumArgs);
- }
+ } else {
+ ObjCInterfaceDecl* ClassDecl = 0;
+
+ // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
+ // long as one of the protocols implements the selector (if not, warn).
+ if (const ObjCObjectPointerType *QIdTy
+ = ReceiverType->getAsObjCQualifiedIdType()) {
+ // Search protocols for instance methods.
+ for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
+ E = QIdTy->qual_end(); I != E; ++I) {
+ ObjCProtocolDecl *PDecl = *I;
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ // Since we aren't supporting "Class<foo>", look for a class method.
+ if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
+ break;
+ }
+ } else if (const ObjCObjectPointerType *OCIType
+ = ReceiverType->getAsObjCInterfacePointerType()) {
+ // We allow sending a message to a pointer to an interface (an object).
+ ClassDecl = OCIType->getInterfaceDecl();
+ // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
+ // faster than the following method (which can do *many* linear searches).
+ // The idea is to add class info to InstanceMethodPool.
+ Method = ClassDecl->lookupInstanceMethod(Sel);
- ObjCMethodDecl *Method = 0;
- ObjCInterfaceDecl* ClassDecl = 0;
-
- // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
- // long as one of the protocols implements the selector (if not, warn).
- if (const ObjCObjectPointerType *QIdTy =
- ReceiverCType->getAsObjCQualifiedIdType()) {
- // Search protocols for instance methods.
- for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(),
- E = QIdTy->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *PDecl = *I;
- if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
- break;
- // Since we aren't supporting "Class<foo>", look for a class method.
- if (PDecl && (Method = PDecl->lookupClassMethod(Sel)))
- break;
- }
- } else if (const ObjCObjectPointerType *OCIType =
- ReceiverCType->getAsObjCInterfacePointerType()) {
- // We allow sending a message to a pointer to an interface (an object).
-
- ClassDecl = OCIType->getInterfaceDecl();
- // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
- // faster than the following method (which can do *many* linear searches).
- // The idea is to add class info to InstanceMethodPool.
- Method = ClassDecl->lookupInstanceMethod(Sel);
-
- if (!Method) {
- // Search protocol qualifiers.
- for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
- E = OCIType->qual_end(); QI != E; ++QI) {
- if ((Method = (*QI)->lookupInstanceMethod(Sel)))
- break;
- }
- }
- if (!Method) {
- // If we have implementations in scope, check "private" methods.
- Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
-
- if (!Method && !isSelfExpr(RExpr)) {
- // If we still haven't found a method, look in the global pool. This
- // behavior isn't very desirable, however we need it for GCC
- // compatibility. FIXME: should we deviate??
- if (OCIType->qual_empty()) {
- Method = LookupInstanceMethodInGlobalPool(
- Sel, SourceRange(lbrac,rbrac));
- if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
- Diag(lbrac, diag::warn_maynot_respond)
- << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel;
+ if (!Method) {
+ // Search protocol qualifiers.
+ for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(),
+ E = OCIType->qual_end(); QI != E; ++QI) {
+ if ((Method = (*QI)->lookupInstanceMethod(Sel)))
+ break;
+ }
}
+ if (!Method) {
+ // If we have implementations in scope, check "private" methods.
+ Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
+
+ if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
+ // If we still haven't found a method, look in the global pool. This
+ // behavior isn't very desirable, however we need it for GCC
+ // compatibility. FIXME: should we deviate??
+ if (OCIType->qual_empty()) {
+ Method = LookupInstanceMethodInGlobalPool(Sel,
+ SourceRange(LBracLoc, RBracLoc));
+ if (Method && !OCIType->getInterfaceDecl()->isForwardDecl())
+ Diag(Loc, diag::warn_maynot_respond)
+ << OCIType->getInterfaceDecl()->getIdentifier() << Sel;
+ }
+ }
+ }
+ if (Method && DiagnoseUseOfDecl(Method, Loc))
+ return ExprError();
+ } else if (!Context.getObjCIdType().isNull() &&
+ (ReceiverType->isPointerType() ||
+ (ReceiverType->isIntegerType() &&
+ ReceiverType->isScalarType()))) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ Diag(Loc, diag::warn_bad_receiver_type)
+ << ReceiverType
+ << Receiver->getSourceRange();
+ if (ReceiverType->isPointerType())
+ ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CastExpr::CK_BitCast);
+ else
+ ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CastExpr::CK_IntegralToPointer);
+ ReceiverType = Receiver->getType();
+ } else {
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
}
- if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
- return true;
- } else if (!Context.getObjCIdType().isNull() &&
- (ReceiverCType->isPointerType() ||
- (ReceiverCType->isIntegerType() &&
- ReceiverCType->isScalarType()))) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- Diag(lbrac, diag::warn_bad_receiver_type)
- << RExpr->getType() << RExpr->getSourceRange();
- if (ReceiverCType->isPointerType())
- ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast);
- else
- ImpCastExprToType(RExpr, Context.getObjCIdType(),
- CastExpr::CK_IntegralToPointer);
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(lbrac, diag::err_bad_receiver_type)
- << RExpr->getType() << RExpr->getSourceRange();
- return true;
}
- if (Method)
- DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs);
- if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
- lbrac, rbrac, returnType))
- return true;
- returnType = returnType.getNonReferenceType();
- return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method,
- lbrac, rbrac, ArgExprs, NumArgs);
+ // Check the message arguments.
+ unsigned NumArgs = ArgsIn.size();
+ Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
+ QualType ReturnType;
+ if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false,
+ LBracLoc, RBracLoc, ReturnType))
+ return ExprError();
+
+ // Construct the appropriate ObjCMessageExpr instance.
+ if (SuperLoc.isValid())
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc,
+ SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, Method,
+ Args, NumArgs, RBracLoc));
+
+ return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver,
+ Sel, Method, Args, NumArgs, RBracLoc));
+}
+
+// ActOnInstanceMessage - used for both unary and keyword messages.
+// ArgExprs is optional - if it is present, the number of expressions
+// is obtained from Sel.getNumArgs().
+Sema::OwningExprResult Sema::ActOnInstanceMessage(Scope *S,
+ ExprArg ReceiverE,
+ Selector Sel,
+ SourceLocation LBracLoc,
+ SourceLocation SelectorLoc,
+ SourceLocation RBracLoc,
+ MultiExprArg Args) {
+ Expr *Receiver = static_cast<Expr *>(ReceiverE.get());
+ if (!Receiver)
+ return ExprError();
+
+ return BuildInstanceMessage(move(ReceiverE), Receiver->getType(),
+ /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
+ LBracLoc, RBracLoc, move(Args));
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 1d0575cd1c12..0aa344617763 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -281,7 +281,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(Init, MemberInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, MemberInit.takeAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
@@ -391,7 +391,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(Init, ElementInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
@@ -458,7 +458,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
if (T->isArrayType())
maxElements = numArrayElements(T);
- else if (T->isStructureType() || T->isUnionType())
+ else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
maxElements = T->getAs<VectorType>()->getNumElements();
@@ -624,10 +624,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isReferenceType()) {
CheckReferenceType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
+ } else if (DeclType->isObjCInterfaceType()) {
+ SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class)
+ << DeclType;
+ hadError = true;
} else {
- // In C, all types are either scalars or aggregates, but
- // additional handling is needed here for C++ (and possibly others?).
- assert(0 && "Unsupported initializer type");
+ SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
+ << DeclType;
+ hadError = true;
}
}
@@ -884,9 +888,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
}
- // OpenCL & AltiVec require all elements to be initialized.
+ // OpenCL requires all elements to be initialized.
if (numEltsInit != maxElements)
- if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec)
+ if (SemaRef.getLangOptions().OpenCL)
SemaRef.Diag(IList->getSourceRange().getBegin(),
diag::err_vector_incorrect_num_initializers)
<< (numEltsInit < maxElements) << maxElements << numEltsInit;
@@ -1354,7 +1358,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// was a typo for another field name.
LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
Sema::LookupMemberName);
- if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) &&
+ if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false,
+ Sema::CTC_NoKeywords) &&
(ReplacementField = R.getAsSingle<FieldDecl>()) &&
ReplacementField->getDeclContext()->getLookupContext()
->Equals(RT->getDecl())) {
@@ -1702,7 +1707,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
}
InitListExpr *Result
- = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0,
+ = new (SemaRef.Context) InitListExpr(SemaRef.Context,
+ InitRange.getBegin(), 0, 0,
InitRange.getEnd());
Result->setType(CurrentObjectType.getNonReferenceType());
@@ -1740,12 +1746,12 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (NumElements < NumInits)
NumElements = IList->getNumInits();
- Result->reserveInits(NumElements);
+ Result->reserveInits(SemaRef.Context, NumElements);
// Link this new initializer list into the structured initializer
// lists.
if (StructuredList)
- StructuredList->updateInit(StructuredIndex, Result);
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
else {
Result->setSyntacticForm(IList);
SyntacticToSemantic[IList] = Result;
@@ -1763,7 +1769,8 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (!StructuredList)
return;
- if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+ if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
+ StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
SemaRef.Diag(expr->getSourceRange().getBegin(),
diag::warn_initializer_overrides)
@@ -1918,11 +1925,15 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
}
InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base)
+ CXXBaseSpecifier *Base,
+ bool IsInheritedVirtualBase)
{
InitializedEntity Result;
Result.Kind = EK_Base;
- Result.Base = Base;
+ Result.Base = reinterpret_cast<uintptr_t>(Base);
+ if (IsInheritedVirtualBase)
+ Result.Base |= 0x01;
+
Result.Type = Base->getType();
return Result;
}
@@ -1984,6 +1995,7 @@ void InitializationSequence::Step::Destroy() {
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
+ case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionRValue:
case SK_QualificationConversionLValue:
@@ -2033,6 +2045,10 @@ bool InitializationSequence::isAmbiguous() const {
return false;
}
+bool InitializationSequence::isConstructorInitialization() const {
+ return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
FunctionDecl *Function,
DeclAccessPair Found) {
@@ -2060,6 +2076,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T,
Steps.push_back(S);
}
+void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) {
+ Step S;
+ S.Kind = SK_ExtraneousCopyToTemporary;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::AddUserConversionStep(FunctionDecl *Function,
DeclAccessPair FoundDecl,
QualType T) {
@@ -2388,15 +2411,11 @@ static void TryReferenceInitialization(Sema &S,
T2 = cv2T2.getUnqualifiedType();
}
- // FIXME: Rvalue references
- bool ForceRValue = false;
-
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
bool DerivedToBase = false;
- Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression :
- Initializer->isLvalue(S.Context);
+ Expr::isLvalueResult InitLvalue = Initializer->isLvalue(S.Context);
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase);
@@ -2480,6 +2499,18 @@ static void TryReferenceInitialization(Sema &S,
// reference-compatible with "cv2 T2", or
if (InitLvalue != Expr::LV_Valid &&
RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the
+ // compiler the freedom to perform a copy here or bind to the
+ // object, while C++0x requires that we bind directly to the
+ // object. Hence, we always bind to the object without making an
+ // extra copy. However, in C++03 requires that we check for the
+ // presence of a suitable copy constructor:
+ //
+ // The constructor that would be used to make the copy shall
+ // be callable whether or not the copy is actually done.
+ if (!S.getLangOptions().CPlusPlus0x)
+ Sequence.AddExtraneousCopyToTemporary(cv2T2);
+
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
S.Context.getQualifiedType(T1, T2Quals),
@@ -2528,9 +2559,7 @@ static void TryReferenceInitialization(Sema &S,
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, cv1T1,
/*SuppressUserConversions=*/false, AllowExplicit,
- /*ForceRValue=*/false,
- /*FIXME:InOverloadResolution=*/false,
- /*UserCast=*/Kind.isExplicitCast());
+ /*FIXME:InOverloadResolution=*/false);
if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
@@ -2595,6 +2624,12 @@ static void TryConstructorInitialization(Sema &S,
bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value ||
Kind.getKind() == InitializationKind::IK_Default);
+
+ // The type we're constructing needs to be complete.
+ if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
+ return;
+ }
// The type we're converting to is a class type. Enumerate its constructors
// to see if one is suitable.
@@ -2611,25 +2646,36 @@ static void TryConstructorInitialization(Sema &S,
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
+ bool SuppressUserConversions = false;
+
// Find the constructor (which may be a template).
CXXConstructorDecl *Constructor = 0;
FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
ConstructorTmpl->getTemplatedDecl());
- else
+ else {
Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor, we
+ // suppress user-defined conversions on the arguments.
+ // FIXME: Move constructors?
+ if (Kind.getKind() == InitializationKind::IK_Copy &&
+ Constructor->isCopyConstructor())
+ SuppressUserConversions = true;
+ }
if (!Constructor->isInvalidDecl() &&
(AllowExplicit || !Constructor->isExplicit())) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
- Args, NumArgs, CandidateSet);
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
else
S.AddOverloadCandidate(Constructor, FoundDecl,
- Args, NumArgs, CandidateSet);
+ Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
}
}
@@ -2770,36 +2816,51 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *DestRecordDecl
= cast<CXXRecordDecl>(DestRecordType->getDecl());
- DeclarationName ConstructorName
- = S.Context.DeclarationNames.getCXXConstructorName(
+ // Try to complete the type we're converting to.
+ if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
+ DeclarationName ConstructorName
+ = S.Context.DeclarationNames.getCXXConstructorName(
S.Context.getCanonicalType(DestType).getUnqualifiedType());
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
-
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
+ DeclContext::lookup_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ NamedDecl *D = *Con;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
+ bool SuppressUserConversions = false;
+
+ // Find the constructor (which may be a template).
+ CXXConstructorDecl *Constructor = 0;
+ FunctionTemplateDecl *ConstructorTmpl
+ = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
- &Initializer, 1, CandidateSet);
- else
- S.AddOverloadCandidate(Constructor, FoundDecl,
- &Initializer, 1, CandidateSet);
- }
- }
+ Constructor = cast<CXXConstructorDecl>(
+ ConstructorTmpl->getTemplatedDecl());
+ else {
+ Constructor = cast<CXXConstructorDecl>(D);
+
+ // If we're performing copy initialization using a copy constructor,
+ // we suppress user-defined conversions on the arguments.
+ // FIXME: Move constructors?
+ if (Kind.getKind() == InitializationKind::IK_Copy &&
+ Constructor->isCopyConstructor())
+ SuppressUserConversions = true;
+
+ }
+
+ if (!Constructor->isInvalidDecl() &&
+ Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ /*ExplicitArgs*/ 0,
+ &Initializer, 1, CandidateSet,
+ SuppressUserConversions);
+ else
+ S.AddOverloadCandidate(Constructor, FoundDecl,
+ &Initializer, 1, CandidateSet,
+ SuppressUserConversions);
+ }
+ }
+ }
}
SourceLocation DeclLoc = Initializer->getLocStart();
@@ -2865,10 +2926,21 @@ static void TryUserDefinedConversion(Sema &S,
// Add the user-defined conversion step that calls the conversion function.
QualType ConvType = Function->getResultType().getNonReferenceType();
- Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
+ if (ConvType->getAs<RecordType>()) {
+ // If we're converting to a class type, there may be an copy if
+ // the resulting temporary object (possible to create an object of
+ // a base class type). That copy is not a separate conversion, so
+ // we just make a note of the actual destination type (possibly a
+ // base class of the type returned by the conversion function) and
+ // let the user-defined conversion step handle the conversion.
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType);
+ return;
+ }
- // If the conversion following the call to the conversion function is
- // interesting, add it as a separate step.
+ Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType);
+
+ // If the conversion following the call to the conversion function
+ // is interesting, add it as a separate step.
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
@@ -2889,9 +2961,7 @@ static void TryImplicitConversion(Sema &S,
= S.TryImplicitConversion(Initializer, Entity.getType(),
/*SuppressUserConversions=*/true,
/*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*FIXME:InOverloadResolution=*/false,
- /*UserCast=*/Kind.isExplicitCast());
+ /*InOverloadResolution=*/false);
if (ICS.isBad()) {
Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
@@ -3054,7 +3124,10 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Initializing;
case InitializedEntity::EK_Parameter:
- // FIXME: Can we tell when we're sending vs. passing?
+ if (Entity.getDecl() &&
+ isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext()))
+ return Sema::AA_Sending;
+
return Sema::AA_Passing;
case InitializedEntity::EK_Result:
@@ -3078,6 +3151,8 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Converting;
}
+/// \brief Whether we should binding a created object as a temporary when
+/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement:
@@ -3098,14 +3173,57 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?");
}
+/// \brief Whether the given entity, when initialized with an object
+/// created for that initialization, requires destruction.
+static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Result:
+ case InitializedEntity::EK_New:
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_VectorElement:
+ return false;
+
+ case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Parameter:
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_Exception:
+ return true;
+ }
+
+ llvm_unreachable("missed an InitializedEntity kind?");
+}
+
+/// \brief Make a (potentially elidable) temporary copy of the object
+/// provided by the given initializer by calling the appropriate copy
+/// constructor.
+///
+/// \param S The Sema object used for type-checking.
+///
+/// \param T The type of the temporary object, which must either by
+/// the type of the initializer expression or a superclass thereof.
+///
+/// \param Enter The entity being initialized.
+///
+/// \param CurInit The initializer expression.
+///
+/// \param IsExtraneousCopy Whether this is an "extraneous" copy that
+/// is permitted in C++03 (but not C++0x) when binding a reference to
+/// an rvalue.
+///
+/// \returns An expression that copies the initializer expression into
+/// a temporary object, or an error expression if a copy could not be
+/// created.
static Sema::OwningExprResult CopyObject(Sema &S,
+ QualType T,
const InitializedEntity &Entity,
- const InitializationKind &Kind,
- Sema::OwningExprResult CurInit) {
- // Determine which class type we're copying.
+ Sema::OwningExprResult CurInit,
+ bool IsExtraneousCopy) {
+ // Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
CXXRecordDecl *Class = 0;
- if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
+ if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
return move(CurInit);
@@ -3126,7 +3244,7 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// not yet) handled as part of constructor initialization, while
// copy elision for exception handlers is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject() &&
- S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType());
+ S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
SourceLocation Loc;
switch (Entity.getKind()) {
case InitializedEntity::EK_Result:
@@ -3151,7 +3269,11 @@ static Sema::OwningExprResult CopyObject(Sema &S,
Loc = CurInitExpr->getLocStart();
break;
}
-
+
+ // Make sure that the type we are copying is complete.
+ if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete)))
+ return move(CurInit);
+
// Perform overload resolution using the class's copy constructors.
DeclarationName ConstructorName
= S.Context.DeclarationNames.getCXXConstructorName(
@@ -3163,7 +3285,8 @@ static Sema::OwningExprResult CopyObject(Sema &S,
// Only consider copy constructors.
CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
if (!Constructor || Constructor->isInvalidDecl() ||
- !Constructor->isCopyConstructor())
+ !Constructor->isCopyConstructor() ||
+ !Constructor->isConvertingConstructor(/*AllowExplicit=*/false))
continue;
DeclAccessPair FoundDecl
@@ -3202,16 +3325,71 @@ static Sema::OwningExprResult CopyObject(Sema &S,
return S.ExprError();
}
- S.CheckConstructorAccess(Loc,
- cast<CXXConstructorDecl>(Best->Function),
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
+ ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+ CurInit.release(); // Ownership transferred into MultiExprArg, below.
+
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
Best->FoundDecl.getAccess());
- CurInit.release();
- return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(),
- cast<CXXConstructorDecl>(Best->Function),
- Elidable,
- Sema::MultiExprArg(S,
- (void**)&CurInitExpr, 1));
+ if (IsExtraneousCopy) {
+ // If this is a totally extraneous copy for C++03 reference
+ // binding purposes, just return the original initialization
+ // expression. We don't generate an (elided) copy operation here
+ // because doing so would require us to pass down a flag to avoid
+ // infinite recursion, where each step adds another extraneous,
+ // elidable copy.
+
+ // Instantiate the default arguments of any extra parameters in
+ // the selected copy constructor, as if we were going to create a
+ // proper call to the copy constructor.
+ for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) {
+ ParmVarDecl *Parm = Constructor->getParamDecl(I);
+ if (S.RequireCompleteType(Loc, Parm->getType(),
+ S.PDiag(diag::err_call_incomplete_argument)))
+ break;
+
+ // Build the default argument expression; we don't actually care
+ // if this succeeds or not, because this routine will complain
+ // if there was a problem.
+ S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm);
+ }
+
+ return S.Owned(CurInitExpr);
+ }
+
+ // Determine the arguments required to actually perform the
+ // constructor call (we might have derived-to-base conversions, or
+ // the copy constructor may have default arguments).
+ if (S.CompleteConstructorCall(Constructor,
+ Sema::MultiExprArg(S,
+ (void **)&CurInitExpr,
+ 1),
+ Loc, ConstructorArgs))
+ return S.ExprError();
+
+ // Actually perform the constructor call.
+ CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
+ move_arg(ConstructorArgs));
+
+ // If we're supposed to bind temporaries, do so.
+ if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ return move(CurInit);
+}
+
+void InitializationSequence::PrintInitLocationNote(Sema &S,
+ const InitializedEntity &Entity) {
+ if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) {
+ if (Entity.getDecl()->getLocation().isInvalid())
+ return;
+
+ if (Entity.getDecl()->getDeclName())
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_named_here)
+ << Entity.getDecl()->getDeclName();
+ else
+ S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
+ }
}
Action::OwningExprResult
@@ -3304,6 +3482,7 @@ InitializationSequence::Perform(Sema &S,
case SK_CastDerivedToBaseLValue:
case SK_BindReference:
case SK_BindReferenceToTemporary:
+ case SK_ExtraneousCopyToTemporary:
case SK_UserConversion:
case SK_QualificationConversionLValue:
case SK_QualificationConversionRValue:
@@ -3348,17 +3527,20 @@ InitializationSequence::Perform(Sema &S,
// We have a derived-to-base cast that produces either an rvalue or an
// lvalue. Perform that cast.
+ CXXBaseSpecifierArray BasePath;
+
// Casts to inaccessible base classes are allowed with C-style casts.
bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
if (S.CheckDerivedToBaseConversion(SourceType, Step->Type,
CurInitExpr->getLocStart(),
- CurInitExpr->getSourceRange(),
- IgnoreBaseAccess))
+ CurInitExpr->getSourceRange(),
+ &BasePath, IgnoreBaseAccess))
return S.ExprError();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type,
CastExpr::CK_DerivedToBase,
- (Expr*)CurInit.release(),
+ (Expr*)CurInit.release(),
+ BasePath,
Step->Kind == SK_CastDerivedToBaseLValue));
break;
}
@@ -3379,6 +3561,7 @@ InitializationSequence::Perform(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element)
<< Entity.getType().isVolatileQualified()
<< CurInitExpr->getSourceRange();
+ PrintInitLocationNote(S, Entity);
return S.ExprError();
}
@@ -3399,6 +3582,11 @@ InitializationSequence::Perform(Sema &S,
break;
+ case SK_ExtraneousCopyToTemporary:
+ CurInit = CopyObject(S, Step->Type, Entity, move(CurInit),
+ /*IsExtraneousCopy=*/true);
+ break;
+
case SK_UserConversion: {
// We have a user-defined conversion that invokes either a constructor
// or a conversion function.
@@ -3406,6 +3594,7 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
+ bool CreatedObject = false;
bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
@@ -3428,7 +3617,7 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return S.ExprError();
- S.CheckConstructorAccess(Kind.getLocation(), Constructor,
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
FoundFn.getAccess());
CastKind = CastExpr::CK_ConstructorConversion;
@@ -3436,6 +3625,8 @@ InitializationSequence::Perform(Sema &S,
if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
S.IsDerivedFrom(SourceType, Class))
IsCopy = true;
+
+ CreatedObject = true;
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
@@ -3461,21 +3652,37 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError();
CastKind = CastExpr::CK_UserDefinedConversion;
+
+ CreatedObject = Conversion->getResultType()->isRecordType();
}
bool RequiresCopy = !IsCopy &&
getKind() != InitializationSequence::ReferenceBinding;
if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-
+ else if (CreatedObject && shouldDestroyTemporary(Entity)) {
+ CurInitExpr = static_cast<Expr *>(CurInit.get());
+ QualType T = CurInitExpr->getType();
+ if (const RecordType *Record = T->getAs<RecordType>()) {
+ CXXDestructorDecl *Destructor
+ = cast<CXXRecordDecl>(Record->getDecl())->getDestructor(S.Context);
+ S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor,
+ S.PDiag(diag::err_access_dtor_temp) << T);
+ S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor);
+ }
+ }
+
CurInitExpr = CurInit.takeAs<Expr>();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
+ CXXBaseSpecifierArray(),
IsLvalue));
if (RequiresCopy)
- CurInit = CopyObject(S, Entity, Kind, move(CurInit));
+ CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
+ move(CurInit), /*IsExtraneousCopy=*/false);
+
break;
}
@@ -3483,21 +3690,24 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionRValue:
// Perform a qualification conversion; these can never go wrong.
S.ImpCastExprToType(CurInitExpr, Step->Type,
- CastExpr::CK_NoOp,
+ CastExpr::CK_NoOp,
Step->Kind == SK_QualificationConversionLValue);
CurInit.release();
CurInit = S.Owned(CurInitExpr);
break;
- case SK_ConversionSequence:
- if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting,
- false, false, *Step->ICS))
+ case SK_ConversionSequence: {
+ bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast();
+
+ if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS,
+ Sema::AA_Converting, IgnoreBaseAccess))
return S.ExprError();
CurInit.release();
- CurInit = S.Owned(CurInitExpr);
+ CurInit = S.Owned(CurInitExpr);
break;
-
+ }
+
case SK_ListInitialization: {
InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
QualType Ty = Step->Type;
@@ -3510,6 +3720,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization: {
+ unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
@@ -3523,8 +3734,9 @@ InitializationSequence::Perform(Sema &S,
Loc, ConstructorArgs))
return S.ExprError();
- // Build the an expression that constructs a temporary.
+ // Build the expression that constructs a temporary.
if (Entity.getKind() == InitializedEntity::EK_Temporary &&
+ NumArgs != 1 && // FIXME: Hack to work around cast weirdness
(Kind.getKind() == InitializationKind::IK_Direct ||
Kind.getKind() == InitializationKind::IK_Value)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
@@ -3537,23 +3749,33 @@ InitializationSequence::Perform(Sema &S,
Kind.getLocation(),
Exprs,
NumExprs,
- Kind.getParenRange().getEnd()));
- } else
+ Kind.getParenRange().getEnd(),
+ ConstructorInitRequiresZeroInit));
+ } else {
+ CXXConstructExpr::ConstructionKind ConstructKind =
+ CXXConstructExpr::CK_Complete;
+
+ if (Entity.getKind() == InitializedEntity::EK_Base) {
+ ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
+ CXXConstructExpr::CK_VirtualBase :
+ CXXConstructExpr::CK_NonVirtualBase;
+ }
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
move_arg(ConstructorArgs),
ConstructorInitRequiresZeroInit,
- Entity.getKind() == InitializedEntity::EK_Base);
+ ConstructKind);
+ }
if (CurInit.isInvalid())
return S.ExprError();
// Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor,
+ S.CheckConstructorAccess(Loc, Constructor, Entity,
Step->Function.FoundDecl.getAccess());
if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-
+
break;
}
@@ -3589,10 +3811,16 @@ InitializationSequence::Perform(Sema &S,
== Sema::Compatible)
ConvTy = Sema::Compatible;
+ bool Complained;
if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
Step->Type, SourceType,
- CurInitExpr, getAssignmentAction(Entity)))
+ CurInitExpr,
+ getAssignmentAction(Entity),
+ &Complained)) {
+ PrintInitLocationNote(S, Entity);
return S.ExprError();
+ } else if (Complained)
+ PrintInitLocationNote(S, Entity);
CurInit.release();
CurInit = S.Owned(CurInitExpr);
@@ -3866,6 +4094,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}
+ PrintInitLocationNote(S, Entity);
return true;
}
@@ -4013,9 +4242,12 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
OS << "bind reference to a temporary";
break;
+ case SK_ExtraneousCopyToTemporary:
+ OS << "extraneous C++03 copy to temporary";
+ break;
+
case SK_UserConversion:
- OS << "user-defined conversion via "
- << S->Function.Function->getNameAsString();
+ OS << "user-defined conversion via " << S->Function.Function;
break;
case SK_QualificationConversionRValue:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 7c6327f8c7fa..5f2592fb77cf 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -92,11 +92,12 @@ private:
unsigned Location;
/// \brief When Kind == EK_Base, the base specifier that provides the
- /// base class.
- CXXBaseSpecifier *Base;
+ /// base class. The lower bit specifies whether the base is an inherited
+ /// virtual base.
+ uintptr_t Base;
- /// \brief When Kind = EK_ArrayElement or EK_VectorElement, 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;
};
@@ -141,7 +142,12 @@ public:
/// \brief Create the initialization entity for a parameter that is
/// only known by its type.
static InitializedEntity InitializeParameter(QualType Type) {
- return InitializedEntity(EK_Parameter, SourceLocation(), Type);
+ InitializedEntity Entity;
+ Entity.Kind = EK_Parameter;
+ Entity.Type = Type;
+ Entity.Parent = 0;
+ Entity.VariableOrMember = 0;
+ return Entity;
}
/// \brief Create the initialization entity for the result of a function.
@@ -168,7 +174,8 @@ public:
/// \brief Create the initialization entity for a base class subobject.
static InitializedEntity InitializeBase(ASTContext &Context,
- CXXBaseSpecifier *Base);
+ CXXBaseSpecifier *Base,
+ bool IsInheritedVirtualBase);
/// \brief Create the initialization entity for a member subobject.
static InitializedEntity InitializeMember(FieldDecl *Member,
@@ -204,7 +211,13 @@ public:
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
- return Base;
+ return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1);
+ }
+
+ /// \brief Return whether the base is an inherited virtual base.
+ bool isInheritedVirtualBase() const {
+ assert(getKind() == EK_Base && "Not a base specifier");
+ return Base & 0x1;
}
/// \brief Determine the location of the 'return' keyword when initializing
@@ -416,6 +429,10 @@ public:
SK_BindReference,
/// \brief Reference binding to a temporary.
SK_BindReferenceToTemporary,
+ /// \brief An optional copy of a temporary object to another
+ /// temporary object, which is permitted (but not required) by
+ /// C++98/03 but not C++0x.
+ SK_ExtraneousCopyToTemporary,
/// \brief Perform a user-defined conversion, either via a conversion
/// function or via a constructor.
SK_UserConversion,
@@ -525,7 +542,11 @@ private:
/// \brief The candidate set created when initialization failed.
OverloadCandidateSet FailedCandidateSet;
-
+
+ /// \brief Prints a follow-up note that highlights the location of
+ /// the initialized entity, if it's remote.
+ void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity);
+
public:
/// \brief Try to perform initialization of the given entity, creating a
/// record of the steps required to perform the initialization.
@@ -606,6 +627,10 @@ public:
/// \brief Determine whether this initialization failed due to an ambiguity.
bool isAmbiguous() const;
+ /// \brief Determine whether this initialization is direct call to a
+ /// constructor.
+ bool isConstructorInitialization() const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
@@ -625,11 +650,26 @@ public:
/// \brief Add a new step binding a reference to an object.
///
- /// \param BindingTemporary true if we are binding a reference to a temporary
+ /// \param BindingTemporary True if we are binding a reference to a temporary
/// object (thereby extending its lifetime); false if we are binding to an
/// lvalue or an lvalue treated as an rvalue.
+ ///
+ /// \param UnnecessaryCopy True if we should check for a copy
+ /// constructor for a completely unnecessary but
void AddReferenceBindingStep(QualType T, bool BindingTemporary);
-
+
+ /// \brief Add a new step that makes an extraneous copy of the input
+ /// to a temporary of the same class type.
+ ///
+ /// This extraneous copy only occurs during reference binding in
+ /// C++98/03, where we are permitted (but not required) to introduce
+ /// an extra copy. At a bare minimum, we must check that we could
+ /// call the copy constructor, and produce a diagnostic if the copy
+ /// constructor is inaccessible or no copy constructor matches.
+ //
+ /// \param T The type of the temporary being created.
+ void AddExtraneousCopyToTemporary(QualType T);
+
/// \brief Add a new step invoking a conversion function, which is either
/// a constructor or a conversion function.
void AddUserConversionStep(FunctionDecl *Function,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index a29c4d452814..337a4a3ce3f7 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -193,62 +193,6 @@ namespace {
};
}
-static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) {
- return D->isInIdentifierNamespace(IDNS);
-}
-
-static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) {
- return D->isInIdentifierNamespace(IDNS) &&
- !D->getDeclContext()->isRecord();
-}
-
-static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) {
- // This lookup ignores everything that isn't a type.
-
- // This is a fast check for the far most common case.
- if (D->isInIdentifierNamespace(Decl::IDNS_Tag))
- return true;
-
- if (isa<UsingShadowDecl>(D))
- D = cast<UsingShadowDecl>(D)->getTargetDecl();
-
- return isa<TypeDecl>(D);
-}
-
-static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) {
- // We don't need to look through using decls here because
- // using decls aren't allowed to name namespaces.
-
- return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D);
-}
-
-/// Gets the default result filter for the given lookup.
-static inline
-LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) {
- switch (NameKind) {
- case Sema::LookupOrdinaryName:
- case Sema::LookupTagName:
- case Sema::LookupMemberName:
- case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping
- case Sema::LookupUsingDeclName:
- case Sema::LookupObjCProtocolName:
- case Sema::LookupObjCImplementationName:
- return &IsAcceptableIDNS;
-
- case Sema::LookupOperatorName:
- return &IsAcceptableOperatorName;
-
- case Sema::LookupNestedNameSpecifierName:
- return &IsAcceptableNestedNameSpecifierName;
-
- case Sema::LookupNamespaceName:
- return &IsAcceptableNamespaceName;
- }
-
- llvm_unreachable("unkknown lookup kind");
- return 0;
-}
-
// Retrieve the set of identifier namespaces that correspond to a
// specific kind of name lookup.
static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
@@ -257,19 +201,35 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
unsigned IDNS = 0;
switch (NameKind) {
case Sema::LookupOrdinaryName:
- case Sema::LookupOperatorName:
case Sema::LookupRedeclarationWithLinkage:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
- IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend;
}
break;
+ case Sema::LookupOperatorName:
+ // Operator lookup is its own crazy thing; it is not the same
+ // as (e.g.) looking up an operator name for redeclaration.
+ assert(!Redeclaration && "cannot do redeclaration operator lookup");
+ IDNS = Decl::IDNS_NonMemberOperator;
+ break;
+
case Sema::LookupTagName:
- IDNS = Decl::IDNS_Tag;
- if (CPlusPlus && Redeclaration)
- IDNS |= Decl::IDNS_TagFriend;
+ if (CPlusPlus) {
+ IDNS = Decl::IDNS_Type;
+
+ // When looking for a redeclaration of a tag name, we add:
+ // 1) TagFriend to find undeclared friend decls
+ // 2) Namespace because they can't "overload" with tag decls.
+ // 3) Tag because it includes class templates, which can't
+ // "overload" with tag decls.
+ if (Redeclaration)
+ IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace;
+ } else {
+ IDNS = Decl::IDNS_Tag;
+ }
break;
case Sema::LookupMemberName:
@@ -279,8 +239,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
break;
case Sema::LookupNestedNameSpecifierName:
+ IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace;
+ break;
+
case Sema::LookupNamespaceName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
+ IDNS = Decl::IDNS_Namespace;
break;
case Sema::LookupUsingDeclName:
@@ -291,10 +254,6 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupObjCProtocolName:
IDNS = Decl::IDNS_ObjCProtocol;
break;
-
- case Sema::LookupObjCImplementationName:
- IDNS = Decl::IDNS_ObjCImplementation;
- break;
}
return IDNS;
}
@@ -303,7 +262,6 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind,
SemaRef.getLangOptions().CPlusPlus,
isForRedeclaration());
- IsAcceptableFn = getResultFilter(LookupKind);
// If we're looking for one of the allocation or deallocation
// operators, make sure that the implicitly-declared new and delete
@@ -341,9 +299,10 @@ void LookupResult::resolveKind() {
// If there's a single decl, we need to examine it to decide what
// kind of lookup this is.
if (N == 1) {
- if (isa<FunctionTemplateDecl>(*Decls.begin()))
+ NamedDecl *D = (*Decls.begin())->getUnderlyingDecl();
+ if (isa<FunctionTemplateDecl>(D))
ResultKind = FoundOverloaded;
- else if (isa<UnresolvedUsingValueDecl>(*Decls.begin()))
+ else if (isa<UnresolvedUsingValueDecl>(D))
ResultKind = FoundUnresolvedValue;
return;
}
@@ -1169,7 +1128,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupOperatorName:
case LookupNamespaceName:
case LookupObjCProtocolName:
- case LookupObjCImplementationName:
// These lookups will never find a member in a C++ class (or base class).
return false;
@@ -1291,7 +1249,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
/// context of the scope-specifier SS (if present).
///
/// @returns True if any decls were found (but possibly ambiguous)
-bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
+bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
bool AllowBuiltinCreation, bool EnteringContext) {
if (SS && SS->isInvalid()) {
// When the scope specifier is invalid, don't even look for
@@ -1303,7 +1261,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) {
// We have resolved the scope specifier to a particular declaration
// contex, and will perform name lookup in that context.
- if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS))
+ if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC))
return false;
R.setContextRange(SS->getRange());
@@ -1428,10 +1386,18 @@ addAssociatedClassesAndNamespaces(QualType T,
Sema::AssociatedNamespaceSet &AssociatedNamespaces,
Sema::AssociatedClassSet &AssociatedClasses);
-static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces,
- DeclContext *Ctx) {
+static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces,
+ DeclContext *Ctx) {
+ // Add the associated namespace for this class.
+
+ // We don't use DeclContext::getEnclosingNamespaceContext() as this may
+ // be a locally scoped record.
+
+ while (Ctx->isRecord() || Ctx->isTransparentContext())
+ Ctx = Ctx->getParent();
+
if (Ctx->isFileContext())
- Namespaces.insert(Ctx);
+ Namespaces.insert(Ctx->getPrimaryContext());
}
// \brief Add the associated classes and namespaces for argument-dependent
@@ -1467,9 +1433,7 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
}
break;
}
@@ -1513,9 +1477,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
// Add the class itself. If we've already seen this class, we don't
// need to visit base classes.
@@ -1537,9 +1499,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx))
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -1580,9 +1540,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class,
if (AssociatedClasses.insert(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
- while (BaseCtx->isRecord())
- BaseCtx = BaseCtx->getParent();
- CollectNamespace(AssociatedNamespaces, BaseCtx);
+ CollectEnclosingNamespace(AssociatedNamespaces, BaseCtx);
// Make sure we visit the bases of this base class.
if (BaseDecl->bases_begin() != BaseDecl->bases_end())
@@ -1657,9 +1615,7 @@ addAssociatedClassesAndNamespaces(QualType T,
AssociatedClasses.insert(EnclosingClass);
// Add the associated namespace for this class.
- while (Ctx->isRecord())
- Ctx = Ctx->getParent();
- CollectNamespace(AssociatedNamespaces, Ctx);
+ CollectEnclosingNamespace(AssociatedNamespaces, Ctx);
return;
}
@@ -1825,16 +1781,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
}
NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
+ SourceLocation Loc,
LookupNameKind NameKind,
RedeclarationKind Redecl) {
- LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl);
+ LookupResult R(*this, Name, Loc, NameKind, Redecl);
LookupName(R, S);
return R.getAsSingle<NamedDecl>();
}
/// \brief Find the protocol with the given name, if any.
-ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) {
- Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName);
+ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II,
+ SourceLocation IdLoc) {
+ Decl *D = LookupSingleName(TUScope, II, IdLoc,
+ LookupObjCProtocolName);
return cast_or_null<ObjCProtocolDecl>(D);
}
@@ -1864,16 +1823,17 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
Op != OpEnd; ++Op) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) {
+ NamedDecl *Found = (*Op)->getUnderlyingDecl();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD
+ Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD
} else if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(*Op)) {
+ = dyn_cast<FunctionTemplateDecl>(Found)) {
// FIXME: friend operators?
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
// later?
if (!FunTmpl->getDeclContext()->isRecord())
- Functions.addDecl(FunTmpl, Op.getAccess());
+ Functions.addDecl(*Op, Op.getAccess());
}
}
}
@@ -2137,7 +2097,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
IEnd = Pos->second.end();
I != IEnd; ++I) {
// A tag declaration does not hide a non-tag declaration.
- if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag &&
+ if ((*I)->hasTagIdentifierNamespace() &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
@@ -2276,6 +2236,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
true, Consumer, Visited);
}
+
+ // If there is an implementation, traverse it. We do this to find
+ // synthesized ivars.
+ if (IFace->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(IFace->getImplementation(), Result,
+ QualifiedNameLookup, true, Consumer, Visited);
+ }
} else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
E = Protocol->protocol_end(); I != E; ++I) {
@@ -2290,6 +2258,13 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
+
+ // If there is an implementation, traverse it.
+ if (Category->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(Category->getImplementation(), Result,
+ QualifiedNameLookup, true, Consumer, Visited);
+ }
}
}
@@ -2421,6 +2396,9 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
/// found (so far) with the typo name.
llvm::SmallVector<NamedDecl *, 4> BestResults;
+ /// \brief The keywords that have the smallest edit distance.
+ llvm::SmallVector<IdentifierInfo *, 4> BestKeywords;
+
/// \brief The best edit distance found so far.
unsigned BestEditDistance;
@@ -2429,13 +2407,23 @@ public:
: Typo(Typo->getName()) { }
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
+ void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
iterator begin() const { return BestResults.begin(); }
iterator end() const { return BestResults.end(); }
- bool empty() const { return BestResults.empty(); }
-
- unsigned getBestEditDistance() const { return BestEditDistance; }
+ void clear_decls() { BestResults.clear(); }
+
+ bool empty() const { return BestResults.empty() && BestKeywords.empty(); }
+
+ typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator
+ keyword_iterator;
+ keyword_iterator keyword_begin() const { return BestKeywords.begin(); }
+ keyword_iterator keyword_end() const { return BestKeywords.end(); }
+ bool keyword_empty() const { return BestKeywords.empty(); }
+ unsigned keyword_size() const { return BestKeywords.size(); }
+
+ unsigned getBestEditDistance() const { return BestEditDistance; }
};
}
@@ -2457,11 +2445,12 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
// entity. If this edit distance is not worse than the best edit
// distance we've seen so far, add it to the list of results.
unsigned ED = Typo.edit_distance(Name->getName());
- if (!BestResults.empty()) {
+ if (!BestResults.empty() || !BestKeywords.empty()) {
if (ED < BestEditDistance) {
// This result is better than any we've seen before; clear out
// the previous results.
BestResults.clear();
+ BestKeywords.clear();
BestEditDistance = ED;
} else if (ED > BestEditDistance) {
// This result is worse than the best results we've seen so far;
@@ -2474,6 +2463,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
BestResults.push_back(ND);
}
+void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
+ llvm::StringRef Keyword) {
+ // Compute the edit distance between the typo and this keyword.
+ // If this edit distance is not worse than the best edit
+ // distance we've seen so far, add it to the list of results.
+ unsigned ED = Typo.edit_distance(Keyword);
+ if (!BestResults.empty() || !BestKeywords.empty()) {
+ if (ED < BestEditDistance) {
+ BestResults.clear();
+ BestKeywords.clear();
+ BestEditDistance = ED;
+ } else if (ED > BestEditDistance) {
+ // This result is worse than the best results we've seen so far;
+ // ignore it.
+ return;
+ }
+ } else
+ BestEditDistance = ED;
+
+ BestKeywords.push_back(&Context.Idents.get(Keyword));
+}
+
/// \brief Try to "correct" a typo in the source code by finding
/// visible declarations whose names are similar to the name that was
/// present in the source code.
@@ -2494,42 +2505,50 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
+/// \param CTC The context in which typo correction occurs, which impacts the
+/// set of keywords permitted.
+///
/// \param OPT when non-NULL, the search for visible declarations will
/// also walk the protocols in the qualified interfaces of \p OPT.
///
-/// \returns true if the typo was corrected, in which case the \p Res
-/// structure will contain the results of name lookup for the
-/// corrected name. Otherwise, returns false.
-bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
- DeclContext *MemberContext, bool EnteringContext,
- const ObjCObjectPointerType *OPT) {
+/// \returns the corrected name if the typo was corrected, otherwise returns an
+/// empty \c DeclarationName. When a typo was corrected, the result structure
+/// may contain the results of name lookup for the correct name or it may be
+/// empty.
+DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ CorrectTypoContext CTC,
+ const ObjCObjectPointerType *OPT) {
if (Diags.hasFatalErrorOccurred())
- return false;
+ return DeclarationName();
// 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;
+ return DeclarationName();
++TyposCorrected;
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
if (!Typo)
- return false;
+ return DeclarationName();
// If the scope specifier itself was invalid, don't try to correct
// typos.
if (SS && SS->isInvalid())
- return false;
+ return DeclarationName();
// Never try to correct typos during template deduction or
// instantiation.
if (!ActiveTemplateInstantiations.empty())
- return false;
-
+ return DeclarationName();
+
TypoCorrectionConsumer Consumer(Typo);
+
+ // Perform name lookup to find visible, similarly-named entities.
if (MemberContext) {
LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
@@ -2543,45 +2562,239 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
} else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
- return false;
+ return DeclarationName();
LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
} else {
LookupVisibleDecls(S, Res.getLookupKind(), Consumer);
}
+ // Add context-dependent keywords.
+ bool WantTypeSpecifiers = false;
+ bool WantExpressionKeywords = false;
+ bool WantCXXNamedCasts = false;
+ bool WantRemainingKeywords = false;
+ switch (CTC) {
+ case CTC_Unknown:
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ WantCXXNamedCasts = true;
+ WantRemainingKeywords = true;
+ break;
+
+ case CTC_NoKeywords:
+ break;
+
+ case CTC_Type:
+ WantTypeSpecifiers = true;
+ break;
+
+ case CTC_ObjCMessageReceiver:
+ Consumer.addKeywordResult(Context, "super");
+ // Fall through to handle message receivers like expressions.
+
+ case CTC_Expression:
+ if (getLangOptions().CPlusPlus)
+ WantTypeSpecifiers = true;
+ WantExpressionKeywords = true;
+ // Fall through to get C++ named casts.
+
+ case CTC_CXXCasts:
+ WantCXXNamedCasts = true;
+ break;
+
+ case CTC_MemberLookup:
+ if (getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult(Context, "template");
+ break;
+ }
+
+ if (WantTypeSpecifiers) {
+ // Add type-specifier keywords to the set of results.
+ const char *CTypeSpecs[] = {
+ "char", "const", "double", "enum", "float", "int", "long", "short",
+ "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool",
+ "_Complex", "_Imaginary",
+ // storage-specifiers as well
+ "extern", "inline", "static", "typedef"
+ };
+
+ const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
+ for (unsigned I = 0; I != NumCTypeSpecs; ++I)
+ Consumer.addKeywordResult(Context, CTypeSpecs[I]);
+
+ if (getLangOptions().C99)
+ Consumer.addKeywordResult(Context, "restrict");
+ if (getLangOptions().Bool || getLangOptions().CPlusPlus)
+ Consumer.addKeywordResult(Context, "bool");
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "class");
+ Consumer.addKeywordResult(Context, "typename");
+ Consumer.addKeywordResult(Context, "wchar_t");
+
+ if (getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult(Context, "char16_t");
+ Consumer.addKeywordResult(Context, "char32_t");
+ Consumer.addKeywordResult(Context, "constexpr");
+ Consumer.addKeywordResult(Context, "decltype");
+ Consumer.addKeywordResult(Context, "thread_local");
+ }
+ }
+
+ if (getLangOptions().GNUMode)
+ Consumer.addKeywordResult(Context, "typeof");
+ }
+
+ if (WantCXXNamedCasts) {
+ Consumer.addKeywordResult(Context, "const_cast");
+ Consumer.addKeywordResult(Context, "dynamic_cast");
+ Consumer.addKeywordResult(Context, "reinterpret_cast");
+ Consumer.addKeywordResult(Context, "static_cast");
+ }
+
+ if (WantExpressionKeywords) {
+ Consumer.addKeywordResult(Context, "sizeof");
+ if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "false");
+ Consumer.addKeywordResult(Context, "true");
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ const char *CXXExprs[] = {
+ "delete", "new", "operator", "throw", "typeid"
+ };
+ const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
+ for (unsigned I = 0; I != NumCXXExprs; ++I)
+ Consumer.addKeywordResult(Context, CXXExprs[I]);
+
+ if (isa<CXXMethodDecl>(CurContext) &&
+ cast<CXXMethodDecl>(CurContext)->isInstance())
+ Consumer.addKeywordResult(Context, "this");
+
+ if (getLangOptions().CPlusPlus0x) {
+ Consumer.addKeywordResult(Context, "alignof");
+ Consumer.addKeywordResult(Context, "nullptr");
+ }
+ }
+ }
+
+ if (WantRemainingKeywords) {
+ if (getCurFunctionOrMethodDecl() || getCurBlock()) {
+ // Statements.
+ const char *CStmts[] = {
+ "do", "else", "for", "goto", "if", "return", "switch", "while" };
+ const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
+ for (unsigned I = 0; I != NumCStmts; ++I)
+ Consumer.addKeywordResult(Context, CStmts[I]);
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "catch");
+ Consumer.addKeywordResult(Context, "try");
+ }
+
+ if (S && S->getBreakParent())
+ Consumer.addKeywordResult(Context, "break");
+
+ if (S && S->getContinueParent())
+ Consumer.addKeywordResult(Context, "continue");
+
+ if (!getSwitchStack().empty()) {
+ Consumer.addKeywordResult(Context, "case");
+ Consumer.addKeywordResult(Context, "default");
+ }
+ } else {
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "namespace");
+ Consumer.addKeywordResult(Context, "template");
+ }
+
+ if (S && S->isClassScope()) {
+ Consumer.addKeywordResult(Context, "explicit");
+ Consumer.addKeywordResult(Context, "friend");
+ Consumer.addKeywordResult(Context, "mutable");
+ Consumer.addKeywordResult(Context, "private");
+ Consumer.addKeywordResult(Context, "protected");
+ Consumer.addKeywordResult(Context, "public");
+ Consumer.addKeywordResult(Context, "virtual");
+ }
+ }
+
+ if (getLangOptions().CPlusPlus) {
+ Consumer.addKeywordResult(Context, "using");
+
+ if (getLangOptions().CPlusPlus0x)
+ Consumer.addKeywordResult(Context, "static_assert");
+ }
+ }
+
+ // If we haven't found anything, we're done.
if (Consumer.empty())
- return false;
+ return DeclarationName();
// Only allow a single, closest name in the result set (it's okay to
// have overloads of that name, though).
- TypoCorrectionConsumer::iterator I = Consumer.begin();
- DeclarationName BestName = (*I)->getDeclName();
-
- // If we've found an Objective-C ivar or property, don't perform
- // name lookup again; we'll just return the result directly.
- NamedDecl *FoundBest = 0;
- if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I))
- FoundBest = *I;
- ++I;
- for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) {
- if (BestName != (*I)->getDeclName())
- return false;
-
- // FIXME: If there are both ivars and properties of the same name,
- // don't return both because the callee can't handle two
- // results. We really need to separate ivar lookup from property
- // lookup to avoid this problem.
- FoundBest = 0;
+ DeclarationName BestName;
+ NamedDecl *BestIvarOrPropertyDecl = 0;
+ bool FoundIvarOrPropertyDecl = false;
+
+ // Check all of the declaration results to find the best name so far.
+ for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
+ IEnd = Consumer.end();
+ I != IEnd; ++I) {
+ if (!BestName)
+ BestName = (*I)->getDeclName();
+ else if (BestName != (*I)->getDeclName())
+ return DeclarationName();
+
+ // \brief Keep track of either an Objective-C ivar or a property, but not
+ // both.
+ if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) {
+ if (FoundIvarOrPropertyDecl)
+ BestIvarOrPropertyDecl = 0;
+ else {
+ BestIvarOrPropertyDecl = *I;
+ FoundIvarOrPropertyDecl = true;
+ }
+ }
}
+ // Now check all of the keyword results to find the best name.
+ switch (Consumer.keyword_size()) {
+ case 0:
+ // No keywords matched.
+ break;
+
+ case 1:
+ // If we already have a name
+ if (!BestName) {
+ // We did not have anything previously,
+ BestName = *Consumer.keyword_begin();
+ } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) {
+ // We have a declaration with the same name as a context-sensitive
+ // keyword. The keyword takes precedence.
+ BestIvarOrPropertyDecl = 0;
+ FoundIvarOrPropertyDecl = false;
+ Consumer.clear_decls();
+ } else {
+ // Name collision; we will not correct typos.
+ return DeclarationName();
+ }
+ break;
+
+ default:
+ // Name collision; we will not correct typos.
+ return DeclarationName();
+ }
+
// BestName is the closest viable name to what the user
// typed. However, to make sure that we don't pick something that's
// way off, make sure that the user typed at least 3 characters for
// each correction.
unsigned ED = Consumer.getBestEditDistance();
- if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
- return false;
+ if (ED == 0 || !BestName.getAsIdentifierInfo() ||
+ (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3)
+ return DeclarationName();
// Perform name lookup again with the name we chose, and declare
// success if we found something that was not ambiguous.
@@ -2590,11 +2803,14 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// If we found an ivar or property, add that result; no further
// lookup is required.
- if (FoundBest)
- Res.addDecl(FoundBest);
+ if (BestIvarOrPropertyDecl)
+ Res.addDecl(BestIvarOrPropertyDecl);
// If we're looking into the context of a member, perform qualified
// name lookup on the best name.
- else if (MemberContext)
+ else if (!Consumer.keyword_empty()) {
+ // The best match was a keyword. Return it.
+ return BestName;
+ } else if (MemberContext)
LookupQualifiedName(Res, MemberContext);
// Perform lookup as if we had just parsed the best name.
else
@@ -2603,8 +2819,11 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
if (Res.isAmbiguous()) {
Res.suppressDiagnostics();
- return false;
+ return DeclarationName();
}
- return Res.getResultKind() != LookupResult::NotFound;
+ if (Res.getResultKind() != LookupResult::NotFound)
+ return BestName;
+
+ return DeclarationName();
}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index cda1f0be2023..b73739fc5551 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -204,7 +204,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
ObjCInterfaceDecl *IDecl = OIT->getDecl();
if (IDecl)
if (ObjCProtocolDecl* PNSCopying =
- LookupProtocol(&Context.Idents.get("NSCopying")))
+ LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc))
if (IDecl->ClassImplementsProtocol(PNSCopying, true))
Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId;
}
@@ -356,7 +356,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (!Ivar) {
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc,
PropertyIvar, PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public,
+ ObjCIvarDecl::Protected,
(Expr *)0);
ClassImpDecl->addDecl(Ivar);
IDecl->makeDeclVisibleInContext(Ivar, false);
@@ -719,7 +719,10 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
E = IDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap);
+ // Exclude property for protocols which conform to class's super-class,
+ // as super-class has to implement the property.
+ if (!ProtocolConformsToSuperClass(IDecl, (*PI)))
+ CollectImmediateProperties((*PI), PropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
if (!CATDecl->IsClassExtension())
@@ -748,6 +751,33 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
+/// ProtocolConformsToSuperClass - Returns true if class's given protocol
+/// conforms to one of its super class's protocols.
+bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl,
+ const ObjCProtocolDecl *PDecl) {
+ if (const ObjCInterfaceDecl *CDecl = IDecl->getSuperClass()) {
+ for (ObjCInterfaceDecl::protocol_iterator PI = CDecl->protocol_begin(),
+ E = CDecl->protocol_end(); PI != E; ++PI) {
+ if (ProtocolConformsToProtocol((*PI), PDecl))
+ return true;
+ return ProtocolConformsToSuperClass(CDecl, PDecl);
+ }
+ }
+ return false;
+}
+
+bool Sema::ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol,
+ const ObjCProtocolDecl *PDecl) {
+ if (PDecl->getIdentifier() == NestedProtocol->getIdentifier())
+ return true;
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ if (ProtocolConformsToProtocol(NestedProtocol, (*PI)))
+ return true;
+ return false;
+}
+
/// LookupPropertyDecl - Looks up a property in the current class and all
/// its protocols.
ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
@@ -810,9 +840,9 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop))
continue;
- if (LangOpts.ObjCNonFragileABI2) {
+ if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) {
ActOnPropertyImplDecl(IMPDecl->getLocation(),
- SourceLocation(),
+ IMPDecl->getLocation(),
true, DeclPtrTy::make(IMPDecl),
Prop->getIdentifier(),
Prop->getIdentifier());
@@ -953,8 +983,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getType(),
/*TInfo=*/0,
VarDecl::None,
+ VarDecl::None,
0);
- SetterMethod->setMethodParams(Context, &Argument, 1);
+ SetterMethod->setMethodParams(Context, &Argument, 1, 1);
CD->addDecl(SetterMethod);
} else
// A user declared setter will be synthesize when @synthesize of
@@ -1066,21 +1097,3 @@ void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
&& PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
}
-
-ObjCIvarDecl*
-Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl,
- IdentifierInfo *NameII) {
- ObjCIvarDecl *Ivar = 0;
- ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII);
- if (Prop && !Prop->isInvalidDecl()) {
- QualType PropType = Context.getCanonicalType(Prop->getType());
- Ivar = ObjCIvarDecl::Create(Context, IDecl, Prop->getLocation(), NameII,
- PropType, /*Dinfo=*/0,
- ObjCIvarDecl::Public, (Expr *)0);
- Ivar->setLexicalDeclContext(IDecl);
- IDecl->addDecl(Ivar);
- Prop->setPropertyIvarDecl(Ivar);
- }
- return Ivar;
-}
-
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index bc10a58d6b20..21f2a51040ec 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -226,7 +226,7 @@ void UserDefinedConversionSequence::DebugPrint() const {
Before.DebugPrint();
OS << " -> ";
}
- OS << "'" << ConversionFunction->getNameAsString() << "'";
+ OS << '\'' << ConversionFunction << '\'';
if (After.First || After.Second || After.Third) {
OS << " -> ";
After.DebugPrint();
@@ -374,8 +374,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
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())))
+ !FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -436,16 +435,11 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) {
/// not permitted.
/// If @p AllowExplicit, then explicit user-defined conversions are
/// permitted.
-/// If @p ForceRValue, then overloading is performed as if From was an rvalue,
-/// no matter its actual lvalueness.
-/// If @p UserCast, the implicit conversion is being done for a user-specified
-/// cast.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit, bool ForceRValue,
- bool InOverloadResolution,
- bool UserCast) {
+ bool AllowExplicit,
+ bool InOverloadResolution) {
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) {
ICS.setStandard();
@@ -457,11 +451,47 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
+ if (SuppressUserConversions) {
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy/move
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ QualType FromType = From->getType();
+ if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() ||
+ !(Context.hasSameUnqualifiedType(FromType, ToType) ||
+ IsDerivedFrom(FromType, ToType))) {
+ // We're not in the case above, so there is no conversion that
+ // we can perform.
+ ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
+ return ICS;
+ }
+
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ ICS.Standard.setFromType(FromType);
+ ICS.Standard.setAllToTypes(ToType);
+
+ // We don't actually check at this point whether there is a valid
+ // copy/move constructor, since overloading just assumes that it
+ // exists. When we actually perform initialization, we'll find the
+ // appropriate constructor to copy the returned object, if needed.
+ ICS.Standard.CopyConstructor = 0;
+
+ // Determine whether this is considered a derived-to-base conversion.
+ if (!Context.hasSameUnqualifiedType(FromType, ToType))
+ ICS.Standard.Second = ICK_Derived_To_Base;
+
+ return ICS;
+ }
+
+ // Attempt user-defined conversion.
OverloadCandidateSet Conversions(From->getExprLoc());
OverloadingResult UserDefResult
= IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions,
- !SuppressUserConversions, AllowExplicit,
- ForceRValue, UserCast);
+ AllowExplicit);
if (UserDefResult == OR_Success) {
ICS.setUserDefined();
@@ -516,6 +546,30 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
return ICS;
}
+/// PerformImplicitConversion - Perform an implicit conversion of the
+/// expression From to the type ToType. Returns true if there was an
+/// error, false otherwise. The expression From is replaced with the
+/// converted expression. Flavor is the kind of conversion we're
+/// performing, used in the error message. If @p AllowExplicit,
+/// explicit user-defined conversions are permitted.
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ AssignmentAction Action, bool AllowExplicit) {
+ ImplicitConversionSequence ICS;
+ return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
+}
+
+bool
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+ AssignmentAction Action, bool AllowExplicit,
+ ImplicitConversionSequence& ICS) {
+ ICS = TryImplicitConversion(From, ToType,
+ /*SuppressUserConversions=*/false,
+ AllowExplicit,
+ /*InOverloadResolution=*/false);
+ return PerformImplicitConversion(From, ToType, ICS, Action);
+}
+
/// \brief Determine whether the conversion from FromType to ToType is a valid
/// conversion that strips "noreturn" off the nested function type.
static bool IsNoReturnConversion(ASTContext &Context, QualType FromType,
@@ -567,8 +621,36 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
- DeclAccessPair AccessPair;
-
+ if (FromType == Context.OverloadTy) {
+ DeclAccessPair AccessPair;
+ if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(From, ToType, false,
+ AccessPair)) {
+ // We were able to resolve the address of the overloaded function,
+ // so we can convert to the type of that function.
+ FromType = Fn->getType();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+ if (!Method->isStatic()) {
+ Type *ClassType
+ = Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FromType = Context.getMemberPointerType(FromType, ClassType);
+ }
+ }
+
+ // If the "from" expression takes the address of the overloaded
+ // function, update the type of the resulting expression accordingly.
+ if (FromType->getAs<FunctionType>())
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens()))
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ FromType = Context.getPointerType(FromType);
+
+ // Check that we've computed the proper type after overload resolution.
+ assert(Context.hasSameType(FromType,
+ FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+ } else {
+ return false;
+ }
+ }
// Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
@@ -613,31 +695,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
- } else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false,
- AccessPair)) {
- // Address of overloaded function (C++ [over.over]).
- SCS.First = ICK_Function_To_Pointer;
-
- // We were able to resolve the address of the overloaded function,
- // so we can convert to the type of that function.
- FromType = Fn->getType();
- if (ToType->isLValueReferenceType())
- FromType = Context.getLValueReferenceType(FromType);
- else if (ToType->isRValueReferenceType())
- FromType = Context.getRValueReferenceType(FromType);
- else if (ToType->isMemberPointerType()) {
- // Resolve address only succeeds if both sides are member pointers,
- // but it doesn't have to be the same class. See DR 247.
- // Note that this means that the type of &Derived::fn can be
- // Ret (Base::*)(Args) if the fn overload actually found is from the
- // base class, even if it was brought into the derived class via a
- // using declaration. The standard isn't clear on this issue at all.
- CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
- FromType = Context.getMemberPointerType(FromType,
- Context.getTypeDeclType(M->getParent()).getTypePtr());
- } else
- FromType = Context.getPointerType(FromType);
} else {
// We don't require any conversions for the first step.
SCS.First = ICK_Identity;
@@ -1274,6 +1331,47 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
return false;
}
+
+/// FunctionArgTypesAreEqual - This routine checks two function proto types
+/// for equlity of their argument types. Caller has already checked that
+/// they have same number of arguments. This routine assumes that Objective-C
+/// pointer types which only differ in their protocol qualifiers are equal.
+bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType,
+ FunctionProtoType* NewType){
+ if (!getLangOptions().ObjC1)
+ return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
+ NewType->arg_type_begin());
+
+ for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
+ N = NewType->arg_type_begin(),
+ E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
+ QualType ToType = (*O);
+ QualType FromType = (*N);
+ if (ToType != FromType) {
+ if (const PointerType *PTTo = ToType->getAs<PointerType>()) {
+ if (const PointerType *PTFr = FromType->getAs<PointerType>())
+ if (PTTo->getPointeeType()->isObjCQualifiedIdType() &&
+ PTFr->getPointeeType()->isObjCQualifiedIdType() ||
+ PTTo->getPointeeType()->isObjCQualifiedClassType() &&
+ PTFr->getPointeeType()->isObjCQualifiedClassType())
+ continue;
+ }
+ else if (ToType->isObjCObjectPointerType() &&
+ FromType->isObjCObjectPointerType()) {
+ QualType ToInterfaceTy = ToType->getPointeeType();
+ QualType FromInterfaceTy = FromType->getPointeeType();
+ if (const ObjCInterfaceType *OITTo =
+ ToInterfaceTy->getAs<ObjCInterfaceType>())
+ if (const ObjCInterfaceType *OITFr =
+ FromInterfaceTy->getAs<ObjCInterfaceType>())
+ if (OITTo->getDecl() == OITFr->getDecl())
+ continue;
+ }
+ return false;
+ }
+ }
+ return true;
+}
/// CheckPointerConversion - Check the pointer conversion from the
/// expression From to the type ToType. This routine checks for
@@ -1283,6 +1381,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
/// error, or returns false otherwise.
bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray& BasePath,
bool IgnoreBaseAccess) {
QualType FromType = From->getType();
@@ -1297,7 +1396,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
// ambiguous or inaccessible conversion.
if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType,
From->getExprLoc(),
- From->getSourceRange(),
+ From->getSourceRange(), &BasePath,
IgnoreBaseAccess))
return true;
@@ -1368,6 +1467,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
/// otherwise.
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
CastExpr::CastKind &Kind,
+ CXXBaseSpecifierArray &BasePath,
bool IgnoreBaseAccess) {
QualType FromType = From->getType();
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
@@ -1391,7 +1491,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=*/ true,
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths);
assert(DerivationOkay &&
@@ -1419,6 +1519,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
diag::err_downcast_from_inaccessible_base);
// Must be a base to derived member conversion.
+ BuildBasePathArray(Paths, BasePath);
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
return false;
}
@@ -1482,48 +1583,39 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) {
/// and this routine will return true. Otherwise, this routine returns
/// false and User is unspecified.
///
-/// \param AllowConversionFunctions true if the conversion should
-/// consider conversion functions at all. If false, only constructors
-/// will be considered.
-///
/// \param AllowExplicit true if the conversion should consider C++0x
/// "explicit" conversion functions as well as non-explicit conversion
/// functions (C++0x [class.conv.fct]p2).
-///
-/// \param ForceRValue true if the expression should be treated as an rvalue
-/// for overload resolution.
-/// \param UserCast true if looking for user defined conversion for a static
-/// cast.
OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
- OverloadCandidateSet& CandidateSet,
- bool AllowConversionFunctions,
- bool AllowExplicit,
- bool ForceRValue,
- bool UserCast) {
+ OverloadCandidateSet& CandidateSet,
+ bool AllowExplicit) {
+ // Whether we will only visit constructors.
+ bool ConstructorsOnly = false;
+
+ // If the type we are conversion to is a class type, enumerate its
+ // constructors.
if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) {
+ // C++ [over.match.ctor]p1:
+ // When objects of class type are direct-initialized (8.5), or
+ // copy-initialized from an expression of the same or a
+ // derived class type (8.5), overload resolution selects the
+ // constructor. [...] For copy-initialization, the candidate
+ // functions are all the converting constructors (12.3.1) of
+ // that class. The argument list is the expression-list within
+ // the parentheses of the initializer.
+ if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
+ (From->getType()->getAs<RecordType>() &&
+ IsDerivedFrom(From->getType(), ToType)))
+ ConstructorsOnly = true;
+
if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) {
// We're not going to find any constructors.
} else if (CXXRecordDecl *ToRecordDecl
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
- // C++ [over.match.ctor]p1:
- // When objects of class type are direct-initialized (8.5), or
- // copy-initialized from an expression of the same or a
- // derived class type (8.5), overload resolution selects the
- // constructor. [...] For copy-initialization, the candidate
- // functions are all the converting constructors (12.3.1) of
- // that class. The argument list is the expression-list within
- // the parentheses of the initializer.
- bool SuppressUserConversions = !UserCast;
- if (Context.hasSameUnqualifiedType(ToType, From->getType()) ||
- IsDerivedFrom(From->getType(), ToType)) {
- SuppressUserConversions = false;
- AllowConversionFunctions = false;
- }
-
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ToType).getUnqualifiedType());
+ Context.getCanonicalType(ToType).getUnqualifiedType());
DeclContext::lookup_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd)
= ToRecordDecl->lookup(ConstructorName);
@@ -1547,26 +1639,25 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
/*ExplicitArgs*/ 0,
&From, 1, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ /*SuppressUserConversions=*/!ConstructorsOnly);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
AddOverloadCandidate(Constructor, FoundDecl,
&From, 1, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ /*SuppressUserConversions=*/!ConstructorsOnly);
}
}
}
}
- if (!AllowConversionFunctions) {
- // Don't allow any conversion functions to enter the overload set.
+ // Enumerate conversion functions, if we're allowed to.
+ if (ConstructorsOnly) {
} else if (RequireCompleteType(From->getLocStart(), From->getType(),
- PDiag(0)
- << From->getSourceRange())) {
+ PDiag(0) << From->getSourceRange())) {
// No conversion functions from incomplete types.
} else if (const RecordType *FromRecordType
- = From->getType()->getAs<RecordType>()) {
+ = From->getType()->getAs<RecordType>()) {
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
@@ -1672,7 +1763,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadCandidateSet CandidateSet(From->getExprLoc());
OverloadingResult OvResult =
IsUserDefinedConversion(From, ToType, ICS.UserDefined,
- CandidateSet, true, false, false);
+ CandidateSet, false);
if (OvResult == OR_Ambiguous)
Diag(From->getSourceRange().getBegin(),
diag::err_typecheck_ambiguous_condition)
@@ -1708,15 +1799,14 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// described in 13.3.3.2, the ambiguous conversion sequence is
// treated as a user-defined sequence that is indistinguishable
// from any other user-defined conversion sequence.
- if (ICS1.getKind() < ICS2.getKind()) {
- if (!(ICS1.isUserDefined() && ICS2.isAmbiguous()))
- return ImplicitConversionSequence::Better;
- } else if (ICS2.getKind() < ICS1.getKind()) {
- if (!(ICS2.isUserDefined() && ICS1.isAmbiguous()))
- return ImplicitConversionSequence::Worse;
- }
+ if (ICS1.getKindRank() < ICS2.getKindRank())
+ return ImplicitConversionSequence::Better;
+ else if (ICS2.getKindRank() < ICS1.getKindRank())
+ return ImplicitConversionSequence::Worse;
- if (ICS1.isAmbiguous() || ICS2.isAmbiguous())
+ // The following checks require both conversion sequences to be of
+ // the same kind.
+ if (ICS1.getKind() != ICS2.getKind())
return ImplicitConversionSequence::Indistinguishable;
// Two implicit conversion sequences of the same form are
@@ -2143,9 +2233,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
}
}
- if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) &&
- (SCS2.ReferenceBinding || SCS2.CopyConstructor) &&
- SCS1.Second == ICK_Derived_To_Base) {
+ if (SCS1.Second == ICK_Derived_To_Base) {
// -- conversion of C to B is better than conversion of C to A,
// -- binding of an expression of type C to a reference of type
// B& is better than binding an expression of type C to a
@@ -2174,34 +2262,353 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
return ImplicitConversionSequence::Indistinguishable;
}
+/// CompareReferenceRelationship - Compare the two types T1 and T2 to
+/// determine whether they are reference-related,
+/// reference-compatible, reference-compatible with added
+/// qualification, or incompatible, for use in C++ initialization by
+/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
+/// type, and the first type (T1) is the pointee type of the reference
+/// type being initialized.
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(SourceLocation Loc,
+ QualType OrigT1, QualType OrigT2,
+ bool& DerivedToBase) {
+ assert(!OrigT1->isReferenceType() &&
+ "T1 must be the pointee type of the reference type");
+ assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
+
+ QualType T1 = Context.getCanonicalType(OrigT1);
+ QualType T2 = Context.getCanonicalType(OrigT2);
+ Qualifiers T1Quals, T2Quals;
+ QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+ QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
+
+ // C++ [dcl.init.ref]p4:
+ // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
+ // reference-related to "cv2 T2" if T1 is the same type as T2, or
+ // T1 is a base class of T2.
+ if (UnqualT1 == UnqualT2)
+ DerivedToBase = false;
+ else if (!RequireCompleteType(Loc, OrigT1, PDiag()) &&
+ !RequireCompleteType(Loc, OrigT2, PDiag()) &&
+ IsDerivedFrom(UnqualT2, UnqualT1))
+ DerivedToBase = true;
+ else
+ return Ref_Incompatible;
+
+ // At this point, we know that T1 and T2 are reference-related (at
+ // least).
+
+ // If the type is an array type, promote the element qualifiers to the type
+ // for comparison.
+ if (isa<ArrayType>(T1) && T1Quals)
+ T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+ if (isa<ArrayType>(T2) && T2Quals)
+ T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
+ // C++ [dcl.init.ref]p4:
+ // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
+ // reference-related to T2 and cv1 is the same cv-qualification
+ // as, or greater cv-qualification than, cv2. For purposes of
+ // overload resolution, cases for which cv1 is greater
+ // cv-qualification than cv2 are identified as
+ // reference-compatible with added qualification (see 13.3.3.2).
+ if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
+ return Ref_Compatible;
+ else if (T1.isMoreQualifiedThan(T2))
+ return Ref_Compatible_With_Added_Qualification;
+ else
+ return Ref_Related;
+}
+
+/// \brief Compute an implicit conversion sequence for reference
+/// initialization.
+static ImplicitConversionSequence
+TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
+ SourceLocation DeclLoc,
+ bool SuppressUserConversions,
+ bool AllowExplicit) {
+ assert(DeclType->isReferenceType() && "Reference init needs a reference");
+
+ // Most paths end in a failed conversion.
+ ImplicitConversionSequence ICS;
+ ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
+
+ QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
+ QualType T2 = Init->getType();
+
+ // If the initializer is the address of an overloaded function, try
+ // to resolve the overloaded function. If all goes well, T2 is the
+ // type of the resulting function.
+ if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
+ DeclAccessPair Found;
+ if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType,
+ false, Found))
+ T2 = Fn->getType();
+ }
+
+ // Compute some basic properties of the types and the initializer.
+ bool isRValRef = DeclType->isRValueReferenceType();
+ bool DerivedToBase = false;
+ Expr::isLvalueResult InitLvalue = Init->isLvalue(S.Context);
+ Sema::ReferenceCompareResult RefRelationship
+ = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
+
+
+ // C++ [over.ics.ref]p3:
+ // Except for an implicit object parameter, for which see 13.3.1,
+ // a standard conversion sequence cannot be formed if it requires
+ // binding an lvalue reference to non-const to an rvalue or
+ // binding an rvalue reference to an lvalue.
+ //
+ // FIXME: DPG doesn't trust this code. It seems far too early to
+ // abort because of a binding of an rvalue reference to an lvalue.
+ if (isRValRef && InitLvalue == Expr::LV_Valid)
+ return ICS;
+
+ // C++0x [dcl.init.ref]p16:
+ // A reference to type "cv1 T1" is initialized by an expression
+ // of type "cv2 T2" as follows:
+
+ // -- If the initializer expression
+ // -- is an lvalue (but is not a bit-field), and "cv1 T1" is
+ // reference-compatible with "cv2 T2," or
+ //
+ // Per C++ [over.ics.ref]p4, we don't check the bit-field property here.
+ if (InitLvalue == Expr::LV_Valid &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ // C++ [over.ics.ref]p1:
+ // When a parameter of reference type binds directly (8.5.3)
+ // to an argument expression, the implicit conversion sequence
+ // is the identity conversion, unless the argument expression
+ // has a type that is a derived class of the parameter type,
+ // in which case the implicit conversion sequence is a
+ // derived-to-base Conversion (13.3.3.1).
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.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;
+ ICS.Standard.CopyConstructor = 0;
+
+ // Nothing more to do: the inaccessibility/ambiguity check for
+ // derived-to-base conversions is suppressed when we're
+ // computing the implicit conversion sequence (C++
+ // [over.best.ics]p2).
+ return ICS;
+ }
+
+ // -- has a class type (i.e., T2 is a class type), where T1 is
+ // not reference-related to T2, and can be implicitly
+ // converted to an lvalue of type "cv3 T3," where "cv1 T1"
+ // is reference-compatible with "cv3 T3" 92) (this
+ // conversion is selected by enumerating the applicable
+ // conversion functions (13.3.1.6) and choosing the best
+ // one through overload resolution (13.3)),
+ if (!isRValRef && !SuppressUserConversions && T2->isRecordType() &&
+ !S.RequireCompleteType(DeclLoc, T2, 0) &&
+ RefRelationship == Sema::Ref_Incompatible) {
+ CXXRecordDecl *T2RecordDecl
+ = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
+
+ OverloadCandidateSet CandidateSet(DeclLoc);
+ const UnresolvedSetImpl *Conversions
+ = T2RecordDecl->getVisibleConversionFunctions();
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = *I;
+ CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ FunctionTemplateDecl *ConvTemplate
+ = dyn_cast<FunctionTemplateDecl>(D);
+ CXXConversionDecl *Conv;
+ if (ConvTemplate)
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ else
+ Conv = cast<CXXConversionDecl>(D);
+
+ // If the conversion function doesn't return a reference type,
+ // it can't be considered for this conversion.
+ if (Conv->getConversionType()->isLValueReferenceType() &&
+ (AllowExplicit || !Conv->isExplicit())) {
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
+ Init, DeclType, CandidateSet);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
+ DeclType, CandidateSet);
+ }
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
+ case OR_Success:
+ // C++ [over.ics.ref]p1:
+ //
+ // [...] If the parameter binds directly to the result of
+ // applying a conversion function to the argument
+ // expression, the implicit conversion sequence is a
+ // user-defined conversion sequence (13.3.3.1.2), with the
+ // second standard conversion sequence either an identity
+ // conversion or, if the conversion function returns an
+ // entity of a type that is a derived class of the parameter
+ // type, a derived-to-base Conversion.
+ if (!Best->FinalConversion.DirectBinding)
+ break;
+
+ ICS.setUserDefined();
+ ICS.UserDefined.Before = Best->Conversions[0].Standard;
+ ICS.UserDefined.After = Best->FinalConversion;
+ ICS.UserDefined.ConversionFunction = Best->Function;
+ ICS.UserDefined.EllipsisConversion = false;
+ assert(ICS.UserDefined.After.ReferenceBinding &&
+ ICS.UserDefined.After.DirectBinding &&
+ "Expected a direct reference binding!");
+ return ICS;
+
+ case OR_Ambiguous:
+ ICS.setAmbiguous();
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
+ Cand != CandidateSet.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ return ICS;
+
+ case OR_No_Viable_Function:
+ case OR_Deleted:
+ // There was no suitable conversion, or we found a deleted
+ // conversion; continue with other checks.
+ break;
+ }
+ }
+
+ // -- Otherwise, the reference shall be to a 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.
+ //
+ // We actually handle one oddity of C++ [over.ics.ref] at this
+ // point, which is that, due to p2 (which short-circuits reference
+ // binding by only attempting a simple conversion for non-direct
+ // bindings) and p3's strange wording, we allow a const volatile
+ // reference to bind to an rvalue. Hence the check for the presence
+ // of "const" rather than checking for "const" being the only
+ // qualifier.
+ if (!isRValRef && !T1.isConstQualified())
+ return ICS;
+
+ // -- if T2 is a class type and
+ // -- the initializer expression is an rvalue and "cv1 T1"
+ // is reference-compatible with "cv2 T2," or
+ //
+ // -- T1 is not reference-related to T2 and the initializer
+ // expression can be implicitly converted to an rvalue
+ // of type "cv3 T3" (this conversion is selected by
+ // enumerating the applicable conversion functions
+ // (13.3.1.6) and choosing the best one through overload
+ // resolution (13.3)),
+ //
+ // then the reference is bound to the initializer
+ // expression rvalue in the first case and to the object
+ // that is the result of the conversion in the second case
+ // (or, in either case, to the appropriate base class
+ // subobject of the object).
+ //
+ // We're only checking the first case here, which is a direct
+ // binding in C++0x but not in C++03.
+ if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
+ RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+ ICS.Standard.Third = ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x;
+ ICS.Standard.RRefBinding = isRValRef;
+ ICS.Standard.CopyConstructor = 0;
+ return ICS;
+ }
+
+ // -- Otherwise, a temporary of type "cv1 T1" is created and
+ // initialized from the initializer expression using the
+ // rules for a non-reference copy initialization (8.5). The
+ // reference is then bound to the temporary. If T1 is
+ // reference-related to T2, cv1 must be the same
+ // cv-qualification as, or greater cv-qualification than,
+ // cv2; otherwise, the program is ill-formed.
+ if (RefRelationship == Sema::Ref_Related) {
+ // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
+ // we would be reference-compatible or reference-compatible with
+ // added qualification. But that wasn't the case, so the reference
+ // initialization fails.
+ return ICS;
+ }
+
+ // If at least one of the types is a class type, the types are not
+ // related, and we aren't allowed any user conversions, the
+ // reference binding fails. This case is important for breaking
+ // recursion, since TryImplicitConversion below will attempt to
+ // create a temporary through the use of a copy constructor.
+ if (SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible &&
+ (T1->isRecordType() || T2->isRecordType()))
+ return ICS;
+
+ // C++ [over.ics.ref]p2:
+ // When a parameter of reference type is not bound directly to
+ // an argument expression, the conversion sequence is the one
+ // required to convert the argument expression to the
+ // underlying type of the reference according to
+ // 13.3.3.1. Conceptually, this conversion sequence corresponds
+ // to copy-initializing a temporary of the underlying type with
+ // the argument expression. Any difference in top-level
+ // cv-qualification is subsumed by the initialization itself
+ // and does not constitute a conversion.
+ ICS = S.TryImplicitConversion(Init, T1, SuppressUserConversions,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false);
+
+ // Of course, that's still a reference binding.
+ if (ICS.isStandard()) {
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.RRefBinding = isRValRef;
+ } else if (ICS.isUserDefined()) {
+ ICS.UserDefined.After.ReferenceBinding = true;
+ ICS.UserDefined.After.RRefBinding = isRValRef;
+ }
+ return ICS;
+}
+
/// TryCopyInitialization - Try to copy-initialize a value of type
/// ToType from the expression From. Return the implicit conversion
/// sequence required to pass this argument, which may be a bad
/// conversion sequence (meaning that the argument cannot be passed to
/// a parameter of this type). If @p SuppressUserConversions, then we
-/// do not permit any user-defined conversion sequences. If @p ForceRValue,
-/// then we treat @p From as an rvalue, even if it is an lvalue.
-ImplicitConversionSequence
-Sema::TryCopyInitialization(Expr *From, QualType ToType,
- bool SuppressUserConversions, bool ForceRValue,
- bool InOverloadResolution) {
- if (ToType->isReferenceType()) {
- ImplicitConversionSequence ICS;
- ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
- CheckReferenceInit(From, ToType,
- /*FIXME:*/From->getLocStart(),
- SuppressUserConversions,
- /*AllowExplicit=*/false,
- ForceRValue,
- &ICS);
- return ICS;
- } else {
- return TryImplicitConversion(From, ToType,
+/// do not permit any user-defined conversion sequences.
+static ImplicitConversionSequence
+TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
+ bool SuppressUserConversions,
+ bool InOverloadResolution) {
+ if (ToType->isReferenceType())
+ return TryReferenceInit(S, From, ToType,
+ /*FIXME:*/From->getLocStart(),
+ SuppressUserConversions,
+ /*AllowExplicit=*/false);
+
+ return S.TryImplicitConversion(From, ToType,
SuppressUserConversions,
/*AllowExplicit=*/false,
- ForceRValue,
InOverloadResolution);
- }
}
/// TryObjectArgumentInitialization - Try to initialize the object
@@ -2310,7 +2717,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
if (!Context.hasSameType(From->getType(), DestType))
ImpCastExprToType(From, DestType, CastExpr::CK_NoOp,
- /*isLvalue=*/!From->getType()->getAs<PointerType>());
+ /*isLvalue=*/!From->getType()->isPointerType());
return false;
}
@@ -2321,7 +2728,6 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
// FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/true,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
@@ -2343,9 +2749,6 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
/// conversions via constructors or conversion operators.
-/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly
-/// hacky way to implement the overloading rules for elidable copy
-/// initialization in C++0x (C++0x 12.8p15).
///
/// \para PartialOverloading true if we are performing "partial" overloading
/// based on an incomplete set of function arguments. This feature is used by
@@ -2356,7 +2759,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
- bool ForceRValue,
bool PartialOverloading) {
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
@@ -2375,7 +2777,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// is irrelevant.
AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Args, NumArgs, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ SuppressUserConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -2445,8 +2847,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
+ SuppressUserConversions,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
@@ -2504,7 +2906,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions, bool ForceRValue) {
+ bool SuppressUserConversions) {
NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
@@ -2518,12 +2920,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
/*ExplicitArgs*/ 0,
ObjectType, Args, NumArgs,
CandidateSet,
- SuppressUserConversions,
- ForceRValue);
+ SuppressUserConversions);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, Args, NumArgs,
- CandidateSet, SuppressUserConversions, ForceRValue);
+ CandidateSet, SuppressUserConversions);
}
}
@@ -2533,15 +2934,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
/// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain
/// both @c a1 and @c a2. If @p SuppressUserConversions, then don't
/// allow user-defined conversions via constructors or conversion
-/// operators. If @p ForceRValue, treat all arguments as rvalues. This is
-/// a slightly hacky way to implement the overloading rules for elidable copy
-/// initialization in C++0x (C++0x 12.8p15).
+/// operators.
void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions, bool ForceRValue) {
+ bool SuppressUserConversions) {
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -2614,8 +3013,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
- SuppressUserConversions, ForceRValue,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
+ SuppressUserConversions,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
@@ -2642,8 +3041,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
QualType ObjectType,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool ForceRValue) {
+ bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(MethodTmpl))
return;
@@ -2674,7 +3072,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, Args, NumArgs,
- CandidateSet, SuppressUserConversions, ForceRValue);
+ CandidateSet, SuppressUserConversions);
}
/// \brief Add a C++ function template specialization as a candidate
@@ -2686,8 +3084,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool ForceRValue) {
+ bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
@@ -2724,7 +3121,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet,
- SuppressUserConversions, ForceRValue);
+ SuppressUserConversions);
}
/// AddConversionCandidate - Add a C++ conversion function as a
@@ -2741,7 +3138,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
OverloadCandidateSet& CandidateSet) {
assert(!Conversion->getDescribedFunctionTemplate() &&
"Conversion function templates use AddTemplateConversionCandidate");
-
+ QualType ConvType = Conversion->getConversionType().getNonReferenceType();
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -2756,7 +3153,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.setFromType(Conversion->getConversionType());
+ Candidate.FinalConversion.setFromType(ConvType);
Candidate.FinalConversion.setAllToTypes(ToType);
// Determine the implicit conversion sequence for the implicit
@@ -2789,7 +3186,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
return;
}
-
// To determine what the conversion from the result of calling the
// conversion function to the type we're eventually trying to
// convert to (ToType), we need to synthesize a call to the
@@ -2802,7 +3198,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
From->getLocStart());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
CastExpr::CK_FunctionToPointerDecay,
- &ConversionRef, false);
+ &ConversionRef, CXXBaseSpecifierArray(), false);
// Note that it is safe to allocate CallExpr on the stack here because
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
@@ -2811,14 +3207,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Conversion->getConversionType().getNonReferenceType(),
From->getLocStart());
ImplicitConversionSequence ICS =
- TryCopyInitialization(&Call, ToType,
+ TryCopyInitialization(*this, &Call, ToType,
/*SuppressUserConversions=*/true,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
+
+ // C++ [over.ics.user]p3:
+ // If the user-defined conversion is specified by a specialization of a
+ // conversion function template, the second standard conversion sequence
+ // shall have exact match rank.
+ if (Conversion->getPrimaryTemplate() &&
+ GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_final_conversion_not_exact;
+ }
+
break;
case ImplicitConversionSequence::BadConversion:
@@ -2948,9 +3354,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// parameter of F.
QualType ParamType = Proto->getArgType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
- = TryCopyInitialization(Args[ArgIdx], ParamType,
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
/*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
@@ -2966,31 +3371,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
-// FIXME: This will eventually be removed, once we've migrated all of the
-// operator overloading logic over to the scheme used by binary operators, which
-// works for template instantiation.
-void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
- SourceLocation OpLoc,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange) {
- UnresolvedSet<16> Fns;
-
- QualType T1 = Args[0]->getType();
- QualType T2;
- if (NumArgs > 1)
- T2 = Args[1]->getType();
-
- DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
- if (S)
- 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);
-}
-
/// \brief Add overload candidates for overloaded operators that are
/// member functions.
///
@@ -3092,9 +3472,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
} else {
Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
ArgIdx == 0 && IsAssignmentOperator,
- /*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
if (Candidate.Conversions[ArgIdx].isBad()) {
@@ -3362,7 +3741,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
const RecordType *TyRec;
if (const MemberPointerType *RHSMPType =
ArgExpr->getType()->getAs<MemberPointerType>())
- TyRec = cast<RecordType>(RHSMPType->getClass());
+ TyRec = RHSMPType->getClass()->getAs<RecordType>();
else
TyRec = ArgExpr->getType()->getAs<RecordType>();
if (!TyRec) {
@@ -4161,7 +4540,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
continue;
AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet,
- false, false, PartialOverloading);
+ false, PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
FoundDecl, ExplicitTemplateArgs,
@@ -4628,6 +5007,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
+ case ovl_fail_final_conversion_not_exact:
return S.NoteOverloadCandidate(Fn);
case ovl_fail_bad_conversion: {
@@ -4823,10 +5203,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(!Cand->Conversions[ConvIdx].isInitialized() &&
"remaining conversion is initialized?");
- // FIXME: these should probably be preserved from the overload
+ // FIXME: this should probably be preserved from the overload
// operation somehow.
bool SuppressUserConversions = false;
- bool ForceRValue = false;
const FunctionProtoType* Proto;
unsigned ArgIdx = ConvIdx;
@@ -4848,10 +5227,10 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(ConvCount <= 3);
for (; ConvIdx != ConvCount; ++ConvIdx)
Cand->Conversions[ConvIdx]
- = S.TryCopyInitialization(Args[ConvIdx],
- Cand->BuiltinTypes.ParamTypes[ConvIdx],
- SuppressUserConversions, ForceRValue,
- /*InOverloadResolution*/ true);
+ = TryCopyInitialization(S, Args[ConvIdx],
+ Cand->BuiltinTypes.ParamTypes[ConvIdx],
+ SuppressUserConversions,
+ /*InOverloadResolution*/ true);
return;
}
@@ -4860,9 +5239,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
if (ArgIdx < NumArgsInProto)
Cand->Conversions[ConvIdx]
- = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx),
- SuppressUserConversions, ForceRValue,
- /*InOverloadResolution=*/true);
+ = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
+ SuppressUserConversions,
+ /*InOverloadResolution=*/true);
else
Cand->Conversions[ConvIdx].setEllipsis();
}
@@ -4966,15 +5345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
IsMember = true;
}
- // We only look at pointers or references to functions.
- FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
- if (!FunctionType->isFunctionType())
- 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). ]
@@ -4987,6 +5357,18 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
ExplicitTemplateArgs = &ETABuffer;
}
+
+ // We expect a pointer or reference to function, or a function pointer.
+ FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
+ if (!FunctionType->isFunctionType()) {
+ if (Complain)
+ Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref)
+ << OvlExpr->getName() << ToType;
+
+ return 0;
+ }
+
+ assert(From->getType() == Context.OverloadTy);
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
@@ -5068,9 +5450,19 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
}
// If there were 0 or 1 matches, we're done.
- if (Matches.empty())
+ if (Matches.empty()) {
+ if (Complain) {
+ Diag(From->getLocStart(), diag::err_addr_ovl_no_viable)
+ << OvlExpr->getName() << FunctionType;
+ for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
+ E = OvlExpr->decls_end();
+ I != E; ++I)
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
+ NoteOverloadCandidate(F);
+ }
+
return 0;
- else if (Matches.size() == 1) {
+ } else if (Matches.size() == 1) {
FunctionDecl *Result = Matches[0].second;
FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result);
@@ -5223,7 +5615,7 @@ static void AddOverloadedCallCandidate(Sema &S,
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) {
assert(!ExplicitTemplateArgs && "Explicit template arguments?");
S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet,
- false, false, PartialOverloading);
+ false, PartialOverloading);
return;
}
@@ -5310,7 +5702,7 @@ static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn,
///
/// Returns true if new candidates were found.
static Sema::OwningExprResult
-BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
+BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -5332,7 +5724,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R))
+ if (SemaRef.DiagnoseEmptyLookup(S, SS, R))
return Destroy(SemaRef, Fn, Args, NumArgs);
assert(!R.empty() && "lookup results empty despite recovery");
@@ -5368,7 +5760,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn,
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
Sema::OwningExprResult
-Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
+Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
@@ -5401,7 +5793,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
// AddRecoveryCallCandidates diagnoses the error itself, so we just
// bailout out if it fails.
if (CandidateSet.empty())
- return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs,
+ return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc);
OverloadCandidateSet::iterator Best;
@@ -6003,7 +6395,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
- NamedDecl *FoundDecl = 0;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
NestedNameSpecifier *Qualifier = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
@@ -6281,7 +6673,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
- CommaLocs, RParenLoc).release();
+ CommaLocs, RParenLoc).result();
}
CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl);
@@ -6385,7 +6777,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
if (CheckFunctionCall(Method, TheCall.get()))
return true;
- return MaybeBindToTemporary(TheCall.release()).release();
+ return MaybeBindToTemporary(TheCall.release()).result();
}
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
@@ -6486,7 +6878,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
/// perhaps a '&' around it). We have resolved the overloaded function
/// to the function declaration Fn, so patch up the expression E to
/// refer (possibly indirectly) to Fn. Returns the new expr.
-Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
+Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(),
@@ -6508,7 +6900,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
return new (Context) ImplicitCastExpr(ICE->getType(),
ICE->getCastKind(),
- SubExpr,
+ SubExpr, CXXBaseSpecifierArray(),
ICE->isLvalueCast());
}
@@ -6619,7 +7011,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
}
Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E,
- NamedDecl *Found,
+ DeclAccessPair Found,
FunctionDecl *Fn) {
return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn));
}
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index cff4774fba27..5e611113083f 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -34,7 +34,7 @@ namespace clang {
OR_Success, ///< Overload resolution succeeded.
OR_No_Viable_Function, ///< No viable function found.
OR_Ambiguous, ///< Ambiguous candidates found.
- OR_Deleted ///< Overload resoltuion refers to a deleted function.
+ OR_Deleted ///< Succeeded, but refers to a deleted function.
};
/// ImplicitConversionKind - The kind of implicit conversion used to
@@ -381,6 +381,33 @@ namespace clang {
assert(isInitialized() && "querying uninitialized conversion");
return Kind(ConversionKind);
}
+
+ /// \brief Return a ranking of the implicit conversion sequence
+ /// kind, where smaller ranks represent better conversion
+ /// sequences.
+ ///
+ /// In particular, this routine gives user-defined conversion
+ /// sequences and ambiguous conversion sequences the same rank,
+ /// per C++ [over.best.ics]p10.
+ unsigned getKindRank() const {
+ switch (getKind()) {
+ case StandardConversion:
+ return 0;
+
+ case UserDefinedConversion:
+ case AmbiguousConversion:
+ return 1;
+
+ case EllipsisConversion:
+ return 2;
+
+ case BadConversion:
+ return 3;
+ }
+
+ return 3;
+ }
+
bool isBad() const { return getKind() == BadConversion; }
bool isStandard() const { return getKind() == StandardConversion; }
bool isEllipsis() const { return getKind() == EllipsisConversion; }
@@ -440,7 +467,11 @@ namespace clang {
/// This conversion candidate is not viable because its result
/// type is not implicitly convertible to the desired type.
- ovl_fail_bad_final_conversion
+ ovl_fail_bad_final_conversion,
+
+ /// This conversion function template specialization candidate is not
+ /// viable because the final conversion was not an exact match.
+ ovl_fail_final_conversion_not_exact
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 791de8c2b9fa..9d6132d050c6 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
@@ -125,7 +126,27 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
return;
}
+ } else if (const CXXFunctionalCastExpr *FC
+ = dyn_cast<CXXFunctionalCastExpr>(E)) {
+ if (isa<CXXConstructExpr>(FC->getSubExpr()) ||
+ isa<CXXTemporaryObjectExpr>(FC->getSubExpr()))
+ return;
+ }
+ // Diagnose "(void*) blah" as a typo for "(void) blah".
+ else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) {
+ TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
+ QualType T = TI->getType();
+
+ // We really do want to use the non-canonical type here.
+ if (T == Context.VoidPtrTy) {
+ PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
+
+ Diag(Loc, diag::warn_unused_voidptr)
+ << FixItHint::CreateRemoval(TL.getStarLoc());
+ return;
+ }
}
+
Diag(Loc, DiagID) << R1 << R2;
}
@@ -572,7 +593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch,
return StmtError();
}
- if (CondTypeBeforePromotion->isBooleanType()) {
+ if (CondExpr->isKnownToHaveBooleanValue()) {
// switch(bool_expr) {...} is often a programmer error, e.g.
// switch(n && mask) { ... } // Doh - should be "n & mask".
// One can always use an if statement instead of switch(bool_expr).
@@ -967,19 +988,22 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
return StmtError(Diag(VD->getLocation(),
diag::err_non_variable_decl_in_for));
} else {
- if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid)
+ Expr *FirstE = cast<Expr>(First);
+ if (!FirstE->isTypeDependent() &&
+ FirstE->isLvalue(Context) != Expr::LV_Valid)
return StmtError(Diag(First->getLocStart(),
diag::err_selector_element_not_lvalue)
<< First->getSourceRange());
FirstType = static_cast<Expr*>(First)->getType();
}
- if (!FirstType->isObjCObjectPointerType() &&
+ if (!FirstType->isDependentType() &&
+ !FirstType->isObjCObjectPointerType() &&
!FirstType->isBlockPointerType())
Diag(ForLoc, diag::err_selector_element_type)
<< FirstType << First->getSourceRange();
}
- if (Second) {
+ if (Second && !Second->isTypeDependent()) {
DefaultFunctionArrayLvalueConversion(Second);
QualType SecondType = Second->getType();
if (!SecondType->isObjCObjectPointerType())
@@ -1422,53 +1446,72 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
if (Context.hasSameType(InTy, OutTy))
continue; // All types can be tied to themselves.
- // Int/ptr operands have some special cases that we allow.
- if ((OutTy->isIntegerType() || OutTy->isPointerType()) &&
- (InTy->isIntegerType() || InTy->isPointerType())) {
-
- // They are ok if they are the same size. Tying void* to int is ok if
- // they are the same size, for example. This also allows tying void* to
- // int*.
- uint64_t OutSize = Context.getTypeSize(OutTy);
- uint64_t InSize = Context.getTypeSize(InTy);
- if (OutSize == InSize)
- continue;
-
- // If the smaller input/output operand is not mentioned in the asm string,
- // then we can promote it and the asm string won't notice. Check this
- // case now.
- bool SmallerValueMentioned = false;
- for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
- AsmStmt::AsmStringPiece &Piece = Pieces[p];
- if (!Piece.isOperand()) continue;
-
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == i+NumOutputs) {
- if (InSize < OutSize) {
- SmallerValueMentioned = true;
- break;
- }
- }
+ // Decide if the input and output are in the same domain (integer/ptr or
+ // floating point.
+ enum AsmDomain {
+ AD_Int, AD_FP, AD_Other
+ } InputDomain, OutputDomain;
+
+ if (InTy->isIntegerType() || InTy->isPointerType())
+ InputDomain = AD_Int;
+ else if (InTy->isFloatingType())
+ InputDomain = AD_FP;
+ else
+ InputDomain = AD_Other;
- // If this is a reference to the input and if the input was the smaller
- // one, then we have to reject this asm.
- if (Piece.getOperandNo() == TiedTo) {
- if (InSize > OutSize) {
- SmallerValueMentioned = true;
- break;
- }
+ if (OutTy->isIntegerType() || OutTy->isPointerType())
+ OutputDomain = AD_Int;
+ else if (OutTy->isFloatingType())
+ OutputDomain = AD_FP;
+ else
+ OutputDomain = AD_Other;
+
+ // They are ok if they are the same size and in the same domain. This
+ // allows tying things like:
+ // void* to int*
+ // void* to int if they are the same size.
+ // double to long double if they are the same size.
+ //
+ uint64_t OutSize = Context.getTypeSize(OutTy);
+ uint64_t InSize = Context.getTypeSize(InTy);
+ if (OutSize == InSize && InputDomain == OutputDomain &&
+ InputDomain != AD_Other)
+ continue;
+
+ // If the smaller input/output operand is not mentioned in the asm string,
+ // then we can promote it and the asm string won't notice. Check this
+ // case now.
+ bool SmallerValueMentioned = false;
+ for (unsigned p = 0, e = Pieces.size(); p != e; ++p) {
+ AsmStmt::AsmStringPiece &Piece = Pieces[p];
+ if (!Piece.isOperand()) continue;
+
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == i+NumOutputs) {
+ if (InSize < OutSize) {
+ SmallerValueMentioned = true;
+ break;
}
}
- // If the smaller value wasn't mentioned in the asm string, and if the
- // output was a register, just extend the shorter one to the size of the
- // larger one.
- if (!SmallerValueMentioned &&
- OutputConstraintInfos[TiedTo].allowsRegister())
- continue;
+ // If this is a reference to the input and if the input was the smaller
+ // one, then we have to reject this asm.
+ if (Piece.getOperandNo() == TiedTo) {
+ if (InSize > OutSize) {
+ SmallerValueMentioned = true;
+ break;
+ }
+ }
}
+ // If the smaller value wasn't mentioned in the asm string, and if the
+ // output was a register, just extend the shorter one to the size of the
+ // larger one.
+ if (!SmallerValueMentioned && InputDomain != AD_Other &&
+ OutputConstraintInfos[TiedTo].allowsRegister())
+ continue;
+
Diag(InputExpr->getLocStart(),
diag::err_asm_tying_incompatible_types)
<< InTy << OutTy << OutputExpr->getSourceRange()
@@ -1483,27 +1526,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
Action::OwningStmtResult
Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen, DeclPtrTy Parm,
- StmtArg Body, StmtArg catchList) {
- Stmt *CatchList = catchList.takeAs<Stmt>();
- ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
-
- // PVD == 0 implies @catch(...).
- if (PVD) {
- // If we already know the decl is invalid, reject it.
- if (PVD->isInvalidDecl())
- return StmtError();
-
- if (!PVD->getType()->isObjCObjectPointerType())
- return StmtError(Diag(PVD->getLocation(),
- diag::err_catch_param_not_objc_type));
- if (PVD->getType()->isObjCQualifiedIdType())
- return StmtError(Diag(PVD->getLocation(),
- diag::err_illegal_qualifiers_on_catch_parm));
- }
-
- ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
- PVD, Body.takeAs<Stmt>(), CatchList);
- return Owned(CatchList ? CatchList : CS);
+ StmtArg Body) {
+ VarDecl *Var = cast_or_null<VarDecl>(Parm.getAs<Decl>());
+ if (Var && Var->isInvalidDecl())
+ return StmtError();
+
+ return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var,
+ Body.takeAs<Stmt>()));
}
Action::OwningStmtResult
@@ -1513,18 +1542,38 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
}
Action::OwningStmtResult
-Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
- StmtArg Try, StmtArg Catch, StmtArg Finally) {
+Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try,
+ MultiStmtArg CatchStmts, StmtArg Finally) {
FunctionNeedsScopeChecking() = true;
- return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
- Catch.takeAs<Stmt>(),
- Finally.takeAs<Stmt>()));
+ unsigned NumCatchStmts = CatchStmts.size();
+ return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(),
+ (Stmt **)CatchStmts.release(),
+ NumCatchStmts,
+ Finally.takeAs<Stmt>()));
+}
+
+Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg ThrowE) {
+ Expr *Throw = static_cast<Expr *>(ThrowE.get());
+ if (Throw) {
+ QualType ThrowType = Throw->getType();
+ // Make sure the expression type is an ObjC pointer or "void *".
+ if (!ThrowType->isDependentType() &&
+ !ThrowType->isObjCObjectPointerType()) {
+ const PointerType *PT = ThrowType->getAs<PointerType>();
+ if (!PT || !PT->getPointeeType()->isVoidType())
+ return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
+ << Throw->getType() << Throw->getSourceRange());
+ }
+ }
+
+ return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>()));
}
Action::OwningStmtResult
-Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
- Expr *ThrowExpr = expr.takeAs<Expr>();
- if (!ThrowExpr) {
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw,
+ Scope *CurScope) {
+ if (!Throw.get()) {
// @throw without an expression designates a rethrow (which much occur
// in the context of an @catch clause).
Scope *AtCatchParent = CurScope;
@@ -1532,17 +1581,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
AtCatchParent = AtCatchParent->getParent();
if (!AtCatchParent)
return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
- } else {
- QualType ThrowType = ThrowExpr->getType();
- // Make sure the expression type is an ObjC pointer or "void *".
- if (!ThrowType->isObjCObjectPointerType()) {
- const PointerType *PT = ThrowType->getAs<PointerType>();
- if (!PT || !PT->getPointeeType()->isVoidType())
- return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
- << ThrowExpr->getType() << ThrowExpr->getSourceRange());
- }
- }
- return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr));
+ }
+
+ return BuildObjCAtThrowStmt(AtLoc, move(Throw));
}
Action::OwningStmtResult
@@ -1552,7 +1593,8 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
- if (!SyncExpr->getType()->isObjCObjectPointerType()) {
+ if (!SyncExpr->getType()->isDependentType() &&
+ !SyncExpr->getType()->isObjCObjectPointerType()) {
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 40ec4bcb58e4..694b21c8393f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -63,20 +63,40 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) {
}
static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) {
+ // The set of class templates we've already seen.
+ llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
LookupResult::Filter filter = R.makeFilter();
while (filter.hasNext()) {
NamedDecl *Orig = filter.next();
NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl());
if (!Repl)
filter.erase();
- else if (Repl != Orig)
+ else if (Repl != Orig) {
+
+ // C++ [temp.local]p3:
+ // A lookup that finds an injected-class-name (10.2) can result in an
+ // ambiguity in certain cases (for example, if it is found in more than
+ // one base class). If all of the injected-class-names that are found
+ // refer to specializations of the same class template, and if the name
+ // is followed by a template-argument-list, the reference refers to the
+ // class template itself and not a specialization thereof, and is not
+ // ambiguous.
+ //
+ // FIXME: Will we eventually have to do the same for alias templates?
+ if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
+ if (!ClassTemplates.insert(ClassTmpl)) {
+ filter.erase();
+ continue;
+ }
+
filter.replace(Repl);
+ }
}
filter.done();
}
TemplateNameKind Sema::isTemplateName(Scope *S,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectTypePtr,
bool EnteringContext,
@@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupOrdinaryName);
R.suppressDiagnostics();
LookupTemplateName(R, S, SS, ObjectType, EnteringContext);
- if (R.empty())
+ if (R.empty() || R.isAmbiguous())
return TNK_Non_template;
TemplateName Template;
@@ -169,7 +189,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
}
void Sema::LookupTemplateName(LookupResult &Found,
- Scope *S, const CXXScopeSpec &SS,
+ Scope *S, CXXScopeSpec &SS,
QualType ObjectType,
bool EnteringContext) {
// Determine where to perform name lookup
@@ -190,7 +210,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
isDependent = isDependentScopeSpecifier(SS);
// The declaration context must be complete.
- if (LookupCtx && RequireCompleteDeclContext(SS))
+ if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
return;
}
@@ -227,14 +247,11 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupName(Found, S);
}
- // FIXME: Cope with ambiguous name-lookup results.
- assert(!Found.isAmbiguous() &&
- "Cannot handle template name-lookup ambiguities");
-
if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
- if (CorrectTypo(Found, S, &SS, LookupCtx)) {
+ if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
+ false, CTC_CXXCasts)) {
FilterAcceptableTemplateNames(Context, Found);
if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) {
if (LookupCtx)
@@ -271,8 +288,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
LookupOrdinaryName);
LookupName(FoundOuter, S);
FilterAcceptableTemplateNames(Context, FoundOuter);
- // FIXME: Handle ambiguities in this lookup better
-
+
if (FoundOuter.empty()) {
// - if the name is not found, the name found in the class of the
// object expression is used, otherwise
@@ -439,7 +455,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
bool Invalid = false;
if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc,
+ LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc,
PrevDecl);
@@ -560,7 +578,9 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
IdentifierInfo *ParamName = D.getIdentifier();
if (ParamName) {
- NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName);
+ NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(),
+ LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter())
Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
PrevDecl);
@@ -705,7 +725,7 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
Sema::DeclResult
Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, const CXXScopeSpec &SS,
+ SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
@@ -733,25 +753,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
ForRedeclaration);
if (SS.isNotEmpty() && !SS.isInvalid()) {
- if (RequireCompleteDeclContext(SS))
- return true;
-
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
// FIXME: Produce a reasonable diagnostic here
return true;
}
+ if (RequireCompleteDeclContext(SS, SemanticContext))
+ return true;
+
LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
LookupName(Previous, S);
}
- assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
+ if (Previous.isAmbiguous())
+ return true;
+
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
- PrevDecl = *Previous.begin();
+ PrevDecl = (*Previous.begin())->getUnderlyingDecl();
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
@@ -779,22 +801,24 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// declared as a friend, and when the name of the friend class or
// function is neither a qualified name nor a template-id, scopes outside
// the innermost enclosing namespace scope are not considered.
- DeclContext *OutermostContext = CurContext;
- while (!OutermostContext->isFileContext())
- OutermostContext = OutermostContext->getLookupParent();
-
- if (PrevDecl &&
- (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
- OutermostContext->Encloses(PrevDecl->getDeclContext()))) {
- SemanticContext = PrevDecl->getDeclContext();
- } else {
- // Declarations in outer scopes don't matter. However, the outermost
- // context we computed is the semantic context for our new
- // declaration.
- PrevDecl = PrevClassTemplate = 0;
- SemanticContext = OutermostContext;
+ if (!SS.isSet()) {
+ DeclContext *OutermostContext = CurContext;
+ while (!OutermostContext->isFileContext())
+ OutermostContext = OutermostContext->getLookupParent();
+
+ if (PrevDecl &&
+ (OutermostContext->Equals(PrevDecl->getDeclContext()) ||
+ OutermostContext->Encloses(PrevDecl->getDeclContext()))) {
+ SemanticContext = PrevDecl->getDeclContext();
+ } else {
+ // Declarations in outer scopes don't matter. However, the outermost
+ // context we computed is the semantic context for our new
+ // declaration.
+ PrevDecl = PrevClassTemplate = 0;
+ SemanticContext = OutermostContext;
+ }
}
-
+
if (CurContext->isDependentContext()) {
// If this is a dependent context, we don't want to link the friend
// class template to the template in scope, because that would perform
@@ -804,7 +828,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
} else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = PrevClassTemplate = 0;
-
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible.
if (!TemplateParameterListsAreEqual(TemplateParams,
@@ -861,9 +885,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
TPC_ClassTemplate))
Invalid = true;
- // FIXME: If we had a scope specifier, we better have a previous template
- // declaration!
-
+ if (SS.isSet()) {
+ // If the name of the template was qualified, we must be defining the
+ // template out-of-line.
+ if (!SS.isInvalid() && !Invalid && !PrevClassTemplate &&
+ !(TUK == TUK_Friend && CurContext->isDependentContext()))
+ Diag(NameLoc, diag::err_member_def_does_not_match)
+ << Name << SemanticContext << SS.getRange();
+ }
+
CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
PrevClassTemplate?
@@ -1206,6 +1236,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
///
/// \param NumParamLists the number of template parameter lists in ParamLists.
///
+/// \param IsFriend Whether to apply the slightly different rules for
+/// matching template parameters to scope specifiers in friend
+/// declarations.
+///
/// \param IsExplicitSpecialization will be set true if the entity being
/// declared is an explicit specialization, false otherwise.
///
@@ -1220,6 +1254,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
+ bool IsFriend,
bool &IsExplicitSpecialization) {
IsExplicitSpecialization = false;
@@ -1285,6 +1320,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
if (Idx >= NumParamLists) {
// We have a template-id without a corresponding template parameter
// list.
+
+ // ...which is fine if this is a friend declaration.
+ if (IsFriend) {
+ IsExplicitSpecialization = true;
+ break;
+ }
+
if (DependentTemplateId) {
// FIXME: the location information here isn't great.
Diag(SS.getRange().getBegin(),
@@ -1302,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// Check the template parameter list against its corresponding template-id.
if (DependentTemplateId) {
- TemplateDecl *Template
- = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
-
- if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Template)) {
- TemplateParameterList *ExpectedTemplateParams = 0;
- // Is this template-id naming the primary template?
- if (Context.hasSameType(TemplateId,
- ClassTemplate->getInjectedClassNameSpecialization(Context)))
- ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
- // ... or a partial specialization?
- else if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = ClassTemplate->findPartialSpecialization(TemplateId))
- ExpectedTemplateParams = PartialSpec->getTemplateParameters();
-
- if (ExpectedTemplateParams)
- TemplateParameterListsAreEqual(ParamLists[Idx],
- ExpectedTemplateParams,
- true, TPL_TemplateMatch);
+ TemplateParameterList *ExpectedTemplateParams = 0;
+
+ // Are there cases in (e.g.) friends where this won't match?
+ if (const InjectedClassNameType *Injected
+ = TemplateId->getAs<InjectedClassNameType>()) {
+ CXXRecordDecl *Record = Injected->getDecl();
+ if (ClassTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
+ ExpectedTemplateParams = Partial->getTemplateParameters();
+ else
+ ExpectedTemplateParams = Record->getDescribedClassTemplate()
+ ->getTemplateParameters();
}
+ if (ExpectedTemplateParams)
+ TemplateParameterListsAreEqual(ParamLists[Idx],
+ ExpectedTemplateParams,
+ true, TPL_TemplateMatch);
+
CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
} else if (ParamLists[Idx]->size() > 0)
Diag(ParamLists[Idx]->getTemplateLoc(),
@@ -1388,6 +1428,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
"Converted template argument list is too short!");
QualType CanonType;
+ bool IsCurrentInstantiation = false;
if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
@@ -1409,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// In the future, we need to teach getTemplateSpecializationType to only
// build the canonical type and return that to us.
CanonType = Context.getCanonicalType(CanonType);
+
+ // This might work out to be a current instantiation, in which
+ // case the canonical type needs to be the InjectedClassNameType.
+ //
+ // TODO: in theory this could be a simple hashtable lookup; most
+ // changes to CurContext don't change the set of current
+ // instantiations.
+ if (isa<ClassTemplateDecl>(Template)) {
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
+ // If we get out to a namespace, we're done.
+ if (Ctx->isFileContext()) break;
+
+ // If this isn't a record, keep looking.
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
+ if (!Record) continue;
+
+ // Look for one of the two cases with InjectedClassNameTypes
+ // and check whether it's the same template.
+ if (!isa<ClassTemplatePartialSpecializationDecl>(Record) &&
+ !Record->getDescribedClassTemplate())
+ continue;
+
+ // Fetch the injected class name type and check whether its
+ // injected type is equal to the type we just built.
+ QualType ICNT = Context.getTypeDeclType(Record);
+ QualType Injected = cast<InjectedClassNameType>(ICNT)
+ ->getInjectedSpecializationType();
+
+ if (CanonType != Injected->getCanonicalTypeInternal())
+ continue;
+
+ // If so, the canonical type of this TST is the injected
+ // class name type of the record we just found.
+ assert(ICNT.isCanonical());
+ CanonType = ICNT;
+ IsCurrentInstantiation = true;
+ break;
+ }
+ }
} else if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
@@ -1442,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType,
+ IsCurrentInstantiation);
}
Action::TypeResult
@@ -1545,14 +1626,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// We actually only call this from template instantiation.
Sema::OwningExprResult
-Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
+Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
DeclarationName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &TemplateArgs) {
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
DC->isDependentContext() ||
- RequireCompleteDeclContext(SS))
+ RequireCompleteDeclContext(SS, DC))
return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs);
LookupResult R(*this, Name, NameLoc, LookupOrdinaryName);
@@ -1586,7 +1667,7 @@ Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS,
/// of the "template" keyword, and "apply" is the \p Name.
Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext) {
@@ -1663,11 +1744,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
const TemplateArgument &Arg = AL.getArgument();
// Check template type parameter.
- if (Arg.getKind() != TemplateArgument::Type) {
+ switch(Arg.getKind()) {
+ case TemplateArgument::Type:
// C++ [temp.arg.type]p1:
// A template-argument for a template-parameter which is a
// type shall be a type-id.
+ break;
+ case TemplateArgument::Template: {
+ // We have a template type parameter but the template argument
+ // is a template without any arguments.
+ SourceRange SR = AL.getSourceRange();
+ TemplateName Name = Arg.getAsTemplate();
+ Diag(SR.getBegin(), diag::err_template_missing_args)
+ << Name << SR;
+ if (TemplateDecl *Decl = Name.getAsTemplateDecl())
+ Diag(Decl->getLocation(), diag::note_template_decl_here);
+ return true;
+ }
+ default: {
// We have a template type parameter but the template argument
// is not a type.
SourceRange SR = AL.getSourceRange();
@@ -1676,6 +1771,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
return true;
}
+ }
if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
return true;
@@ -2317,14 +2413,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
- if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) {
- S.Diag(Arg->getLocStart(),
- diag::err_template_arg_unresolved_overloaded_function)
- << ParamType << Arg->getSourceRange();
- } else {
- S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
- << Arg->getSourceRange();
- }
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
@@ -2525,6 +2615,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(Entity->getCanonicalDecl());
+ S.MarkDeclarationReferenced(Arg->getLocStart(), Entity);
return false;
}
@@ -2797,16 +2888,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
- true,
- FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ if (Arg->getType() == Context.OverloadTy) {
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
- ArgType = Arg->getType();
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
+ } else
+ return true;
}
-
+
if (!ParamType->isMemberPointerType())
return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
ParamType,
@@ -2851,17 +2945,20 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
- ParamRefType->getPointeeType(),
- true,
- FoundResult)) {
- if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
- return true;
+ if (Arg->getType() == Context.OverloadTy) {
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
+ ParamRefType->getPointeeType(),
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
- ArgType = Arg->getType();
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
+ } else
+ return true;
}
-
+
return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
ParamType,
Arg, Converted);
@@ -2964,9 +3061,21 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
return ExprError();
RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+
+ // We might need to perform a trailing qualification conversion, since
+ // the element type on the parameter could be more qualified than the
+ // element type in the expression we constructed.
+ if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
+ ParamType.getUnqualifiedType())) {
+ Expr *RefE = RefExpr.takeAs<Expr>();
+ ImpCastExprToType(RefE, ParamType.getUnqualifiedType(),
+ CastExpr::CK_NoOp);
+ RefExpr = Owned(RefE);
+ }
+
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- ParamType));
+ ParamType.getUnqualifiedType()));
return move(RefExpr);
}
}
@@ -3467,7 +3576,7 @@ Sema::DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
@@ -3500,6 +3609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
+ TUK == TUK_Friend,
isExplicitSpecialization);
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
@@ -3683,6 +3793,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+ unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
+ : ClassTemplate->getPartialSpecializations().size();
ClassTemplatePartialSpecializationDecl *Partial
= ClassTemplatePartialSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
@@ -3692,7 +3804,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Converted,
TemplateArgs,
CanonType,
- PrevPartial);
+ PrevPartial,
+ SequenceNumber);
SetNestedNameSpecifier(Partial, SS);
if (PrevPartial) {
@@ -4032,7 +4145,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// instantiation has no effect.
//
// In C++98/03 mode, we only give an extension warning here, because it
- // is not not harmful to try to explicitly instantiate something that
+ // is not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
if (!getLangOptions().CPlusPlus0x) {
Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
@@ -4068,6 +4181,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
}
+/// \brief Perform semantic analysis for the given dependent function
+/// template specialization. The only possible way to get a dependent
+/// function template specialization is with a friend declaration,
+/// like so:
+///
+/// template <class T> void foo(T);
+/// template <class T> class A {
+/// friend void foo<>(T);
+/// };
+///
+/// There really isn't any useful analysis we can do here, so we
+/// just store the information.
+bool
+Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ LookupResult &Previous) {
+ // Remove anything from Previous that isn't a function template in
+ // the correct context.
+ DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next()->getUnderlyingDecl();
+ if (!isa<FunctionTemplateDecl>(D) ||
+ !FDLookupContext->Equals(D->getDeclContext()->getLookupContext()))
+ F.erase();
+ }
+ F.done();
+
+ // Should this be diagnosed here?
+ if (Previous.empty()) return true;
+
+ FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
+ ExplicitTemplateArgs);
+ return false;
+}
+
/// \brief Perform semantic analysis for the given function template
/// specialization.
///
@@ -4153,6 +4302,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ Specialization->setLocation(FD->getLocation());
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
@@ -4227,7 +4377,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
bool
Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
-
+
// Try to find the member we are instantiating.
NamedDecl *Instantiation = 0;
NamedDecl *InstantiatedFrom = 0;
@@ -4273,6 +4423,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// this mismatch later.
return false;
}
+
+ // If this is a friend, just bail out here before we start turning
+ // things into explicit specializations.
+ if (Member->getFriendObjectKind() != Decl::FOK_None) {
+ // Preserve instantiation information.
+ if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
+ cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
+ } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
+ }
+
+ Previous.clear();
+ Previous.addDecl(Instantiation);
+ return false;
+ }
// Make sure that this is a specialization of a member.
if (!InstantiatedFrom) {
@@ -4612,7 +4781,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
SourceLocation TemplateLoc,
unsigned TagSpec,
SourceLocation KWLoc,
- const CXXScopeSpec &SS,
+ CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
AttributeList *Attr) {
@@ -5001,9 +5170,30 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
assert(Keyword != ETK_None && "Invalid tag kind!");
+ if (TUK == TUK_Declaration || TUK == TUK_Definition) {
+ Diag(NameLoc, diag::err_dependent_tag_decl)
+ << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
+ << SS.getRange();
+ return true;
+ }
+
return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
}
+static void FillTypeLoc(DependentNameTypeLoc TL,
+ SourceLocation TypenameLoc,
+ SourceRange QualifierRange) {
+ // FIXME: typename, qualifier range
+ TL.setNameLoc(TypenameLoc);
+}
+
+static void FillTypeLoc(QualifiedNameTypeLoc TL,
+ SourceLocation TypenameLoc,
+ SourceRange QualifierRange) {
+ // FIXME: typename, qualifier range
+ TL.setNameLoc(TypenameLoc);
+}
+
Sema::TypeResult
Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
const IdentifierInfo &II, SourceLocation IdLoc) {
@@ -5012,10 +5202,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (!NNS)
return true;
- QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc));
+ QualType T = CheckTypenameType(ETK_Typename, NNS, II,
+ SourceRange(TypenameLoc, IdLoc));
if (T.isNull())
return true;
- return T.getAsOpaquePtr();
+
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ if (isa<DependentNameType>(T)) {
+ DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ } else {
+ QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ }
+
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
Sema::TypeResult
@@ -5034,48 +5237,49 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
// track of the nested-name-specifier.
// FIXME: Note that the QualifiedNameType had the "typename" keyword!
- return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+
+ T = Context.getQualifiedNameType(NNS, T);
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
- return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
- .getAsOpaquePtr();
+ T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId);
+ TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
+ DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ // FIXME: fill inner type loc
+ FillTypeLoc(TL, TypenameLoc, SS.getRange());
+ return CreateLocInfoType(T, TSI).getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
-Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
+Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, const IdentifierInfo &II,
SourceRange Range) {
- CXXRecordDecl *CurrentInstantiation = 0;
- if (NNS->isDependent()) {
- CurrentInstantiation = getCurrentInstantiationOf(NNS);
-
- // If the nested-name-specifier does not refer to the current
- // instantiation, then build a typename type.
- if (!CurrentInstantiation)
- return Context.getDependentNameType(ETK_Typename, NNS, &II);
-
- // The nested-name-specifier refers to the current instantiation, so the
- // "typename" keyword itself is superfluous. In C++03, the program is
- // actually ill-formed. However, DR 382 (in C++0x CD1) allows such
- // extraneous "typename" keywords, and we retroactively apply this DR to
- // C++03 code.
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+ SS.setRange(Range);
+
+ DeclContext *Ctx = computeDeclContext(SS);
+ if (!Ctx) {
+ // If the nested-name-specifier is dependent and couldn't be
+ // resolved to a type, build a typename type.
+ assert(NNS->isDependent());
+ return Context.getDependentNameType(Keyword, NNS, &II);
}
- DeclContext *Ctx = 0;
+ // If the nested-name-specifier refers to the current instantiation,
+ // the "typename" keyword itself is superfluous. In C++03, the
+ // program is actually ill-formed. However, DR 382 (in C++0x CD1)
+ // allows such extraneous "typename" keywords, and we retroactively
+ // apply this DR to C++03 code. In any case we continue.
- if (CurrentInstantiation)
- Ctx = CurrentInstantiation;
- else {
- CXXScopeSpec SS;
- SS.setScopeRep(NNS);
- SS.setRange(Range);
- if (RequireCompleteDeclContext(SS))
- return QualType();
-
- Ctx = computeDeclContext(SS);
- }
- assert(Ctx && "No declaration context?");
+ if (RequireCompleteDeclContext(SS, Ctx))
+ return QualType();
DeclarationName Name(&II);
LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName);
@@ -5089,7 +5293,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getDependentNameType(ETK_Typename, NNS, &II);
+ return Context.getDependentNameType(Keyword, NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -5133,6 +5337,8 @@ namespace {
DeclarationName Entity;
public:
+ typedef TreeTransform<CurrentInstantiationRebuilder> inherited;
+
CurrentInstantiationRebuilder(Sema &SemaRef,
SourceLocation Loc,
DeclarationName Entity)
@@ -5168,7 +5374,7 @@ namespace {
/// FIXME: This is completely unsafe; we will need to actually clone the
/// expressions.
Sema::OwningExprResult TransformExpr(Expr *E) {
- return getSema().Owned(E);
+ return getSema().Owned(E->Retain());
}
/// \brief Transforms a typename type by determining whether the type now
@@ -5256,15 +5462,30 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
/// in X<T> and returning a QualifiedNameType whose canonical type is the same
/// as the canonical type of T*, allowing the return types of the out-of-line
/// definition and the declaration to match.
-QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
- DeclarationName Name) {
- if (T.isNull() || !T->isDependentType())
+TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
+ SourceLocation Loc,
+ DeclarationName Name) {
+ if (!T || !T->getType()->isDependentType())
return T;
CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
return Rebuilder.TransformType(T);
}
+bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
+ if (SS.isInvalid()) return true;
+
+ NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(),
+ DeclarationName());
+ NestedNameSpecifier *Rebuilt =
+ Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange());
+ if (!Rebuilt) return true;
+
+ SS.setScopeRep(Rebuilt);
+ return false;
+}
+
/// \brief Produces a formatted string that describes the binding of
/// template parameters to template arguments.
std::string
@@ -5344,8 +5565,15 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
}
case TemplateArgument::Expression: {
- assert(false && "No expressions in deduced template arguments!");
- Result += "<expression>";
+ // FIXME: This is non-optimal, since we're regurgitating the
+ // expression we were given.
+ std::string Str;
+ {
+ llvm::raw_string_ostream OS(Str);
+ Args[I].getAsExpr()->printPretty(OS, Context, 0,
+ Context.PrintingPolicy);
+ }
+ Result += Str;
break;
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index d61a767dc5fe..2bb97eba11cb 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -638,7 +638,8 @@ DeduceTemplateArguments(Sema &S,
case Type::InjectedClassName: {
// Treat a template's injected-class-name as if the template
// specialization type had been used.
- Param = cast<InjectedClassNameType>(Param)->getUnderlyingType();
+ Param = cast<InjectedClassNameType>(Param)
+ ->getInjectedSpecializationType();
assert(isa<TemplateSpecializationType>(Param) &&
"injected class name is not a template specialization type");
// fall through
@@ -960,32 +961,18 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
-/// \brief Perform template argument deduction to determine whether
-/// the given template arguments match the given class template
-/// partial specialization per C++ [temp.class.spec.match].
-Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs,
- TemplateDeductionInfo &Info) {
- // C++ [temp.class.spec.match]p2:
- // A partial specialization matches a given actual template
- // argument list if the template arguments of the partial
- // specialization can be deduced from the actual template argument
- // list (14.8.2).
- SFINAETrap Trap(*this);
- llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
- Deduced.resize(Partial->getTemplateParameters()->size());
- if (TemplateDeductionResult Result
- = ::DeduceTemplateArguments(*this,
- Partial->getTemplateParameters(),
- Partial->getTemplateArgs(),
- TemplateArgs, Info, Deduced))
- return Result;
-
- InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- Deduced.data(), Deduced.size());
- if (Inst)
- return TDK_InstantiationDepth;
+/// Complete template argument deduction for a class template partial
+/// specialization.
+static Sema::TemplateDeductionResult
+FinishTemplateArgumentDeduction(Sema &S,
+ ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ Sema::TemplateDeductionInfo &Info) {
+ // Trap errors.
+ Sema::SFINAETrap Trap(S);
+
+ Sema::ContextRAII SavedContext(S, Partial);
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
@@ -995,18 +982,19 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
- = const_cast<NamedDecl *>(
+ = const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
Info.Param = makeTemplateParameter(Param);
- return TDK_Incomplete;
+ return Sema::TDK_Incomplete;
}
-
+
Builder.Append(Deduced[I]);
}
-
+
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
- = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ = new (S.Context) TemplateArgumentList(S.Context, Builder,
+ /*TakeArgs=*/true);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the template
@@ -1016,7 +1004,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// to the class template.
// FIXME: Do we have to correct the types of deduced non-type template
// arguments (in particular, integral non-type template arguments?).
- Sema::LocalInstantiationScope InstScope(*this);
+ Sema::LocalInstantiationScope InstScope(S);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
@@ -1029,11 +1017,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
TemplateArgumentLoc InstArg;
- if (Subst(PartialTemplateArgs[I], InstArg,
- MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
+ if (S.Subst(PartialTemplateArgs[I], InstArg,
+ MultiLevelTemplateArgumentList(*DeducedArgumentList))) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = PartialTemplateArgs[I].getArgument();
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
InstArgs.addArgument(InstArg);
}
@@ -1041,10 +1029,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
TemplateArgumentListBuilder ConvertedInstArgs(
ClassTemplate->getTemplateParameters(), N);
- if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
+ if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
InstArgs, false, ConvertedInstArgs)) {
// FIXME: fail with more useful information?
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) {
@@ -1060,26 +1048,60 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Expr *InstExpr = InstArg.getAsExpr();
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
+ if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Partial->getTemplateArgs()[I];
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
}
}
}
- if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
- return TDK_NonDeducedMismatch;
+ return Sema::TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
- return TDK_SubstitutionFailure;
+ return Sema::TDK_SubstitutionFailure;
- return TDK_Success;
+ return Sema::TDK_Success;
+}
+
+/// \brief Perform template argument deduction to determine whether
+/// the given template arguments match the given class template
+/// partial specialization per C++ [temp.class.spec.match].
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
+ // C++ [temp.class.spec.match]p2:
+ // A partial specialization matches a given actual template
+ // argument list if the template arguments of the partial
+ // specialization can be deduced from the actual template argument
+ // list (14.8.2).
+ SFINAETrap Trap(*this);
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(*this,
+ Partial->getTemplateParameters(),
+ Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
+
+ InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
+ Deduced.data(), Deduced.size());
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs,
+ Deduced, Info);
}
/// \brief Determine whether the given type T is a simple-template-id type.
@@ -1162,6 +1184,8 @@ Sema::SubstituteExplicitTemplateArguments(
if (Inst)
return TDK_InstantiationDepth;
+ ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
+
if (CheckTemplateArgumentList(FunctionTemplate,
SourceLocation(),
ExplicitTemplateArgs,
@@ -1310,6 +1334,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (Inst)
return TDK_InstantiationDepth;
+ ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
+
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
@@ -1416,9 +1442,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
+ DeclContext *Owner = FunctionTemplate->getDeclContext();
+ if (FunctionTemplate->getFriendObjectKind())
+ Owner = FunctionTemplate->getLexicalDeclContext();
Specialization = cast_or_null<FunctionDecl>(
- SubstDecl(FunctionTemplate->getTemplatedDecl(),
- FunctionTemplate->getDeclContext(),
+ SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
MultiLevelTemplateArgumentList(*DeducedArgumentList)));
if (!Specialization)
return TDK_SubstitutionFailure;
@@ -2332,35 +2360,49 @@ Sema::getMoreSpecializedPartialSpecialization(
// whose type is a class template specialization with the template
// arguments of the second partial specialization.
//
- // Rather than synthesize function templates, we merely perform the
- // equivalent partial ordering by performing deduction directly on the
- // template arguments of the class template partial specializations. This
- // computation is slightly simpler than the general problem of function
- // template partial ordering, because class template partial specializations
- // are more constrained. We know that every template parameter is deduc
+ // Rather than synthesize function templates, we merely perform the
+ // equivalent partial ordering by performing deduction directly on
+ // the template arguments of the class template partial
+ // specializations. This computation is slightly simpler than the
+ // general problem of function template partial ordering, because
+ // class template partial specializations are more constrained. We
+ // know that every template parameter is deducible from the class
+ // template partial specialization's template arguments, for
+ // example.
llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Sema::TemplateDeductionInfo Info(Context, Loc);
+
+ QualType PT1 = PS1->getInjectedSpecializationType();
+ QualType PT2 = PS2->getInjectedSpecializationType();
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS2->getTemplateParameters(),
- Context.getTypeDeclType(PS2),
- Context.getTypeDeclType(PS1),
+ PT2,
+ PT1,
Info,
Deduced,
0);
-
+ if (Better1)
+ Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
+ PS1->getTemplateArgs(),
+ Deduced, Info);
+
// Determine whether PS2 is at least as specialized as PS1
Deduced.clear();
Deduced.resize(PS1->getTemplateParameters()->size());
bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
PS1->getTemplateParameters(),
- Context.getTypeDeclType(PS1),
- Context.getTypeDeclType(PS2),
+ PT1,
+ PT2,
Info,
Deduced,
0);
+ if (Better2)
+ Better2 = !::FinishTemplateArgumentDeduction(*this, PS1,
+ PS2->getTemplateArgs(),
+ Deduced, Info);
if (Better1 == Better2)
return 0;
@@ -2537,6 +2579,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
break;
}
+ case Type::InjectedClassName:
+ T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
+ // fall through
+
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index d21862b71e89..14bd24320104 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -38,10 +38,16 @@ using namespace clang;
/// arguments relative to the primary template, even when we're
/// dealing with a specialization. This is only relevant for function
/// template specializations.
+///
+/// \param Pattern If non-NULL, indicates the pattern from which we will be
+/// instantiating the definition of the given declaration, \p D. This is
+/// used to determine the proper set of template instantiation arguments for
+/// friend function template specializations.
MultiLevelTemplateArgumentList
Sema::getTemplateInstantiationArgs(NamedDecl *D,
const TemplateArgumentList *Innermost,
- bool RelativeToPrimary) {
+ bool RelativeToPrimary,
+ const FunctionDecl *Pattern) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -89,9 +95,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// If this is a friend declaration and it declares an entity at
// namespace scope, take arguments from its lexical parent
- // instead of its semantic parent.
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
if (Function->getFriendObjectKind() &&
- Function->getDeclContext()->isFileContext()) {
+ Function->getDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
Ctx = Function->getLexicalDeclContext();
RelativeToPrimary = false;
continue;
@@ -339,12 +347,32 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
/// \brief Prints the current instantiation stack through a series of
/// notes.
void Sema::PrintInstantiationStack() {
+ // Determine which template instantiations to skip, if any.
+ unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart;
+ unsigned Limit = Diags.getTemplateBacktraceLimit();
+ if (Limit && Limit < ActiveTemplateInstantiations.size()) {
+ SkipStart = Limit / 2 + Limit % 2;
+ SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2;
+ }
+
// FIXME: In all of these cases, we need to show the template arguments
+ unsigned InstantiationIdx = 0;
for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
- ++Active) {
+ ++Active, ++InstantiationIdx) {
+ // Skip this instantiation?
+ if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) {
+ if (InstantiationIdx == SkipStart) {
+ // Note that we're skipping instantiations.
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_instantiation_contexts_suppressed)
+ << unsigned(ActiveTemplateInstantiations.size() - Limit);
+ }
+ continue;
+ }
+
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
Decl *D = reinterpret_cast<Decl *>(Active->Entity);
@@ -512,8 +540,7 @@ bool Sema::isSFINAEContext() const {
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
namespace {
- class TemplateInstantiator
- : public TreeTransform<TemplateInstantiator> {
+ class TemplateInstantiator : public TreeTransform<TemplateInstantiator> {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
@@ -569,6 +596,11 @@ namespace {
IdentifierInfo *Name,
SourceLocation Loc, SourceRange TypeRange);
+ /// \brief Rebuild the Objective-C exception declaration and register the
+ /// declaration as an instantiated local.
+ VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TSInfo, QualType T);
+
/// \brief Check for tag mismatches when instantiating an
/// elaborated type.
QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
@@ -579,13 +611,9 @@ namespace {
Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
- /// \brief Transforms a function proto type by performing
- /// substitution in the function parameters, possibly adjusting
- /// their types and marking default arguments as uninstantiated.
- bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
- llvm::SmallVectorImpl<QualType> &PTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
-
+ QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm);
/// \brief Transforms a template type parameter type by performing
@@ -667,7 +695,16 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
SourceRange TypeRange) {
VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator,
Name, Loc, TypeRange);
- if (Var && !Var->isInvalidDecl())
+ if (Var)
+ getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
+ return Var;
+}
+
+VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TSInfo,
+ QualType T) {
+ VarDecl *Var = inherited::RebuildObjCExceptionDecl(ExceptionDecl, TSInfo, T);
+ if (Var)
getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var);
return Var;
}
@@ -791,63 +828,17 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
E->getParam());
}
-
-bool
-TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
- llvm::SmallVectorImpl<QualType> &PTypes,
- llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
- // Create a local instantiation scope for the parameters.
- // FIXME: When we implement the C++0x late-specified return type,
- // we will need to move this scope out to the function type itself.
- bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0);
- Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope,
- IsTemporaryScope);
-
- if (TreeTransform<TemplateInstantiator>::
- TransformFunctionTypeParams(TL, PTypes, PVars))
- return true;
-
- // Check instantiated parameters.
- if (SemaRef.CheckInstantiatedParams(PVars))
- return true;
-
- return false;
+QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
+ FunctionProtoTypeLoc TL,
+ QualType ObjectType) {
+ // We need a local instantiation scope for this function prototype.
+ Sema::LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ return inherited::TransformFunctionProtoType(TLB, TL, ObjectType);
}
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
- TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
- TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
- if (!NewDI)
- return 0;
-
- // TODO: do we have to clone this decl if the types match and
- // there's no default argument?
-
- ParmVarDecl *NewParm
- = ParmVarDecl::Create(SemaRef.Context,
- OldParm->getDeclContext(),
- OldParm->getLocation(),
- OldParm->getIdentifier(),
- NewDI->getType(),
- NewDI,
- OldParm->getStorageClass(),
- /* DefArg */ NULL);
-
- // Maybe adjust new parameter type.
- NewParm->setType(SemaRef.adjustParameterType(NewParm->getType()));
-
- // Mark the (new) default argument as uninstantiated (if any).
- if (OldParm->hasUninstantiatedDefaultArg()) {
- Expr *Arg = OldParm->getUninstantiatedDefaultArg();
- NewParm->setUninstantiatedDefaultArg(Arg);
- } else if (Expr *Arg = OldParm->getDefaultArg())
- NewParm->setUninstantiatedDefaultArg(Arg);
-
- NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
-
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
- return NewParm;
+ return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs);
}
QualType
@@ -959,6 +950,91 @@ QualType Sema::SubstType(QualType T,
return Instantiator.TransformType(T);
}
+static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
+ if (T->getType()->isDependentType())
+ return true;
+
+ TypeLoc TL = T->getTypeLoc();
+ if (!isa<FunctionProtoTypeLoc>(TL))
+ return false;
+
+ FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL);
+ for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
+ ParmVarDecl *P = FP.getArg(I);
+
+ // TODO: currently we always rebuild expressions. When we
+ // properly get lazier about this, we should use the same
+ // logic to avoid rebuilding prototypes here.
+ if (P->hasInit())
+ return true;
+ }
+
+ return false;
+}
+
+/// A form of SubstType intended specifically for instantiating the
+/// type of a FunctionDecl. Its purpose is solely to force the
+/// instantiation of default-argument expressions.
+TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
+ const MultiLevelTemplateArgumentList &Args,
+ SourceLocation Loc,
+ DeclarationName Entity) {
+ assert(!ActiveTemplateInstantiations.empty() &&
+ "Cannot perform an instantiation without some context on the "
+ "instantiation stack");
+
+ if (!NeedsInstantiationAsFunctionType(T))
+ return T;
+
+ TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+
+ TypeLocBuilder TLB;
+
+ TypeLoc TL = T->getTypeLoc();
+ TLB.reserve(TL.getFullDataSize());
+
+ QualType Result = Instantiator.TransformType(TLB, TL, QualType());
+ if (Result.isNull())
+ return 0;
+
+ return TLB.getTypeSourceInfo(Context, Result);
+}
+
+ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
+ TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
+ OldParm->getDeclName());
+ if (!NewDI)
+ return 0;
+
+ if (NewDI->getType()->isVoidType()) {
+ Diag(OldParm->getLocation(), diag::err_param_with_void_type);
+ return 0;
+ }
+
+ ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
+ NewDI, NewDI->getType(),
+ OldParm->getIdentifier(),
+ OldParm->getLocation(),
+ OldParm->getStorageClass(),
+ OldParm->getStorageClassAsWritten());
+ if (!NewParm)
+ return 0;
+
+ // Mark the (new) default argument as uninstantiated (if any).
+ if (OldParm->hasUninstantiatedDefaultArg()) {
+ Expr *Arg = OldParm->getUninstantiatedDefaultArg();
+ NewParm->setUninstantiatedDefaultArg(Arg);
+ } else if (Expr *Arg = OldParm->getDefaultArg())
+ NewParm->setUninstantiatedDefaultArg(Arg);
+
+ NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
+
+ CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
+ return NewParm;
+}
+
/// \brief Perform substitution on the base class specifiers of the
/// given class template specialization.
///
@@ -1083,8 +1159,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
- DeclContext *PreviousContext = CurContext;
- CurContext = Instantiation;
+ ContextRAII SavedContext(*this, Instantiation);
// If this is an instantiation of a local class, merge this local
// instantiation scope with the enclosing scope. Otherwise, every
@@ -1120,12 +1195,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation),
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
- CheckCompletedCXXClass(Instantiation);
+ CheckCompletedCXXClass(/*Scope=*/0, Instantiation);
if (Instantiation->isInvalidDecl())
Invalid = true;
// Exit the scope of this instantiation.
- CurContext = PreviousContext;
+ SavedContext.pop();
// 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
@@ -1195,21 +1270,20 @@ Sema::InstantiateClassTemplateSpecialization(
typedef std::pair<ClassTemplatePartialSpecializationDecl *,
TemplateArgumentList *> MatchResult;
llvm::SmallVector<MatchResult, 4> Matched;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
- Partial = Template->getPartialSpecializations().begin(),
- PartialEnd = Template->getPartialSpecializations().end();
- Partial != PartialEnd;
- ++Partial) {
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ Template->getPartialSpecializations(PartialSpecs);
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+ ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(Context, PointOfInstantiation);
if (TemplateDeductionResult Result
- = DeduceTemplateArguments(&*Partial,
+ = DeduceTemplateArguments(Partial,
ClassTemplateSpec->getTemplateArgs(),
Info)) {
// FIXME: Store the failed-deduction information for use in
// diagnostics, later.
(void)Result;
} else {
- Matched.push_back(std::make_pair(&*Partial, Info.take()));
+ Matched.push_back(std::make_pair(Partial, Info.take()));
}
}
@@ -1331,6 +1405,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Function,
MSInfo->getTemplateSpecializationKind(),
@@ -1363,6 +1441,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Var->isStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Var,
MSInfo->getTemplateSpecializationKind(),
@@ -1389,11 +1471,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
}
}
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
- if (Record->isInjectedClassName())
+ // Always skip the injected-class-name, along with any
+ // redeclarations of nested classes, since both would cause us
+ // to try to instantiate the members of a class twice.
+ if (Record->isInjectedClassName() || Record->getPreviousDeclaration())
continue;
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
+
+ if (MSInfo->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ continue;
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Record,
MSInfo->getTemplateSpecializationKind(),
@@ -1502,3 +1592,29 @@ bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output,
return Instantiator.TransformTemplateArgument(Input, Output);
}
+
+Decl *Sema::LocalInstantiationScope::getInstantiationOf(const Decl *D) {
+ for (LocalInstantiationScope *Current = this; Current;
+ Current = Current->Outer) {
+ // Check if we found something within this scope.
+ llvm::DenseMap<const Decl *, Decl *>::iterator Found
+ = Current->LocalDecls.find(D);
+ if (Found != Current->LocalDecls.end())
+ return Found->second;
+
+ // If we aren't combined with our outer scope, we're done.
+ if (!Current->CombineWithOuterScope)
+ break;
+ }
+
+ assert(D->isInvalidDecl() &&
+ "declaration was not instantiated in this scope!");
+ return 0;
+}
+
+void Sema::LocalInstantiationScope::InstantiatedLocal(const Decl *D,
+ Decl *Inst) {
+ Decl *&Stored = LocalDecls[D];
+ assert((!Stored || Stored == Inst)&& "Already instantiated this local");
+ Stored = Inst;
+}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3375ccc0ebcd..8b851b21eacd 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -200,12 +200,22 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
if (Invalid)
Typedef->setInvalidDecl();
+ if (const TagType *TT = DI->getType()->getAs<TagType>()) {
+ TagDecl *TD = TT->getDecl();
+
+ // If the TagDecl that the TypedefDecl points to is an anonymous decl
+ // keep track of the TypedefDecl.
+ if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl())
+ TD->setTypedefForAnonDecl(Typedef);
+ }
+
if (TypedefDecl *Prev = D->getPreviousDeclaration()) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+
Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
@@ -322,7 +332,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
DI->getType(), DI,
- D->getStorageClass());
+ D->getStorageClass(),
+ D->getStorageClassAsWritten());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
@@ -354,6 +365,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Owner->makeDeclVisibleInContext(Var);
} else {
Owner->addDecl(Var);
+
+ if (Owner->isFunctionOrMethod())
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
// Link instantiations of static data members back to the template from
@@ -476,47 +490,37 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
- FriendDecl::FriendUnion FU;
-
// Handle friend type expressions by simply substituting template
- // parameters into the pattern type.
+ // parameters into the pattern type and checking the result.
if (TypeSourceInfo *Ty = D->getFriendType()) {
TypeSourceInfo *InstTy =
SemaRef.SubstType(Ty, TemplateArgs,
D->getLocation(), DeclarationName());
- if (!InstTy) return 0;
-
- // This assertion is valid because the source type was necessarily
- // an elaborated-type-specifier with a record tag.
- assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
-
- FU = InstTy;
-
- // Handle everything else by appropriate substitution.
- } else {
- NamedDecl *ND = D->getFriendDecl();
- assert(ND && "friend decl must be a decl or a type!");
-
- // FIXME: We have a problem here, because the nested call to Visit(ND)
- // will inject the thing that the friend references into the current
- // owner, which is wrong.
- Decl *NewND;
+ if (!InstTy)
+ return 0;
- // Hack to make this work almost well pending a rewrite.
- if (D->wasSpecialization()) {
- // Totally egregious hack to work around PR5866
+ FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy);
+ if (!FD)
return 0;
- } else {
- NewND = Visit(ND);
- }
- if (!NewND) return 0;
+
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+ }
+
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
- FU = cast<NamedDecl>(NewND);
- }
+ // All of the Visit implementations for the various potential friend
+ // declarations have to be carefully written to work for friend
+ // objects, with the most important detail being that the target
+ // decl should almost certainly not be placed in Owner.
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
FriendDecl *FD =
- FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
- D->getFriendLoc());
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
Owner->addDecl(FD);
return FD;
@@ -619,21 +623,6 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
-namespace {
- class SortDeclByLocation {
- SourceManager &SourceMgr;
-
- public:
- explicit SortDeclByLocation(SourceManager &SourceMgr)
- : SourceMgr(SourceMgr) { }
-
- bool operator()(const Decl *X, const Decl *Y) const {
- return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
- Y->getLocation());
- }
- };
-}
-
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
@@ -698,19 +687,52 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return 0;
}
+ bool AdoptedPreviousTemplateParams = false;
if (PrevClassTemplate) {
+ bool Complain = true;
+
+ // HACK: libstdc++ 4.2.1 contains an ill-formed friend class
+ // template for struct std::tr1::__detail::_Map_base, where the
+ // template parameters of the friend declaration don't match the
+ // template parameters of the original declaration. In this one
+ // case, we don't complain about the ill-formed friend
+ // declaration.
+ if (isFriend && Pattern->getIdentifier() &&
+ Pattern->getIdentifier()->isStr("_Map_base") &&
+ DC->isNamespace() &&
+ cast<NamespaceDecl>(DC)->getIdentifier() &&
+ cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__detail")) {
+ DeclContext *DCParent = DC->getParent();
+ if (DCParent->isNamespace() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier() &&
+ cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) {
+ DeclContext *DCParent2 = DCParent->getParent();
+ if (DCParent2->isNamespace() &&
+ cast<NamespaceDecl>(DCParent2)->getIdentifier() &&
+ cast<NamespaceDecl>(DCParent2)->getIdentifier()->isStr("std") &&
+ DCParent2->getParent()->isTranslationUnit())
+ Complain = false;
+ }
+ }
+
TemplateParameterList *PrevParams
= PrevClassTemplate->getTemplateParameters();
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
- /*Complain=*/true,
- Sema::TPL_TemplateMatch))
- return 0;
+ Complain,
+ Sema::TPL_TemplateMatch)) {
+ if (Complain)
+ return 0;
+
+ AdoptedPreviousTemplateParams = true;
+ InstParams = PrevParams;
+ }
// Do some additional validation, then merge default arguments
// from the existing declarations.
- if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
+ if (!AdoptedPreviousTemplateParams &&
+ SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
Sema::TPC_ClassTemplate))
return 0;
}
@@ -730,7 +752,13 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
D->getIdentifier(), InstParams, RecordInst,
PrevClassTemplate);
RecordInst->setDescribedClassTemplate(Inst);
+
if (isFriend) {
+ if (PrevClassTemplate)
+ Inst->setAccess(PrevClassTemplate->getAccess());
+ else
+ Inst->setAccess(D->getAccess());
+
Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
// TODO: do we want to track the instantiation progeny of this
// friend target decl?
@@ -742,29 +770,19 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(RecordInst,
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
-
+
// Finish handling of friends.
if (isFriend) {
DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
return Inst;
}
- Inst->setAccess(D->getAccess());
Owner->addDecl(Inst);
- // First, we sort the partial specializations by location, so
- // that we instantiate them in the order they were declared.
- llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
- for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
- P = D->getPartialSpecializations().begin(),
- PEnd = D->getPartialSpecializations().end();
- P != PEnd; ++P)
- PartialSpecs.push_back(&*P);
- std::sort(PartialSpecs.begin(), PartialSpecs.end(),
- SortDeclByLocation(SemaRef.SourceMgr));
-
// Instantiate all of the partial specializations of this member class
// template.
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
@@ -807,7 +825,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// merged with the local instantiation scope for the function template
// itself.
Sema::LocalInstantiationScope Scope(SemaRef);
-
+
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
@@ -963,7 +981,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, TInfo,
- D->getStorageClass(),
+ D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype());
if (Qualifier)
@@ -1027,11 +1045,47 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+ bool isExplicitSpecialization = false;
LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (TemplateParams || !FunctionTemplate) {
+ if (DependentFunctionTemplateSpecializationInfo *Info
+ = D->getDependentSpecializationInfo()) {
+ assert(isFriend && "non-friend has dependent specialization info?");
+
+ // This needs to be set now for future sanity.
+ Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+
+ // Instantiate the explicit template arguments.
+ TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+ Info->getRAngleLoc());
+ for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) {
+ TemplateArgumentLoc Loc;
+ if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs))
+ return 0;
+
+ ExplicitArgs.addArgument(Loc);
+ }
+
+ // Map the candidate templates to their instantiations.
+ for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
+ Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
+ Info->getTemplate(I),
+ TemplateArgs);
+ if (!Temp) return 0;
+
+ Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+ }
+
+ if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+ &ExplicitArgs,
+ Previous))
+ Function->setInvalidDecl();
+
+ isExplicitSpecialization = true;
+
+ } else if (TemplateParams || !FunctionTemplate) {
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
@@ -1046,25 +1100,30 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
- false, Redeclaration,
+ isExplicitSpecialization, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
+ NamedDecl *PrincipalDecl = (TemplateParams
+ ? cast<NamedDecl>(FunctionTemplate)
+ : Function);
+
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
if (isFriend) {
- NamedDecl *ToFriendD = 0;
NamedDecl *PrevDecl;
- if (TemplateParams) {
- ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ if (TemplateParams)
PrevDecl = FunctionTemplate->getPreviousDeclaration();
- } else {
- ToFriendD = Function;
+ else
PrevDecl = Function->getPreviousDeclaration();
- }
- ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
- DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
+
+ PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
+ DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
}
+ if (Function->isOverloadedOperator() && !DC->isRecord() &&
+ PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ PrincipalDecl->setNonMemberOperator();
+
return Function;
}
@@ -1146,14 +1205,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Constructor->getLocation(),
Name, T, TInfo,
Constructor->isExplicit(),
- Constructor->isInlineSpecified(), false);
+ Constructor->isInlineSpecified(),
+ false);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(ClassTy));
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
Destructor->getLocation(), Name,
- T, Destructor->isInlineSpecified(), false);
+ T, Destructor->isInlineSpecified(),
+ false);
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
CanQualType ConvTy
= SemaRef.Context.getCanonicalType(
@@ -1168,7 +1229,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
D->getDeclName(), T, TInfo,
- D->isStatic(), D->isInlineSpecified());
+ D->isStatic(),
+ D->getStorageClassAsWritten(),
+ D->isInlineSpecified());
}
if (Qualifier)
@@ -1279,41 +1342,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- QualType T;
- TypeSourceInfo *DI = D->getTypeSourceInfo();
- if (DI) {
- DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
- D->getDeclName());
- if (DI) T = DI->getType();
- } else {
- T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(),
- D->getDeclName());
- DI = 0;
- }
-
- if (T.isNull())
- return 0;
-
- T = SemaRef.adjustParameterType(T);
-
- // Allocate the parameter
- ParmVarDecl *Param
- = ParmVarDecl::Create(SemaRef.Context,
- SemaRef.Context.getTranslationUnitDecl(),
- D->getLocation(),
- D->getIdentifier(), T, DI, D->getStorageClass(), 0);
-
- // Mark the default argument as being uninstantiated.
- if (D->hasUninstantiatedDefaultArg())
- Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
- else if (Expr *Arg = D->getDefaultArg())
- Param->setUninstantiatedDefaultArg(Arg);
-
- // Note: we don't try to instantiate function parameters until after
- // we've instantiated the function's type. Therefore, we don't have
- // to check for 'void' parameter types here.
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
- return Param;
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1718,7 +1747,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
Converted,
InstTemplateArgs,
CanonType,
- 0);
+ 0,
+ ClassTemplate->getPartialSpecializations().size());
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return 0;
@@ -1733,48 +1763,50 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return false;
}
-bool
-Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) {
- bool Invalid = false;
- for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i)
- if (ParmVarDecl *PInst = Params[i]) {
- if (PInst->isInvalidDecl())
- Invalid = true;
- else if (PInst->getType()->isVoidType()) {
- Diag(PInst->getLocation(), diag::err_param_with_void_type);
- PInst->setInvalidDecl();
- Invalid = true;
- }
- else if (RequireNonAbstractType(PInst->getLocation(),
- PInst->getType(),
- diag::err_abstract_type_in_decl,
- Sema::AbstractParamType)) {
- PInst->setInvalidDecl();
- Invalid = true;
- }
- }
- return Invalid;
-}
-
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
- TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName());
+ TypeSourceInfo *NewTInfo
+ = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
+ D->getTypeSpecStartLoc(),
+ D->getDeclName());
if (!NewTInfo)
return 0;
- // Get parameters from the new type info.
- TypeLoc NewTL = NewTInfo->getTypeLoc();
- FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
- assert(NewProtoLoc && "Missing prototype?");
- for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
- Params.push_back(NewProtoLoc->getArg(i));
-
+ if (NewTInfo != OldTInfo) {
+ // Get parameters from the new type info.
+ TypeLoc OldTL = OldTInfo->getTypeLoc();
+ if (FunctionProtoTypeLoc *OldProtoLoc
+ = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ TypeLoc NewTL = NewTInfo->getTypeLoc();
+ FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
+ assert(NewProtoLoc && "Missing prototype?");
+ for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) {
+ // FIXME: Variadic templates will break this.
+ Params.push_back(NewProtoLoc->getArg(i));
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ OldProtoLoc->getArg(i),
+ NewProtoLoc->getArg(i));
+ }
+ }
+ } else {
+ // The function type itself was not dependent and therefore no
+ // substitution occurred. However, we still need to instantiate
+ // the function parameters themselves.
+ TypeLoc OldTL = OldTInfo->getTypeLoc();
+ if (FunctionProtoTypeLoc *OldProtoLoc
+ = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
+ ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
+ if (!Parm)
+ return 0;
+ Params.push_back(Parm);
+ }
+ }
+ }
return NewTInfo;
}
@@ -1938,8 +1970,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
- return;
-
+ return;
+
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
@@ -1971,7 +2003,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
CurContext = Function;
MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function);
+ getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =
@@ -2459,7 +2491,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
T = Context.getTypeDeclType(Record);
assert(isa<InjectedClassNameType>(T) &&
"type of partial specialization is not an InjectedClassNameType");
- T = cast<InjectedClassNameType>(T)->getUnderlyingType();
+ T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
}
if (!T.isNull()) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 8278691a4a3b..d1a74beb538f 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -81,9 +81,12 @@ 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))
+ if (ProcessFnAttr(S, Type, *I->first)) {
S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
<< I->first->getName() << I->second;
+ // Avoid any further processing of this attribute.
+ I->first->setInvalid();
+ }
Attrs.clear();
}
@@ -92,6 +95,8 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) {
E = Attrs.end(); I != E; ++I) {
S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type)
<< I->first->getName() << I->second;
+ // Avoid any further processing of this attribute.
+ I->first->setInvalid();
}
Attrs.clear();
}
@@ -280,6 +285,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
if (TheSema.getLangOptions().CPlusPlus) {
TagDecl::TagKind Tag
= TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType());
+ Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result);
Result = Context.getElaboratedType(Result, Tag);
}
@@ -498,6 +504,8 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
Qs.removeRestrict();
}
+ assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType");
+
// Build the pointer type.
return Context.getQualifiedType(Context.getPointerType(T), Qs);
}
@@ -604,15 +612,31 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
SourceRange Brackets, DeclarationName Entity) {
SourceLocation Loc = Brackets.getBegin();
- // C99 6.7.5.2p1: If the element type is an incomplete or function type,
- // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
- // Not in C++, though. There we only dislike void.
if (getLangOptions().CPlusPlus) {
+ // C++ [dcl.array]p1:
+ // T is called the array element type; this type shall not be a reference
+ // type, the (possibly cv-qualified) type void, a function type or an
+ // abstract class type.
+ //
+ // Note: function types are handled in the common path with C.
+ if (T->isReferenceType()) {
+ Diag(Loc, diag::err_illegal_decl_array_of_references)
+ << getPrintableNameForEntity(Entity) << T;
+ return QualType();
+ }
+
if (T->isVoidType()) {
Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T;
return QualType();
}
+
+ if (RequireNonAbstractType(Brackets.getBegin(), T,
+ diag::err_array_of_abstract_type))
+ return QualType();
+
} else {
+ // C99 6.7.5.2p1: If the element type is an incomplete or function type,
+ // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
if (RequireCompleteType(Loc, T,
diag::err_illegal_decl_array_incomplete_type))
return QualType();
@@ -624,13 +648,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
- // C++ 8.3.2p4: There shall be no ... arrays of references ...
- if (T->isReferenceType()) {
- Diag(Loc, diag::err_illegal_decl_array_of_references)
- << getPrintableNameForEntity(Entity) << T;
- return QualType();
- }
-
if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) {
Diag(Loc, diag::err_illegal_decl_array_of_auto)
<< getPrintableNameForEntity(Entity);
@@ -922,7 +939,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
-
+ TypeSourceInfo *ReturnTypeInfo = 0;
+
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
switch (D.getName().getKind()) {
@@ -948,12 +966,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Constructors and destructors don't have return types. Use
// "void" instead.
T = Context.VoidTy;
+
+ if (TInfo)
+ ReturnTypeInfo = Context.getTrivialTypeSourceInfo(T,
+ D.getName().StartLocation);
break;
case UnqualifiedId::IK_ConversionFunctionId:
// The result type of a conversion function is the type that it
// converts to.
- T = GetTypeFromParser(D.getName().ConversionFunctionId);
+ T = GetTypeFromParser(D.getName().ConversionFunctionId,
+ TInfo? &ReturnTypeInfo : 0);
break;
}
@@ -1036,7 +1059,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) {
const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>();
T = Context.getObjCObjectPointerType(T,
- (ObjCProtocolDecl **)OIT->qual_begin(),
+ const_cast<ObjCProtocolDecl **>(
+ OIT->qual_begin()),
OIT->getNumProtocols(),
DeclType.Ptr.TypeQuals);
break;
@@ -1253,8 +1277,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
// The scope spec must refer to a class, or be dependent.
QualType ClsType;
- if (isDependentScopeSpecifier(DeclType.Mem.Scope())
- || dyn_cast_or_null<CXXRecordDecl>(
+ if (DeclType.Mem.Scope().isInvalid()) {
+ // Avoid emitting extra errors if we already errored on the scope.
+ D.setInvalidType(true);
+ } else if (isDependentScopeSpecifier(DeclType.Mem.Scope())
+ || dyn_cast_or_null<CXXRecordDecl>(
computeDeclContext(DeclType.Mem.Scope()))) {
NestedNameSpecifier *NNS
= (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep();
@@ -1353,7 +1380,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.isInvalidType())
*TInfo = 0;
else
- *TInfo = GetTypeSourceInfoForDeclarator(D, T);
+ *TInfo = GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo);
}
return T;
@@ -1538,8 +1565,14 @@ namespace {
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
+///
+/// \param ReturnTypeInfo For declarators whose return type does not show
+/// up in the normal place in the declaration specifiers (such as a C++
+/// conversion function), this pointer will refer to a type source information
+/// for that return type.
TypeSourceInfo *
-Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
+Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
+ TypeSourceInfo *ReturnTypeInfo) {
TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T);
UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc();
@@ -1549,7 +1582,18 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) {
}
TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL);
-
+
+ // We have source information for the return type that was not in the
+ // declaration specifiers; copy that information into the current type
+ // location so that it will be retained. This occurs, for example, with
+ // a C++ conversion function, where the return type occurs within the
+ // declarator-id rather than in the declaration specifiers.
+ if (ReturnTypeInfo && D.getDeclSpec().getTypeSpecType() == TST_unspecified) {
+ TypeLoc TL = ReturnTypeInfo->getTypeLoc();
+ assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
+ memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
+ }
+
return TInfo;
}
@@ -1648,12 +1692,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
// for two or more different address spaces."
if (Type.getAddressSpace()) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers);
+ Attr.setInvalid();
return;
}
// Check the attribute arguments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0));
@@ -1661,6 +1707,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int)
<< ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1669,6 +1716,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (addrSpace.isNegative()) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
<< ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
addrSpace.setIsSigned(false);
@@ -1678,6 +1726,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
if (addrSpace > max) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
<< Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1691,6 +1740,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
const AttributeList &Attr, Sema &S) {
if (Type.getObjCGCAttr() != Qualifiers::GCNone) {
S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc);
+ Attr.setInvalid();
return;
}
@@ -1698,11 +1748,13 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
if (!Attr.getParameterName()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
<< "objc_gc" << 1;
+ Attr.setInvalid();
return;
}
Qualifiers::GC GCAttr;
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
if (Attr.getParameterName()->isStr("weak"))
@@ -1712,6 +1764,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
else {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "objc_gc" << Attr.getParameterName();
+ Attr.setInvalid();
return;
}
@@ -1725,6 +1778,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
// Complain immediately if the arg count is wrong.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ Attr.setInvalid();
return false;
}
@@ -1766,6 +1820,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
// Otherwise, a calling convention.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ Attr.setInvalid();
return false;
}
@@ -1788,13 +1843,17 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
CallingConv CCOld = Fn->getCallConv();
if (S.Context.getCanonicalCallConv(CC) ==
- S.Context.getCanonicalCallConv(CCOld)) return false;
+ S.Context.getCanonicalCallConv(CCOld)) {
+ Attr.setInvalid();
+ 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);
+ Attr.setInvalid();
return false;
}
@@ -1803,6 +1862,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
if (isa<FunctionNoProtoType>(Fn)) {
S.Diag(Attr.getLoc(), diag::err_cconv_knr)
<< FunctionType::getNameForCallConv(CC);
+ Attr.setInvalid();
return false;
}
@@ -1810,6 +1870,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
if (FnP->isVariadic()) {
S.Diag(Attr.getLoc(), diag::err_cconv_varargs)
<< FunctionType::getNameForCallConv(CC);
+ Attr.setInvalid();
return false;
}
}
@@ -1829,6 +1890,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
// Check the attribute arugments.
if (Attr.getNumArgs() != 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ Attr.setInvalid();
return;
}
Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
@@ -1836,12 +1898,14 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
<< "vector_size" << sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
// the base type must be integer or float, and can't already be a vector.
if (CurType->isVectorType() ||
(!CurType->isIntegerType() && !CurType->isRealFloatingType())) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
+ Attr.setInvalid();
return;
}
unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType));
@@ -1852,11 +1916,13 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S
if (vectorSize % typeSize) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
<< sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
if (vectorSize == 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
<< sizeExpr->getSourceRange();
+ Attr.setInvalid();
return;
}
@@ -1873,8 +1939,12 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
// type, but others can be present in the type specifiers even though they
// apply to the decl. Here we apply type attributes and ignore the rest.
for (; AL; AL = AL->getNext()) {
- // If this is an attribute we can handle, do so now, otherwise, add it to
- // the LeftOverAttrs list for rechaining.
+ // Skip attributes that were marked to be invalid.
+ if (AL->isInvalid())
+ continue;
+
+ // If this is an attribute we can handle, do so now,
+ // otherwise, add it to the FnAttrs list for rechaining.
switch (AL->getKind()) {
default: break;
@@ -2029,7 +2099,10 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization, Specialization);
+ // The access doesn't really matter in this case.
+ DeclAccessPair Found = DeclAccessPair::make(Specialization,
+ Specialization->getAccess());
+ E = FixOverloadedFunctionReference(E, Found, Specialization);
if (!E)
return QualType();
} else {
@@ -2049,7 +2122,10 @@ QualType Sema::BuildDecltypeType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization, Specialization);
+ // The access doesn't really matter in this case.
+ DeclAccessPair Found = DeclAccessPair::make(Specialization,
+ Specialization->getAccess());
+ E = FixOverloadedFunctionReference(E, Found, Specialization);
if (!E)
return QualType();
} else {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f9ffd3f41aa5..5ce268bd9eb4 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -338,6 +338,7 @@ public:
QualType ObjectType);
OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
+ OwningExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
#define STMT(Node, Parent) \
OwningStmtResult Transform##Node(Node *S);
@@ -378,10 +379,6 @@ public:
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
SourceLocation Sigil);
- /// \brief Build a new Objective C object pointer type.
- QualType RebuildObjCObjectPointerType(QualType PointeeType,
- SourceLocation Sigil);
-
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
/// qualifiers.
@@ -577,10 +574,9 @@ public:
TagDecl::TagKind Kind = TagDecl::TK_enum;
switch (Keyword) {
case ETK_None:
- // FIXME: Note the lack of the "typename" specifier!
- // Fall through
+ // Fall through.
case ETK_Typename:
- return SemaRef.CheckTypenameType(NNS, *Id, SR);
+ return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
case ETK_Class: Kind = TagDecl::TK_class; break;
case ETK_Struct: Kind = TagDecl::TK_struct; break;
@@ -892,6 +888,88 @@ public:
move(Exprs), move(AsmString), move(Clobbers),
RParenLoc, MSAsm);
}
+
+ /// \brief Build a new Objective-C @try statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg TryBody,
+ MultiStmtArg CatchStmts,
+ StmtArg Finally) {
+ return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(CatchStmts),
+ move(Finally));
+ }
+
+ /// \brief Rebuild an Objective-C exception declaration.
+ ///
+ /// By default, performs semantic analysis to build the new declaration.
+ /// Subclasses may override this routine to provide different behavior.
+ VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl,
+ TypeSourceInfo *TInfo, QualType T) {
+ return getSema().BuildObjCExceptionDecl(TInfo, T,
+ ExceptionDecl->getIdentifier(),
+ ExceptionDecl->getLocation());
+ }
+
+ /// \brief Build a new Objective-C @catch statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParenLoc,
+ VarDecl *Var,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc,
+ Sema::DeclPtrTy::make(Var),
+ move(Body));
+ }
+
+ /// \brief Build a new Objective-C @finally statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtFinallyStmt(AtLoc, move(Body));
+ }
+
+ /// \brief Build a new Objective-C @throw statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Operand) {
+ return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand));
+ }
+
+ /// \brief Build a new Objective-C @synchronized statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg Object,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object),
+ move(Body));
+ }
+
+ /// \brief Build a new Objective-C fast enumeration statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg Element,
+ ExprArg Collection,
+ SourceLocation RParenLoc,
+ StmtArg Body) {
+ return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc,
+ move(Element),
+ move(Collection),
+ RParenLoc,
+ move(Body));
+ }
/// \brief Build a new C++ exception declaration.
///
@@ -989,6 +1067,19 @@ public:
return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr));
}
+ /// \brief Build a new builtin offsetof expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc,
+ TypeSourceInfo *Type,
+ Action::OffsetOfComponent *Components,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components,
+ NumComponents, RParenLoc);
+ }
+
/// \brief Build a new sizeof or alignof expression with a type argument.
///
/// By default, performs semantic analysis to build the new expression.
@@ -1421,30 +1512,24 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
- SourceLocation LParenLoc,
- QualType T,
+ OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true,
- T.getAsOpaquePtr(), RParenLoc);
+ return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand,
+ RParenLoc);
}
/// \brief Build a new C++ typeid(expr) expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
- SourceLocation LParenLoc,
+ OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+ SourceLocation TypeidLoc,
ExprArg Operand,
SourceLocation RParenLoc) {
- OwningExprResult Result
- = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(),
- RParenLoc);
- if (Result.isInvalid())
- return getSema().ExprError();
-
- Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
- return move(Result);
+ return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, move(Operand),
+ RParenLoc);
}
/// \brief Build a new C++ "this" expression.
@@ -1688,29 +1773,147 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc,
- QualType T,
+ TypeSourceInfo *EncodeTypeInfo,
SourceLocation RParenLoc) {
- return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T,
+ return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo,
RParenLoc));
}
- /// \brief Build a new Objective-C protocol expression.
+ /// \brief Build a new Objective-C class message.
+ OwningExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ MultiExprArg Args,
+ SourceLocation RBracLoc) {
+ return SemaRef.BuildClassMessage(ReceiverTypeInfo,
+ ReceiverTypeInfo->getType(),
+ /*SuperLoc=*/SourceLocation(),
+ Sel, Method, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ /// \brief Build a new Objective-C instance message.
+ OwningExprResult RebuildObjCMessageExpr(ExprArg Receiver,
+ Selector Sel,
+ ObjCMethodDecl *Method,
+ SourceLocation LBracLoc,
+ MultiExprArg Args,
+ SourceLocation RBracLoc) {
+ QualType ReceiverType = static_cast<Expr *>(Receiver.get())->getType();
+ return SemaRef.BuildInstanceMessage(move(Receiver),
+ ReceiverType,
+ /*SuperLoc=*/SourceLocation(),
+ Sel, Method, LBracLoc, RBracLoc,
+ move(Args));
+ }
+
+ /// \brief Build a new Objective-C ivar reference expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol,
- SourceLocation AtLoc,
- SourceLocation ProtoLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
- return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression(
- Protocol->getIdentifier(),
- AtLoc,
- ProtoLoc,
- LParenLoc,
- RParenLoc));
+ OwningExprResult RebuildObjCIvarRefExpr(ExprArg BaseArg, ObjCIvarDecl *Ivar,
+ SourceLocation IvarLoc,
+ bool IsArrow, bool IsFreeIvar) {
+ // FIXME: We lose track of the IsFreeIvar bit.
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc,
+ Sema::LookupMemberName);
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/IvarLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/IvarLoc, IsArrow, SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
+ /// \brief Build a new Objective-C property reference expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCPropertyRefExpr(ExprArg BaseArg,
+ ObjCPropertyDecl *Property,
+ SourceLocation PropertyLoc) {
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
+ Sema::LookupMemberName);
+ bool IsArrow = false;
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/PropertyLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/PropertyLoc, IsArrow,
+ SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
+ /// \brief Build a new Objective-C implicit setter/getter reference
+ /// expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCImplicitSetterGetterRefExpr(
+ ObjCMethodDecl *Getter,
+ QualType T,
+ ObjCMethodDecl *Setter,
+ SourceLocation NameLoc,
+ ExprArg Base) {
+ // Since these expressions can only be value-dependent, we do not need to
+ // perform semantic analysis again.
+ return getSema().Owned(
+ new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T,
+ Setter,
+ NameLoc,
+ Base.takeAs<Expr>()));
}
+ /// \brief Build a new Objective-C "isa" expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildObjCIsaExpr(ExprArg BaseArg, SourceLocation IsaLoc,
+ bool IsArrow) {
+ CXXScopeSpec SS;
+ Expr *Base = BaseArg.takeAs<Expr>();
+ LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
+ Sema::LookupMemberName);
+ OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
+ /*FIME:*/IsaLoc,
+ SS, DeclPtrTy());
+ if (Result.isInvalid())
+ return getSema().ExprError();
+
+ if (Result.get())
+ return move(Result);
+
+ return getSema().BuildMemberReferenceExpr(getSema().Owned(Base),
+ Base->getType(),
+ /*FIXME:*/IsaLoc, IsArrow, SS,
+ /*FirstQualifierInScope=*/0,
+ R,
+ /*TemplateArgs=*/0);
+ }
+
/// \brief Build a new shuffle vector expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2225,29 +2428,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
return T.getType();
}
-// Ugly metaprogramming macros because I couldn't be bothered to make
-// the equivalent template version work.
-#define TransformPointerLikeType(TypeClass) do { \
- QualType PointeeType \
- = getDerived().TransformType(TLB, TL.getPointeeLoc()); \
- if (PointeeType.isNull()) \
- return QualType(); \
- \
- QualType Result = TL.getType(); \
- if (getDerived().AlwaysRebuild() || \
- PointeeType != TL.getPointeeLoc().getType()) { \
- Result = getDerived().Rebuild##TypeClass(PointeeType, \
- TL.getSigilLoc()); \
- if (Result.isNull()) \
- return QualType(); \
- } \
- \
- TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \
- NewT.setSigilLoc(TL.getSigilLoc()); \
- \
- return Result; \
-} while(0)
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T,
@@ -2271,7 +2451,42 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL,
QualType ObjectType) {
- TransformPointerLikeType(PointerType);
+ QualType PointeeType
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (PointeeType->isObjCInterfaceType()) {
+ // A dependent pointer type 'T *' has is being transformed such
+ // that an Objective-C class type is being replaced for 'T'. The
+ // resulting pointer type is an ObjCObjectPointerType, not a
+ // PointerType.
+ const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>();
+ Result = SemaRef.Context.getObjCObjectPointerType(PointeeType,
+ const_cast<ObjCProtocolDecl **>(
+ IFace->qual_begin()),
+ IFace->getNumProtocols());
+
+ ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+ NewT.setStarLoc(TL.getSigilLoc());
+ NewT.setHasProtocolsAsWritten(false);
+ NewT.setLAngleLoc(SourceLocation());
+ NewT.setRAngleLoc(SourceLocation());
+ NewT.setHasBaseTypeAsWritten(true);
+ return Result;
+ }
+
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
+ NewT.setSigilLoc(TL.getSigilLoc());
+ return Result;
}
template<typename Derived>
@@ -2279,7 +2494,23 @@ QualType
TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
BlockPointerTypeLoc TL,
QualType ObjectType) {
- TransformPointerLikeType(BlockPointerType);
+ QualType PointeeType
+ = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildBlockPointerType(PointeeType,
+ TL.getSigilLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ BlockPointerTypeLoc NewT = TLB.push<BlockPointerTypeLoc>(Result);
+ NewT.setSigilLoc(TL.getSigilLoc());
+ return Result;
}
/// Transforms a reference type. Note that somewhat paradoxically we
@@ -2630,6 +2861,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
+ OldParm->getStorageClassAsWritten(),
/* DefArg */ NULL);
}
@@ -2675,17 +2907,19 @@ QualType
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
QualType ObjectType) {
- FunctionProtoType *T = TL.getTypePtr();
- QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
- if (ResultType.isNull())
- return QualType();
-
- // Transform the parameters.
+ // Transform the parameters. We do this first for the benefit of template
+ // instantiations, so that the ParmVarDecls get/ placed into the template
+ // instantiation scope before we transform the function type.
llvm::SmallVector<QualType, 4> ParamTypes;
llvm::SmallVector<ParmVarDecl*, 4> ParamDecls;
if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls))
return QualType();
-
+
+ FunctionProtoType *T = TL.getTypePtr();
+ QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ if (ResultType.isNull())
+ return QualType();
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
ResultType != T->getResultType() ||
@@ -3117,8 +3351,8 @@ QualType
TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
ObjCInterfaceTypeLoc TL,
QualType ObjectType) {
- assert(false && "TransformObjCInterfaceType unimplemented");
- return QualType();
+ // ObjCInterfaceType is never dependent.
+ return TL.getType();
}
template<typename Derived>
@@ -3126,8 +3360,8 @@ QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL,
QualType ObjectType) {
- assert(false && "TransformObjCObjectPointerType unimplemented");
- return QualType();
+ // ObjCObjectPointerType is never dependent.
+ return TL.getType();
}
//===----------------------------------------------------------------------===//
@@ -3587,51 +3821,172 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @try statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the body of the @try.
+ OwningStmtResult TryBody = getDerived().TransformStmt(S->getTryBody());
+ if (TryBody.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the @catch statements (if present).
+ bool AnyCatchChanged = false;
+ ASTOwningVector<&ActionBase::DeleteStmt> CatchStmts(SemaRef);
+ for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+ OwningStmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I));
+ if (Catch.isInvalid())
+ return SemaRef.StmtError();
+ if (Catch.get() != S->getCatchStmt(I))
+ AnyCatchChanged = true;
+ CatchStmts.push_back(Catch.release());
+ }
+
+ // Transform the @finally statement (if present).
+ OwningStmtResult Finally(SemaRef);
+ if (S->getFinallyStmt()) {
+ Finally = getDerived().TransformStmt(S->getFinallyStmt());
+ if (Finally.isInvalid())
+ return SemaRef.StmtError();
+ }
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ TryBody.get() == S->getTryBody() &&
+ !AnyCatchChanged &&
+ Finally.get() == S->getFinallyStmt())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), move(TryBody),
+ move_arg(CatchStmts), move(Finally));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @catch statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the @catch parameter, if there is one.
+ VarDecl *Var = 0;
+ if (VarDecl *FromVar = S->getCatchParamDecl()) {
+ TypeSourceInfo *TSInfo = 0;
+ if (FromVar->getTypeSourceInfo()) {
+ TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo());
+ if (!TSInfo)
+ return SemaRef.StmtError();
+ }
+
+ QualType T;
+ if (TSInfo)
+ T = TSInfo->getType();
+ else {
+ T = getDerived().TransformType(FromVar->getType());
+ if (T.isNull())
+ return SemaRef.StmtError();
+ }
+
+ Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T);
+ if (!Var)
+ return SemaRef.StmtError();
+ }
+
+ OwningStmtResult Body = getDerived().TransformStmt(S->getCatchBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(),
+ S->getRParenLoc(),
+ Var, move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @finally statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getFinallyBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Body.get() == S->getFinallyBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(),
+ move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @throw statement");
- return SemaRef.Owned(S->Retain());
+ OwningExprResult Operand(SemaRef);
+ if (S->getThrowExpr()) {
+ Operand = getDerived().TransformExpr(S->getThrowExpr());
+ if (Operand.isInvalid())
+ return getSema().StmtError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Operand.get() == S->getThrowExpr())
+ return getSema().Owned(S->Retain());
+
+ return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
ObjCAtSynchronizedStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @synchronized statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the object we are locking.
+ OwningExprResult Object = getDerived().TransformExpr(S->getSynchExpr());
+ if (Object.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getSynchBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing change, just retain the current statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Object.get() == S->getSynchExpr() &&
+ Body.get() == S->getSynchBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(),
+ move(Object), move(Body));
}
template<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCForCollectionStmt(
ObjCForCollectionStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C for-each statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the element statement.
+ OwningStmtResult Element = getDerived().TransformStmt(S->getElement());
+ if (Element.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the collection expression.
+ OwningExprResult Collection = getDerived().TransformExpr(S->getCollection());
+ if (Collection.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing changed, just retain this statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Element.get() == S->getElement() &&
+ Collection.get() == S->getCollection() &&
+ Body.get() == S->getBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(),
+ /*FIXME:*/S->getForLoc(),
+ move(Element),
+ move(Collection),
+ S->getRParenLoc(),
+ move(Body));
}
@@ -3828,6 +4183,72 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
template<typename Derived>
Sema::OwningExprResult
+TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
+ // Transform the type.
+ TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+ if (!Type)
+ return getSema().ExprError();
+
+ // Transform all of the components into components similar to what the
+ // parser uses.
+ // FIXME: It would be slightly more efficient in the non-dependent case to
+ // just map FieldDecls, rather than requiring the rebuilder to look for
+ // the fields again. However, __builtin_offsetof is rare enough in
+ // template code that we don't care.
+ bool ExprChanged = false;
+ typedef Action::OffsetOfComponent Component;
+ typedef OffsetOfExpr::OffsetOfNode Node;
+ llvm::SmallVector<Component, 4> Components;
+ for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+ const Node &ON = E->getComponent(I);
+ Component Comp;
+ Comp.isBrackets = true;
+ Comp.LocStart = ON.getRange().getBegin();
+ Comp.LocEnd = ON.getRange().getEnd();
+ switch (ON.getKind()) {
+ case Node::Array: {
+ Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex());
+ OwningExprResult Index = getDerived().TransformExpr(FromIndex);
+ if (Index.isInvalid())
+ return getSema().ExprError();
+
+ ExprChanged = ExprChanged || Index.get() != FromIndex;
+ Comp.isBrackets = true;
+ Comp.U.E = Index.takeAs<Expr>(); // FIXME: leaked
+ break;
+ }
+
+ case Node::Field:
+ case Node::Identifier:
+ Comp.isBrackets = false;
+ Comp.U.IdentInfo = ON.getFieldName();
+ if (!Comp.U.IdentInfo)
+ continue;
+
+ break;
+
+ case Node::Base:
+ // Will be recomputed during the rebuild.
+ continue;
+ }
+
+ Components.push_back(Comp);
+ }
+
+ // If nothing changed, retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Type == E->getTypeSourceInfo() &&
+ !ExprChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new offsetof expression.
+ return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type,
+ Components.data(), Components.size(),
+ E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (E->isArgumentType()) {
TypeSourceInfo *OldT = E->getArgumentTypeInfo();
@@ -4597,19 +5018,18 @@ template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
if (E->isTypeOperand()) {
- TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
-
- QualType T = getDerived().TransformType(E->getTypeOperand());
- if (T.isNull())
+ TypeSourceInfo *TInfo
+ = getDerived().TransformType(E->getTypeOperandSourceInfo());
+ if (!TInfo)
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getTypeOperand())
+ TInfo == E->getTypeOperandSourceInfo())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
- /*FIXME:*/E->getLocStart(),
- T,
+ return getDerived().RebuildCXXTypeidExpr(E->getType(),
+ E->getLocStart(),
+ TInfo,
E->getLocEnd());
}
@@ -4627,8 +5047,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
SubExpr.get() == E->getExprOperand())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
- /*FIXME:*/E->getLocStart(),
+ return getDerived().RebuildCXXTypeidExpr(E->getType(),
+ E->getLocStart(),
move(SubExpr),
E->getLocEnd());
}
@@ -4997,6 +5417,17 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
SS.setScopeRep(Qualifier);
SS.setRange(Old->getQualifierRange());
+ }
+
+ if (Old->getNamingClass()) {
+ CXXRecordDecl *NamingClass
+ = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ Old->getNameLoc(),
+ Old->getNamingClass()));
+ if (!NamingClass)
+ return SemaRef.ExprError();
+
+ R.setNamingClass(NamingClass);
}
// If we have no template arguments, it's a normal declaration name.
@@ -5423,6 +5854,18 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
R.resolveKind();
+ // Determine the naming class.
+ if (!Old->getNamingClass()) {
+ CXXRecordDecl *NamingClass
+ = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl(
+ Old->getMemberLoc(),
+ Old->getNamingClass()));
+ if (!NamingClass)
+ return SemaRef.ExprError();
+
+ R.setNamingClass(NamingClass);
+ }
+
TemplateArgumentListInfo TransArgs;
if (Old->hasExplicitTemplateArgs()) {
TransArgs.setLAngleLoc(Old->getLAngleLoc());
@@ -5463,27 +5906,76 @@ TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
- // FIXME: poor source location
- TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName());
- QualType EncodedType = getDerived().TransformType(E->getEncodedType());
- if (EncodedType.isNull())
+ TypeSourceInfo *EncodedTypeInfo
+ = getDerived().TransformType(E->getEncodedTypeSourceInfo());
+ if (!EncodedTypeInfo)
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- EncodedType == E->getEncodedType())
+ EncodedTypeInfo == E->getEncodedTypeSourceInfo())
return SemaRef.Owned(E->Retain());
return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(),
- EncodedType,
+ EncodedTypeInfo,
E->getRParenLoc());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform arguments.
+ bool ArgChanged = false;
+ ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef);
+ for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
+ OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I));
+ if (Arg.isInvalid())
+ return SemaRef.ExprError();
+
+ ArgChanged = ArgChanged || Arg.get() != E->getArg(I);
+ Args.push_back(Arg.takeAs<Expr>());
+ }
+
+ if (E->getReceiverKind() == ObjCMessageExpr::Class) {
+ // Class message: transform the receiver type.
+ TypeSourceInfo *ReceiverTypeInfo
+ = getDerived().TransformType(E->getClassReceiverTypeInfo());
+ if (!ReceiverTypeInfo)
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing message send.
+ if (!getDerived().AlwaysRebuild() &&
+ ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new class message send.
+ return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo,
+ E->getSelector(),
+ E->getMethodDecl(),
+ E->getLeftLoc(),
+ move_arg(Args),
+ E->getRightLoc());
+ }
+
+ // Instance message: transform the receiver
+ assert(E->getReceiverKind() == ObjCMessageExpr::Instance &&
+ "Only class and instance messages may be instantiated");
+ OwningExprResult Receiver
+ = getDerived().TransformExpr(E->getInstanceReceiver());
+ if (Receiver.isInvalid())
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing message send.
+ if (!getDerived().AlwaysRebuild() &&
+ Receiver.get() == E->getInstanceReceiver() && !ArgChanged)
+ return SemaRef.Owned(E->Retain());
+
+ // Build a new instance message send.
+ return getDerived().RebuildObjCMessageExpr(move(Receiver),
+ E->getSelector(),
+ E->getMethodDecl(),
+ E->getLeftLoc(),
+ move_arg(Args),
+ E->getRightLoc());
}
template<typename Derived>
@@ -5495,64 +5987,100 @@ TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
- ObjCProtocolDecl *Protocol
- = cast_or_null<ObjCProtocolDecl>(
- getDerived().TransformDecl(E->getLocStart(),
- E->getProtocol()));
- if (!Protocol)
- return SemaRef.ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- Protocol == E->getProtocol())
- return SemaRef.Owned(E->Retain());
-
- return getDerived().RebuildObjCProtocolExpr(Protocol,
- E->getAtLoc(),
- /*FIXME:*/E->getAtLoc(),
- /*FIXME:*/E->getAtLoc(),
- E->getRParenLoc());
-
+ return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the ivar; it will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCIvarRefExpr(move(Base), E->getDecl(),
+ E->getLocation(),
+ E->isArrow(), E->isFreeIvar());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the property; it will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCPropertyRefExpr(move(Base), E->getProperty(),
+ E->getLocation());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr(
ObjCImplicitSetterGetterRefExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // If this implicit setter/getter refers to class methods, it cannot have any
+ // dependent parts. Just retain the existing declaration.
+ if (E->getInterfaceDecl())
+ return SemaRef.Owned(E->Retain());
+
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // We don't need to transform the getters/setters; they will never change.
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCImplicitSetterGetterRefExpr(
+ E->getGetterMethod(),
+ E->getType(),
+ E->getSetterMethod(),
+ E->getLocation(),
+ move(Base));
+
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
+ // Can never occur in a dependent context.
return SemaRef.Owned(E->Retain());
}
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
- // FIXME: Implement this!
- assert(false && "Cannot transform Objective-C expressions yet");
- return SemaRef.Owned(E->Retain());
+ // Transform the base expression.
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ // If nothing changed, just retain the existing expression.
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildObjCIsaExpr(move(Base), E->getIsaMemberLoc(),
+ E->isArrow());
}
template<typename Derived>
@@ -5632,14 +6160,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
template<typename Derived>
QualType
-TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType,
- SourceLocation Sigil) {
- return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil,
- getDerived().getBaseEntity());
-}
-
-template<typename Derived>
-QualType
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt *Size,
@@ -5767,6 +6287,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) {
assert(D && "no decl found");
if (D->isInvalidDecl()) return QualType();
+ // FIXME: Doesn't account for ObjCInterfaceDecl!
TypeDecl *Ty;
if (isa<UsingDecl>(D)) {
UsingDecl *Using = cast<UsingDecl>(D);
diff --git a/test/ASTMerge/category.m b/test/ASTMerge/category.m
index bf0d11b61292..6ba229204147 100644
--- a/test/ASTMerge/category.m
+++ b/test/ASTMerge/category.m
@@ -6,4 +6,4 @@
// CHECK: category1.m:16:1: note: instance method 'method2' also declared here
// CHECK: category2.m:26:1: error: instance method 'method3' has incompatible result types in different translation units ('float' vs. 'int')
// CHECK: category1.m:24:1: note: instance method 'method3' also declared here
-// CHECK: 4 diagnostics generated.
+// CHECK: 2 errors generated.
diff --git a/test/ASTMerge/enum.c b/test/ASTMerge/enum.c
index 9b78fd1022e4..4380d192f1bd 100644
--- a/test/ASTMerge/enum.c
+++ b/test/ASTMerge/enum.c
@@ -22,4 +22,4 @@
// 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
+// CHECK: 4 warnings and 4 errors generated
diff --git a/test/ASTMerge/function.c b/test/ASTMerge/function.c
index 581b6ec5882c..f97eceed9866 100644
--- a/test/ASTMerge/function.c
+++ b/test/ASTMerge/function.c
@@ -6,4 +6,4 @@
// 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
+// CHECK: 2 errors generated
diff --git a/test/ASTMerge/interface.m b/test/ASTMerge/interface.m
index 47e4e052692b..420ae3882548 100644
--- a/test/ASTMerge/interface.m
+++ b/test/ASTMerge/interface.m
@@ -15,5 +15,5 @@
// CHECK: interface1.m:46:1: note: class method 'bar:' also declared here
// CHECK: interface2.m:57:20: error: instance method 'bar:' has a parameter with a different types in different translation units ('double' vs. 'float')
// CHECK: interface1.m:58:19: note: declared here with type 'float'
-// CHECK: 13 diagnostics generated
+// CHECK: 6 errors generated
diff --git a/test/ASTMerge/property.m b/test/ASTMerge/property.m
index 0fd7e4872d72..5f7a7308da65 100644
--- a/test/ASTMerge/property.m
+++ b/test/ASTMerge/property.m
@@ -6,4 +6,4 @@
// CHECK: property1.m:10:28: note: declared here with type 'float'
// CHECK: property2.m:12:26: error: instance method 'Prop1' has incompatible result types in different translation units ('int' vs. 'float')
// CHECK: property1.m:10:28: note: instance method 'Prop1' also declared here
-// CHECK: 4 diagnostics generated.
+// CHECK: 2 errors generated.
diff --git a/test/ASTMerge/struct.c b/test/ASTMerge/struct.c
index e72b93b249f9..7217222ae5c1 100644
--- a/test/ASTMerge/struct.c
+++ b/test/ASTMerge/struct.c
@@ -39,4 +39,4 @@
// 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
+// CHECK: 8 warnings and 7 errors generated
diff --git a/test/ASTMerge/typedef.c b/test/ASTMerge/typedef.c
index 4498864b4908..6f911295b96c 100644
--- a/test/ASTMerge/typedef.c
+++ b/test/ASTMerge/typedef.c
@@ -4,4 +4,4 @@
// 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
+// CHECK: 1 error
diff --git a/test/ASTMerge/var.c b/test/ASTMerge/var.c
index fd307940aff7..7f23b9f5d26d 100644
--- a/test/ASTMerge/var.c
+++ b/test/ASTMerge/var.c
@@ -9,4 +9,4 @@
// 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
+// CHECK: 3 errors
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index 952de737f75b..acaf74ded996 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s
-
+// RUN: false
+// XFAIL: *
int f1() {
int y = 1;
y++;
diff --git a/test/Analysis/inline2.c b/test/Analysis/inline2.c
index e2758c160a89..ec965a69c644 100644
--- a/test/Analysis/inline2.c
+++ b/test/Analysis/inline2.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s
+// RUN: false
+// XFAIL: *
// Test parameter 'a' is registered to LiveVariables analysis data although it
// is not referenced in the function body.
diff --git a/test/Analysis/inline3.c b/test/Analysis/inline3.c
index 3661263b6bae..8f45858bb949 100644
--- a/test/Analysis/inline3.c
+++ b/test/Analysis/inline3.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f2 -verify %s
-
+// RUN: false
+// XFAIL: *
// Test when entering f1(), we set the right AnalysisContext to Environment.
// Otherwise, block-level expr '1 && a' would not be block-level.
diff --git a/test/Analysis/inline4.c b/test/Analysis/inline4.c
index dd2379f04381..b2b3c346e374 100644
--- a/test/Analysis/inline4.c
+++ b/test/Analysis/inline4.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -inline-call -analyzer-store region -analyze-function f -verify %s
-
+// RUN: false
+// XFAIL: *
int g(int a) {
return a;
}
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
new file mode 100644
index 000000000000..dd891596c5dc
--- /dev/null
+++ b/test/Analysis/method-call.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s
+struct A {
+ int x;
+ A(int a) { x = a; }
+ int getx() { return x; }
+};
+
+void f1() {
+ A x(3);
+ if (x.getx() == 3) {
+ int *p = 0;
+ *p = 3; // expected-warning{{Dereference of null pointer}}
+ } else {
+ int *p = 0;
+ *p = 3; // no-warning
+ }
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index d10b9fa5ded7..42551417a2a5 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -955,3 +955,62 @@ void pr6288_b(void) {
*(px[0]) = 0; // no-warning
}
+// <rdar://problem/7817800> - A bug in RemoveDeadBindings was causing instance variable bindings
+// to get prematurely pruned from the state.
+@interface Rdar7817800 {
+ char *x;
+}
+- (void) rdar7817800_baz;
+@end
+
+char *rdar7817800_foobar();
+void rdar7817800_qux(void*);
+
+@implementation Rdar7817800
+- (void) rdar7817800_baz {
+ if (x)
+ rdar7817800_qux(x);
+ x = rdar7817800_foobar();
+ // Previously this triggered a bogus null dereference warning.
+ x[1] = 'a'; // no-warning
+}
+@end
+
+// PR 6036 - This test case triggered a crash inside StoreManager::CastRegion because the size
+// of 'unsigned long (*)[0]' is 0.
+struct pr6036_a { int pr6036_b; };
+struct pr6036_c;
+void u132monitk (struct pr6036_c *pr6036_d) {
+ (void) ((struct pr6036_a *) (unsigned long (*)[0]) ((char *) pr6036_d - 1))->pr6036_b; // expected-warning{{Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption}}
+}
+
+// <rdar://problem/7813989> - ?-expressions used as a base of a member expression should be treated as an lvalue
+typedef struct rdar7813989_NestedVal { int w; } rdar7813989_NestedVal;
+typedef struct rdar7813989_Val { rdar7813989_NestedVal nv; } rdar7813989_Val;
+
+int rdar7813989(int x, rdar7813989_Val *a, rdar7813989_Val *b) {
+ // This previously crashed with an assertion failure.
+ int z = (x ? a->nv : b->nv).w;
+ return z + 1;
+}
+
+// PR 6844 - Don't crash on vaarg expression.
+typedef __builtin_va_list va_list;
+void map(int srcID, ...) {
+ va_list ap;
+ int i;
+ for (i = 0; i < srcID; i++) {
+ int v = __builtin_va_arg(ap, int);
+ }
+}
+
+// PR 6854 - crash when casting symbolic memory address to a float
+// Handle casting from a symbolic region to a 'float'. This isn't
+// really all that intelligent, but previously this caused a crash
+// in SimpleSValuator.
+void pr6854(void * arg) {
+ void * a = arg;
+ *(void**)a = arg;
+ float f = *(float*) a;
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index fa05f6f60308..2b21eec18cd7 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -933,3 +933,27 @@ void foo_rev95547_b(struct s_rev95547 w) {
struct s_rev95547 w2 = w;
w2.z1.x += 20.0; // no-warning
}
+
+//===----------------------------------------------------------------------===//
+// Test handling statement expressions that don't populate a CFG block that
+// is used to represent the computation of the RHS of a logical operator.
+// This previously triggered a crash.
+//===----------------------------------------------------------------------===//
+
+void pr6938() {
+ if (1 && ({
+ while (0);
+ 0;
+ }) == 0) {
+ }
+}
+
+void pr6938_b() {
+ if (1 && *({ // expected-warning{{Dereference of null pointer}}
+ while (0) {}
+ ({
+ (int *) 0;
+ });
+ }) == 0) {
+ }
+}
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
new file mode 100644
index 000000000000..f26eecd4b196
--- /dev/null
+++ b/test/Analysis/new.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store region -verify %s
+
+void f1() {
+ int *n = new int;
+ if (*n) { // expected-warning {{Branch condition evaluates to a garbage value}}
+ }
+}
+
+void f2() {
+ int *n = new int(3);
+ if (*n) { // 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 5722a04aa2dd..5f5187194dab 100644
--- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
+++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m
@@ -72,11 +72,11 @@ int handleVoidInComma() {
int marker(void) { // control reaches end of non-void function
}
+// CHECK-darwin8: control reaches end of non-void function
// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage
// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage
-// CHECK-darwin8: control reaches end of non-void function
-// CHECK-darwin8: 5 diagnostics generated
+// CHECK-darwin8: 5 warnings generated
// CHECK-darwin9: control reaches end of non-void function
-// CHECK-darwin9: 1 diagnostic generated
+// CHECK-darwin9: 1 warning generated
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 5376ca0eb356..5a1049c7d71e 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -62,8 +62,8 @@ int f4(int *p) {
int f4_b() {
short array[2];
- uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion initializing}}
- short *p = x; // expected-warning{{incompatible integer to pointer conversion initializing}}
+ uintptr_t x = array; // expected-warning{{incompatible pointer to integer conversion}}
+ short *p = x; // expected-warning{{incompatible integer to pointer conversion}}
// The following branch should be infeasible.
if (!(p = &array[0])) {
diff --git a/test/Analysis/override-werror.c b/test/Analysis/override-werror.c
index 522b9dcb94e7..f4854bb819ad 100644
--- a/test/Analysis/override-werror.c
+++ b/test/Analysis/override-werror.c
@@ -6,7 +6,7 @@
// analyzer results.
char* f(int *p) {
- return p; // expected-warning{{incompatible pointer types returning 'int *', expected 'char *'}}
+ return p; // expected-warning{{incompatible pointer types}}
}
void g(int *p) {
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index 777ad197987d..9d036ac7b5c6 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,11 +1,24 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=region
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem %s -analyzer-store=region -fblocks -verify
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic -fblocks -verify
+
+struct _opaque_pthread_once_t {
+ long __sig;
+ char __opaque[8];
+};
+typedef struct _opaque_pthread_once_t __darwin_pthread_once_t;
+typedef __darwin_pthread_once_t pthread_once_t;
+int pthread_once(pthread_once_t *, void (*)(void));
+
+typedef void (^dispatch_block_t)(void);
+typedef long dispatch_once_t;
+void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
#ifndef O_CREAT
#define O_CREAT 0x0200
#define O_RDONLY 0x0000
#endif
int open(const char *, int, ...);
+int close(int fildes);
void test_open(const char *path) {
int fd;
@@ -17,3 +30,23 @@ void test_open(const char *path) {
if (!fd)
close(fd);
}
+
+void test_dispatch_once() {
+ dispatch_once_t pred = 0;
+ do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // expected-warning{{Call to 'dispatch_once' uses the local variable 'pred' for the predicate value}}
+}
+void test_dispatch_once_neg() {
+ static dispatch_once_t pred = 0;
+ do { if (__builtin_expect(*(&pred), ~0l) != ~0l) dispatch_once((&pred), (^() {})); } while (0); // no-warning
+}
+
+void test_pthread_once_aux();
+
+void test_pthread_once() {
+ pthread_once_t pred = {0x30B1BCBA, {0}};
+ pthread_once(&pred, test_pthread_once_aux); // expected-warning{{Call to 'pthread_once' uses the local variable 'pred' for the "control" value}}
+}
+void test_pthread_once_neg() {
+ static pthread_once_t pred = {0x30B1BCBA, {0}};
+ pthread_once(&pred, test_pthread_once_aux); // no-warning
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
index ee01416c7b1b..0e262f3eb1d6 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
@@ -71,3 +71,18 @@ namespace O {
}
}
+extern "C" {
+ struct L { };
+}
+
+void h(L); // expected-note{{candidate function}}
+
+namespace P {
+ void h(L); // expected-note{{candidate function}}
+ void test_transparent_context_adl(L l) {
+ {
+ h(l); // expected-error {{call to 'h' is ambiguous}}
+ }
+ }
+}
+
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
new file mode 100644
index 000000000000..004d1e491f17
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test0 {
+ struct A {
+ static int foo;
+ };
+
+ namespace i0 {
+ typedef int A; // expected-note {{declared here}}
+
+ int test() {
+ struct A a; // expected-error {{elaborated type refers to a typedef}}
+ return a.foo;
+ }
+ }
+
+ namespace i1 {
+ template <class> class A; // expected-note {{declared here}}
+
+ int test() {
+ struct A a; // expected-error {{elaborated type refers to a template}}
+ return a.foo;
+ }
+ }
+
+ namespace i2 {
+ int A;
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+
+ namespace i3 {
+ void A();
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+
+ namespace i4 {
+ template <class T> void A();
+
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+ }
+
+ // This should magically be okay; see comment in SemaDecl.cpp.
+ // rdar://problem/7898108
+ typedef struct A A;
+ int test() {
+ struct A a;
+ return a.foo;
+ }
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
index f9bac40c9ddb..30393961b3f3 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
@@ -36,7 +36,7 @@ namespace Numbers {
double d;
};
Number zero(0.0f);
- void g(Number);
+ void g(Number); // expected-note 2{{passing argument to parameter here}}
}
void test2() {
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
index e57954609907..d2afd5d83fdc 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
@@ -32,6 +32,6 @@ namespace test1 {
// Test that we don't find the injected class name when parsing base
// specifiers.
namespace test2 {
- template <class T> struct bar {}; // expected-note {{template parameter is declared here}}
- template <class T> struct foo : bar<foo> {}; // expected-error {{template argument for template type parameter must be a type}}
+ template <class T> struct bar {};
+ template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template foo requires template arguments}} expected-note {{template is declared here}}
}
diff --git a/test/CXX/class.access/class.access.base/p1.cpp b/test/CXX/class.access/class.access.base/p1.cpp
index 1bbcedb9a1e7..09884316f9cd 100644
--- a/test/CXX/class.access/class.access.base/p1.cpp
+++ b/test/CXX/class.access/class.access.base/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++0x [class.access.base]p1(a):
// If a class is declared to be a base class for another class using
diff --git a/test/CXX/class.access/class.access.base/p5.cpp b/test/CXX/class.access/class.access.base/p5.cpp
index 96037e7de2b0..938d9fbe9bf8 100644
--- a/test/CXX/class.access/class.access.base/p5.cpp
+++ b/test/CXX/class.access/class.access.base/p5.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faccess-control -verify %s
+// RUN: %clang_cc1 -verify %s
namespace test0 {
struct A {
diff --git a/test/CXX/class.access/class.access.nest/p1.cpp b/test/CXX/class.access/class.access.nest/p1.cpp
index d2644c6ef476..eceffcf991bb 100644
--- a/test/CXX/class.access/class.access.nest/p1.cpp
+++ b/test/CXX/class.access/class.access.nest/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// Derived from GNU's std::string
namespace test0 {
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 22266cd8f8fc..991698d5dcca 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++'0x [class.friend] p1:
// A friend of a class is a function or class that is given permission to use
@@ -192,3 +192,98 @@ namespace test4 {
return a == b; // expected-note {{requested here}}
}
}
+
+
+// PR6174
+namespace test5 {
+ namespace ns {
+ class A;
+ }
+
+ class ns::A {
+ private: int x;
+ friend class B;
+ };
+
+ namespace ns {
+ class B {
+ int test(A *p) { return p->x; }
+ };
+ }
+}
+
+// PR6207
+namespace test6 {
+ struct A {};
+
+ struct B {
+ friend A::A();
+ friend A::~A();
+ friend A &A::operator=(const A&);
+ };
+}
+
+namespace test7 {
+ template <class T> struct X {
+ X();
+ ~X();
+ void foo();
+ void bar();
+ };
+
+ class A {
+ friend void X<int>::foo();
+ friend X<int>::X();
+ friend X<int>::X(const X&);
+
+ private:
+ A(); // expected-note 2 {{declared private here}}
+ };
+
+ template<> void X<int>::foo() {
+ A a;
+ }
+
+ template<> void X<int>::bar() {
+ A a; // expected-error {{calling a private constructor}}
+ }
+
+ template<> X<int>::X() {
+ A a;
+ }
+
+ template<> X<int>::~X() {
+ A a; // expected-error {{calling a private constructor}}
+ }
+}
+
+// Return types, parameters and default arguments to friend functions.
+namespace test8 {
+ class A {
+ typedef int I; // expected-note 4 {{declared private here}}
+ static const I x = 0;
+ friend I f(I i);
+ template<typename T> friend I g(I i);
+ };
+
+ // FIXME: This should be on line 264.
+ const A::I A::x; // expected-note {{declared private here}}
+ A::I f(A::I i = A::x) {}
+ template<typename T> A::I g(A::I i) {
+ T t;
+ }
+ template A::I g<A::I>(A::I i);
+
+ A::I f2(A::I i = A::x) {} // expected-error 3 {{is a private member of}}
+ template<typename T> A::I g2(A::I i) { // expected-error 2 {{is a private member of}}
+ T t;
+ }
+ template A::I g2<A::I>(A::I i);
+}
+
+// PR6885
+namespace test9 {
+ class B {
+ friend class test9;
+ };
+}
diff --git a/test/CXX/class.access/class.friend/p2-cxx03.cpp b/test/CXX/class.access/class.friend/p2-cxx03.cpp
new file mode 100644
index 000000000000..0391c4b989d2
--- /dev/null
+++ b/test/CXX/class.access/class.friend/p2-cxx03.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<typename T>
+class X0 {
+ friend T; // expected-warning{{non-class type 'T' cannot be a friend}}
+};
+
+class X1 { };
+enum E1 { };
+X0<X1> x0a;
+X0<X1 *> x0b;
+X0<int> x0c;
+X0<E1> x0d;
+
diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
new file mode 100644
index 000000000000..4f55e5339ab2
--- /dev/null
+++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+template<typename T>
+class X0 {
+ friend T;
+};
+
+class Y1 { };
+enum E1 { };
+X0<Y1> x0a;
+X0<Y1 *> x0b;
+X0<int> x0c;
+X0<E1> x0d;
+
+template<typename T>
+class X1 {
+ friend typename T::type; // expected-error{{no type named 'type' in 'Y1'}}
+};
+
+struct Y2 {
+ struct type { };
+};
+
+struct Y3 {
+ typedef int type;
+};
+
+X1<Y2> x1a;
+X1<Y3> x1b;
+X1<Y1> x1c; // expected-note{{in instantiation of template class 'X1<Y1>' requested here}}
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
new file mode 100644
index 000000000000..6ff630c99697
--- /dev/null
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -0,0 +1,387 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test0 {
+ class A {
+ protected: int x; // expected-note 3 {{declared}}
+ static int sx; // expected-note 3 {{declared}}
+ };
+ class B : public A {
+ };
+ class C : protected A { // expected-note {{declared}}
+ };
+ class D : private B { // expected-note 3 {{constrained}}
+ };
+
+ void test(A &a) {
+ (void) a.x; // expected-error {{'x' is a protected member}}
+ (void) a.sx; // expected-error {{'sx' is a protected member}}
+ }
+ void test(B &b) {
+ (void) b.x; // expected-error {{'x' is a protected member}}
+ (void) b.sx; // expected-error {{'sx' is a protected member}}
+ }
+ void test(C &c) {
+ (void) c.x; // expected-error {{'x' is a protected member}} expected-error {{protected base class}}
+ (void) c.sx; // expected-error {{'sx' is a protected member}}
+ }
+ void test(D &d) {
+ (void) d.x; // expected-error {{'x' is a private member}} expected-error {{private base class}}
+ (void) d.sx; // expected-error {{'sx' is a private member}}
+ }
+}
+
+namespace test1 {
+ class A {
+ protected: int x;
+ static int sx;
+ static void test(A&);
+ };
+ class B : public A {
+ static void test(B&);
+ };
+ class C : protected A {
+ static void test(C&);
+ };
+ class D : private B {
+ static void test(D&);
+ };
+
+ void A::test(A &a) {
+ (void) a.x;
+ (void) a.sx;
+ }
+ void B::test(B &b) {
+ (void) b.x;
+ (void) b.sx;
+ }
+ void C::test(C &c) {
+ (void) c.x;
+ (void) c.sx;
+ }
+ void D::test(D &d) {
+ (void) d.x;
+ (void) d.sx;
+ }
+}
+
+namespace test2 {
+ class A {
+ protected: int x; // expected-note 3 {{declared}}
+ static int sx;
+ static void test(A&);
+ };
+ class B : public A {
+ static void test(A&);
+ };
+ class C : protected A {
+ static void test(A&);
+ };
+ class D : private B {
+ static void test(A&);
+ };
+
+ void A::test(A &a) {
+ (void) a.x;
+ (void) a.sx;
+ }
+ void B::test(A &a) {
+ (void) a.x; // expected-error {{'x' is a protected member}}
+ (void) a.sx;
+ }
+ void C::test(A &a) {
+ (void) a.x; // expected-error {{'x' is a protected member}}
+ (void) a.sx;
+ }
+ void D::test(A &a) {
+ (void) a.x; // expected-error {{'x' is a protected member}}
+ (void) a.sx;
+ }
+}
+
+namespace test3 {
+ class B;
+ class A {
+ protected: int x; // expected-note {{declared}}
+ static int sx;
+ static void test(B&);
+ };
+ class B : public A {
+ static void test(B&);
+ };
+ class C : protected A {
+ static void test(B&);
+ };
+ class D : private B {
+ static void test(B&);
+ };
+
+ void A::test(B &b) {
+ (void) b.x;
+ (void) b.sx;
+ }
+ void B::test(B &b) {
+ (void) b.x;
+ (void) b.sx;
+ }
+ void C::test(B &b) {
+ (void) b.x; // expected-error {{'x' is a protected member}}
+ (void) b.sx;
+ }
+ void D::test(B &b) {
+ (void) b.x;
+ (void) b.sx;
+ }
+}
+
+namespace test4 {
+ class C;
+ class A {
+ protected: int x; // expected-note 2 {{declared}}
+ static int sx;
+ static void test(C&);
+ };
+ class B : public A {
+ static void test(C&);
+ };
+ class C : protected A { // expected-note 4 {{constrained}} expected-note 3 {{declared}}
+ static void test(C&);
+ };
+ class D : private B {
+ static void test(C&);
+ };
+
+ void A::test(C &c) {
+ (void) c.x; // expected-error {{'x' is a protected member}} \
+ // expected-error {{protected base class}}
+ (void) c.sx; // expected-error {{'sx' is a protected member}}
+ }
+ void B::test(C &c) {
+ (void) c.x; // expected-error {{'x' is a protected member}} \
+ // expected-error {{protected base class}}
+ (void) c.sx; // expected-error {{'sx' is a protected member}}
+ }
+ void C::test(C &c) {
+ (void) c.x;
+ (void) c.sx;
+ }
+ void D::test(C &c) {
+ (void) c.x; // expected-error {{'x' is a protected member}} \
+ // expected-error {{protected base class}}
+ (void) c.sx; // expected-error {{'sx' is a protected member}}
+ }
+}
+
+namespace test5 {
+ class D;
+ class A {
+ protected: int x;
+ static int sx;
+ static void test(D&);
+ };
+ class B : public A {
+ static void test(D&);
+ };
+ class C : protected A {
+ static void test(D&);
+ };
+ class D : private B { // expected-note 9 {{constrained}}
+ static void test(D&);
+ };
+
+ void A::test(D &d) {
+ (void) d.x; // expected-error {{'x' is a private member}} \
+ // expected-error {{cannot cast}}
+ (void) d.sx; // expected-error {{'sx' is a private member}}
+ }
+ void B::test(D &d) {
+ (void) d.x; // expected-error {{'x' is a private member}} \
+ // expected-error {{cannot cast}}
+ (void) d.sx; // expected-error {{'sx' is a private member}}
+ }
+ void C::test(D &d) {
+ (void) d.x; // expected-error {{'x' is a private member}} \
+ // expected-error {{cannot cast}}
+ (void) d.sx; // expected-error {{'sx' is a private member}}
+ }
+ void D::test(D &d) {
+ (void) d.x;
+ (void) d.sx;
+ }
+}
+
+namespace test6 {
+ class Static {};
+ class A {
+ protected:
+ void foo(int); // expected-note 3 {{declared}}
+ void foo(long);
+ static void foo(Static);
+
+ static void test(A&);
+ };
+ class B : public A {
+ static void test(A&);
+ };
+ class C : protected A {
+ static void test(A&);
+ };
+ class D : private B {
+ static void test(A&);
+ };
+
+ void A::test(A &a) {
+ a.foo(10);
+ a.foo(Static());
+ }
+ void B::test(A &a) {
+ a.foo(10); // expected-error {{'foo' is a protected member}}
+ a.foo(Static());
+ }
+ void C::test(A &a) {
+ a.foo(10); // expected-error {{'foo' is a protected member}}
+ a.foo(Static());
+ }
+ void D::test(A &a) {
+ a.foo(10); // expected-error {{'foo' is a protected member}}
+ a.foo(Static());
+ }
+}
+
+namespace test7 {
+ class Static {};
+ class A {
+ protected:
+ void foo(int); // expected-note 3 {{declared}}
+ void foo(long);
+ static void foo(Static);
+
+ static void test();
+ };
+ class B : public A {
+ static void test();
+ };
+ class C : protected A {
+ static void test();
+ };
+ class D : private B {
+ static void test();
+ };
+
+ void A::test() {
+ void (A::*x)(int) = &A::foo;
+ void (*sx)(Static) = &A::foo;
+ }
+ void B::test() {
+ void (A::*x)(int) = &A::foo; // expected-error {{'foo' is a protected member}}
+ void (*sx)(Static) = &A::foo;
+ }
+ void C::test() {
+ void (A::*x)(int) = &A::foo; // expected-error {{'foo' is a protected member}}
+ void (*sx)(Static) = &A::foo;
+ }
+ void D::test() {
+ void (A::*x)(int) = &A::foo; // expected-error {{'foo' is a protected member}}
+ void (*sx)(Static) = &A::foo;
+ }
+}
+
+namespace test8 {
+ class Static {};
+ class A {
+ protected:
+ void foo(int); // expected-note 3 {{declared}}
+ void foo(long);
+ static void foo(Static);
+
+ static void test();
+ };
+ class B : public A {
+ static void test();
+ };
+ class C : protected A {
+ static void test();
+ };
+ class D : private B {
+ static void test();
+ };
+ void call(void (A::*)(int));
+ void calls(void (*)(Static));
+
+ void A::test() {
+ call(&A::foo);
+ calls(&A::foo);
+ }
+ void B::test() {
+ call(&A::foo); // expected-error {{'foo' is a protected member}}
+ calls(&A::foo);
+ }
+ void C::test() {
+ call(&A::foo); // expected-error {{'foo' is a protected member}}
+ calls(&A::foo);
+ }
+ void D::test() {
+ call(&A::foo); // expected-error {{'foo' is a protected member}}
+ calls(&A::foo);
+ }
+}
+
+namespace test9 {
+ class A {
+ protected: int foo(); // expected-note 8 {{declared}}
+ };
+
+ class B : public A {
+ friend class D;
+ };
+
+ class C : protected B { // expected-note {{declared}} \
+ // expected-note 6 {{constrained}}
+ };
+
+ class D : public A {
+ static void test(A &a) {
+ a.foo(); // expected-error {{'foo' is a protected member}}
+ a.A::foo(); // expected-error {{'foo' is a protected member}}
+ a.B::foo();
+ a.C::foo(); // expected-error {{'foo' is a protected member}}
+ }
+
+ static void test(B &b) {
+ b.foo();
+ b.A::foo(); // expected-error {{'foo' is a protected member}}
+ b.B::foo();
+ b.C::foo(); // expected-error {{'foo' is a protected member}}
+ }
+
+ static void test(C &c) {
+ c.foo(); // expected-error {{'foo' is a protected member}} \
+ // expected-error {{cannot cast}}
+ c.A::foo(); // expected-error {{'foo' is a protected member}} \
+ // expected-error {{'A' is a protected member}} \
+ // expected-error {{cannot cast}}
+ c.B::foo(); // expected-error {{'B' is a protected member}} \
+ // expected-error {{cannot cast}}
+ c.C::foo(); // expected-error {{'foo' is a protected member}} \
+ // expected-error {{cannot cast}}
+ }
+
+ static void test(D &d) {
+ d.foo();
+ d.A::foo();
+ d.B::foo();
+ d.C::foo(); // expected-error {{'foo' is a protected member}}
+ }
+ };
+}
+
+namespace test10 {
+ template<typename T> class A {
+ protected:
+ int foo();
+ int foo() const;
+
+ ~A() { foo(); }
+ };
+
+ template class A<int>;
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 3bbdbab8d516..1cd896613679 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++0x [class.access]p4:
@@ -88,13 +88,24 @@ namespace test1 {
namespace test2 {
class A {
private:
- A(); // expected-note {{declared private here}}
+ A(); // expected-note 3 {{declared private here}}
static A foo;
};
A a; // expected-error {{calling a private constructor}}
A A::foo; // okay
+
+ class B : A { }; // expected-error {{base class 'test2::A' has private constructor}}
+ B b;
+
+ class C : virtual A {
+ public:
+ C();
+ };
+
+ class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private constructor}}
+ D d;
}
// Implicit destructor calls.
@@ -191,13 +202,13 @@ namespace test5 {
void operator=(const A &); // expected-note 2 {{declared private here}}
};
- class Test1 { A a; }; // expected-error {{field of type 'test5::A' has private copy assignment operator}}
+ class Test1 { A a; }; // expected-error {{private member}}
void test1() {
Test1 a;
a = Test1();
}
- class Test2 : A {}; // expected-error {{base class 'test5::A' has private copy assignment operator}}
+ class Test2 : A {}; // expected-error {{private member}}
void test2() {
Test2 a;
a = Test2();
@@ -327,3 +338,83 @@ namespace test13 {
(void) d->x;
}
}
+
+// Destructors for temporaries.
+namespace test14 {
+ class A {
+ private: ~A(); // expected-note {{declared private here}}
+ };
+ A foo();
+
+ void test() {
+ foo(); // expected-error {{temporary of type 'test14::A' has private destructor}}
+ }
+
+ class X {
+ ~X(); // expected-note {{declared private here}}
+ };
+
+ struct Y1 {
+ operator X();
+ };
+
+ void g() {
+ const X &xr = Y1(); // expected-error{{temporary of type 'test14::X' has private destructor}}
+ }
+}
+
+// PR 7024
+namespace test15 {
+ template <class T> class A {
+ private:
+ int private_foo; // expected-note {{declared private here}}
+ static int private_sfoo; // expected-note {{declared private here}}
+ protected:
+ int protected_foo; // expected-note 4 {{declared protected here}}
+ static int protected_sfoo; // expected-note 3 {{declared protected here}}
+
+ int test1(A<int> &a) {
+ return a.private_foo; // expected-error {{private member}}
+ }
+
+ int test2(A<int> &a) {
+ return a.private_sfoo; // expected-error {{private member}}
+ }
+
+ int test3(A<int> &a) {
+ return a.protected_foo; // expected-error {{protected member}}
+ }
+
+ int test4(A<int> &a) {
+ return a.protected_sfoo; // expected-error {{protected member}}
+ }
+ };
+
+ template class A<int>;
+ template class A<long>; // expected-note 4 {{in instantiation}}
+
+ template <class T> class B : public A<T> {
+ // TODO: These first two accesses can be detected as ill-formed at
+ // definition time because they're member accesses and A<int> can't
+ // be a subclass of B<T> for any T.
+
+ int test1(A<int> &a) {
+ return a.protected_foo; // expected-error 2 {{protected member}}
+ }
+
+ int test2(A<int> &a) {
+ return a.protected_sfoo; // expected-error {{protected member}}
+ }
+
+ int test3(B<int> &b) {
+ return b.protected_foo; // expected-error {{protected member}}
+ }
+
+ int test4(B<int> &b) {
+ return b.protected_sfoo; // expected-error {{protected member}}
+ }
+ };
+
+ template class B<int>; // expected-note {{in instantiation}}
+ template class B<long>; // expected-note 4 {{in instantiation}}
+}
diff --git a/test/CXX/class.access/p6.cpp b/test/CXX/class.access/p6.cpp
index aaf510a6d11f..734a4d8c4869 100644
--- a/test/CXX/class.access/p6.cpp
+++ b/test/CXX/class.access/p6.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++0x [class.access]p6:
// All access controls in [class.access] affect the ability to
@@ -52,3 +52,70 @@ namespace test1 {
A apriv = priv; // expected-error {{private constructor}}
}
}
+
+// PR6967
+namespace test2 {
+ class A {
+ public:
+ template <class T> static void set(T &t, typename T::type v) {
+ t.value = v;
+ }
+ template <class T> static typename T::type get(const T &t) {
+ return t.value;
+ }
+ };
+
+ class B {
+ friend class A;
+
+ private:
+ typedef int type;
+ type value;
+ };
+
+ int test() {
+ B b;
+ A::set(b, 0);
+ return A::get(b);
+ }
+}
+
+namespace test3 {
+ class Green {}; class Blue {};
+
+ // We have to wrap this in a class because a partial specialization
+ // isn't actually in the context of the template.
+ struct Outer {
+ template <class T, class Nat> class A {
+ };
+ };
+
+ template <class T> class Outer::A<T, typename T::nature> {
+ public:
+ static void foo();
+ };
+
+ class B {
+ private: typedef Green nature;
+ friend class Outer;
+ };
+
+ void test() {
+ Outer::A<B, Green>::foo();
+ Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo'}}
+ }
+}
+
+namespace test4 {
+ template <class T> class A {
+ private: typedef int type;
+ template <class U> friend void foo(U &, typename U::type);
+ };
+
+ template <class U> void foo(U &, typename U::type) {}
+
+ void test() {
+ A<int> a;
+ foo(a, 0);
+ }
+}
diff --git a/test/CXX/class/class.friend/p2.cpp b/test/CXX/class/class.friend/p2.cpp
index 9fe2b17e5049..eb5036f81287 100644
--- a/test/CXX/class/class.friend/p2.cpp
+++ b/test/CXX/class/class.friend/p2.cpp
@@ -4,7 +4,7 @@ struct B0;
class A {
friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
- friend int; // expected-error {{friends can only be classes or functions}}
- friend B0; // expected-error {{must specify 'struct' to befriend}}
+ friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
+ friend B0; // expected-warning {{must specify 'struct' to befriend}}
friend class C; // okay
};
diff --git a/test/CXX/class/class.local/p2.cpp b/test/CXX/class/class.local/p2.cpp
index 2b1359c3d8d3..db4c90f564fe 100644
--- a/test/CXX/class/class.local/p2.cpp
+++ b/test/CXX/class/class.local/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -faccess-control
+// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A { };
diff --git a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
index f5fbf7a08c20..c81e4ef1b1b8 100644
--- a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
+++ b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp
@@ -50,7 +50,7 @@ namespace test1 {
}
namespace test2 {
- class Unrelated {
+ struct Unrelated {
void foo();
};
diff --git a/test/CXX/conv/conv.mem/p4.cpp b/test/CXX/conv/conv.mem/p4.cpp
index 42f6343e069e..e0748d892362 100644
--- a/test/CXX/conv/conv.mem/p4.cpp
+++ b/test/CXX/conv/conv.mem/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
struct Base {
int data;
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
index a5f314dac239..ddcbe785a739 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
@@ -53,4 +53,16 @@ struct Y {
friend union X1;
};
+namespace N {
+ namespace M {
+ template<typename T> class X;
+ }
+}
+
+namespace N3 {
+ class Y {
+ template<typename T> friend class N::M::X;
+ };
+}
+
// FIXME: Woefully inadequate for testing
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
index 89e9c897d225..bb1d67f51a6c 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// We have to avoid ADL for this test.
@@ -12,7 +12,8 @@ namespace Test0 {
test<1> foo(class foo);
namespace A {
- test<2> foo(class ::foo); // expected-note {{candidate}}
+ test<2> foo(class ::foo); // expected-note {{candidate}} \
+ // expected-note{{passing argument to parameter here}}
void test0() {
using ::foo;
@@ -38,7 +39,7 @@ namespace Test0 {
test<2> _1 = (foo)(a);
class Test0::foo b;
- test<2> _2 = (foo)(b); // expected-error {{no viable conversion from 'class Test0::foo' to 'class foo' is possible}}
+ test<2> _2 = (foo)(b); // expected-error {{no viable conversion from 'class Test0::foo' to 'class ::foo' is possible}}
}
}
}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
index 23da98ce7ee6..a43d9e019ed3 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
@@ -166,7 +166,7 @@ namespace test3 {
template <class T> struct C : A<T> {
using typename A<T>::type;
- using typename A<T>::hiding; // expected-note {{declared at}} \
+ using typename A<T>::hiding; // expected-note {{declared here}} \
// expected-error {{'typename' keyword used on a non-type}}
using typename A<T>::union_member; // expected-error {{'typename' keyword used on a non-type}}
using typename A<T>::enumerator; // expected-error {{'typename' keyword used on a non-type}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index c53031177323..b04e869a4860 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -13,7 +13,7 @@ class A1 {
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
- // expected-error {{enum types cannot be friends}}
+ // expected-warning {{cannot be a friend}}
};
template <class T> struct B { // expected-note {{previous use is here}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp
new file mode 100644
index 000000000000..5a342d423a2d
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// C++03 requires that we check for a copy constructor when binding a
+// reference to a reference-compatible rvalue, since we are allowed to
+// make a copy. C++0x does not permit the copy, so ensure that we
+// don't diagnose cases where the copy constructor is unavailable.
+
+struct X1 {
+ X1();
+ explicit X1(const X1&);
+};
+
+struct X2 {
+ X2();
+
+private:
+ X2(const X2&);
+};
+
+struct X3 {
+ X3();
+
+private:
+ X3(X3&);
+};
+
+template<typename T>
+T get_value_badly() {
+ double *dp = 0;
+ T *tp = dp;
+ return T();
+}
+
+template<typename T>
+struct X4 {
+ X4();
+ X4(const X4&, T = get_value_badly<T>());
+};
+
+void g1(const X1&);
+void g2(const X2&);
+void g3(const X3&);
+void g4(const X4<int>&);
+
+void test() {
+ g1(X1());
+ g2(X2());
+ g3(X3());
+ g4(X4<int>());
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
new file mode 100644
index 000000000000..16394110d054
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++03 requires that we check for a copy constructor when binding a
+// reference to a temporary, since we are allowed to make a copy, Even
+// though we don't actually make that copy, make sure that we diagnose
+// cases where that copy constructor is somehow unavailable.
+
+struct X1 {
+ X1();
+ explicit X1(const X1&);
+};
+
+struct X2 {
+ X2();
+
+private:
+ X2(const X2&); // expected-note{{declared private here}}
+};
+
+struct X3 {
+ X3();
+
+private:
+ X3(X3&); // expected-note{{candidate constructor not viable: no known conversion from 'X3' to 'X3 &' for 1st argument}}
+};
+
+// Check for instantiation of default arguments
+template<typename T>
+T get_value_badly() {
+ double *dp = 0;
+ T *tp = dp; // expected-error{{ cannot initialize a variable of type 'int *' with an lvalue of type 'double *'}}
+ return T();
+}
+
+template<typename T>
+struct X4 {
+ X4();
+ X4(const X4&, T = get_value_badly<T>()); // expected-note{{in instantiation of}}
+};
+
+// Check for "dangerous" default arguments that could cause recursion.
+struct X5 {
+ X5();
+ X5(const X5&, const X5& = X5()); // expected-error{{no viable constructor copying parameter of type 'X5'}}
+};
+
+void g1(const X1&);
+void g2(const X2&);
+void g3(const X3&);
+void g4(const X4<int>&);
+void g5(const X5&);
+
+void test() {
+ g1(X1()); // expected-error{{no viable constructor copying parameter of type 'X1'}}
+ g2(X2()); // expected-error{{calling a private constructor of class 'X2'}}
+ g3(X3()); // expected-error{{no viable constructor copying parameter of type 'X3'}}
+ g4(X4<int>());
+ g5(X5()); // expected-error{{no viable constructor copying parameter of type 'X5'}}
+}
+
+// Check for dangerous recursion in default arguments.
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
index d757adf6986c..9b3925969c45 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
@@ -17,11 +17,11 @@ struct B : A { } b;
// CHECK: example1
void example1() {
// CHECK: A &ra =
- // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase> lvalue
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)> lvalue
A &ra = b;
// CHECK: A const &rca =
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
- // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
const A& rca = b;
}
@@ -35,12 +35,12 @@ struct X {
void example2() {
// CHECK: A const &rca =
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
- // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
// CHECK: CallExpr{{.*}}B
const A &rca = f();
// CHECK: A const &r =
// CHECK: ImplicitCastExpr{{.*}}'struct A const' <NoOp>
- // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase>
+ // CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
const A& r = x;
}
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
index 4c7ee942bd52..51d61a52a678 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp
@@ -22,3 +22,19 @@ namespace PR6264 {
T bar = S();
}
}
+
+namespace PR6066 {
+ struct B { };
+ struct A : B {
+ operator B*();
+ operator B&(); // expected-warning{{conversion function converting 'PR6066::A' to its base class 'PR6066::B' will never be used}}
+ };
+
+ void f(B&); // no rvalues accepted
+ void f(B*);
+
+ int g() {
+ f(A()); // calls f(B*)
+ return 0;
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
index 7ee052c5f9cb..3100e56a080e 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
@@ -2,7 +2,8 @@
float global_f;
-void f0(int *ip = &global_f); // expected-error{{cannot initialize}}
+void f0(int *ip = &global_f); // expected-error{{cannot initialize}} \
+// expected-note{{passing argument to parameter 'ip' here}}
// Example from C++03 standard
int a = 1;
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
index 00234ac5fd16..9ab0b489a2c4 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class C {
+public:
void f(int i = 3); // expected-note{{here}}
void g(int i, int j = 99);
};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
index 17fd71291000..aaf745142401 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp
@@ -9,10 +9,10 @@
typedef int &intref;
typedef intref &intrefref;
-template <class T> class RefMem {
+template <class T> class RefMem { // expected-warning{{class 'RefMem<int &>' does not declare any constructor to initialize its non-modifiable members}}
T
&
- member;
+ member; // expected-note{{ reference member 'member' will never be initialized}}
};
struct RefRef {
@@ -34,7 +34,7 @@ struct RefRef {
int
&
>
- refref3; // collapses
+ refref3; // collapses expected-note{{in instantiation of template class 'RefMem<int &>' requested here}}
};
diff --git a/test/CXX/except/except.handle/p16.cpp b/test/CXX/except/except.handle/p16.cpp
index 87972f59856e..4950a2f6aab0 100644
--- a/test/CXX/except/except.handle/p16.cpp
+++ b/test/CXX/except/except.handle/p16.cpp
@@ -11,12 +11,12 @@ class X {
public:
X(const X<T> &) {
int *ip = 0;
- ptr = ip; // expected-error{{incompatible type assigning 'int *', expected 'float *'}}
+ ptr = ip; // expected-error{{assigning to 'float *' from incompatible type 'int *'}}
}
~X() {
float *fp = 0;
- ptr = fp; // expected-error{{incompatible type assigning 'float *', expected 'int *'}}
+ ptr = fp; // expected-error{{assigning to 'int *' from incompatible type 'float *'}}
}
};
diff --git a/test/CXX/expr/expr.unary/expr.delete/p5.cpp b/test/CXX/expr/expr.unary/expr.delete/p5.cpp
index 4b2b5ae7cbd5..2fa30e59dca5 100644
--- a/test/CXX/expr/expr.unary/expr.delete/p5.cpp
+++ b/test/CXX/expr/expr.unary/expr.delete/p5.cpp
@@ -11,7 +11,7 @@ class T0 { ~T0(); };
// The trivial case, inside a template instantiation.
template<typename T>
-class T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete type}}
+struct T1_A { T *x; ~T1_A() { delete x; } }; // expected-warning {{deleting pointer to incomplete type}}
class T1_B; // expected-note {{forward declaration}}
void f0() { T1_A<T1_B> x; } // expected-note {{in instantiation of member function}}
diff --git a/test/CXX/expr/expr.unary/expr.new/p19.cpp b/test/CXX/expr/expr.unary/expr.new/p19.cpp
index 6134779f1fd2..bb69fd55fd80 100644
--- a/test/CXX/expr/expr.unary/expr.new/p19.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p19.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions %s
typedef __SIZE_TYPE__ size_t;
// Operator delete template for placement new with global lookup
diff --git a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
index c188e1e25e04..4c924b137ccd 100644
--- a/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fexceptions %s
typedef __SIZE_TYPE__ size_t;
struct S {
diff --git a/test/CXX/expr/expr.unary/expr.new/p20.cpp b/test/CXX/expr/expr.unary/expr.new/p20.cpp
index 71e584e775c3..8cbe2b9be3be 100644
--- a/test/CXX/expr/expr.unary/expr.new/p20.cpp
+++ b/test/CXX/expr/expr.unary/expr.new/p20.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions %s
typedef __SIZE_TYPE__ size_t;
// Overloaded operator delete with two arguments
diff --git a/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp
new file mode 100644
index 000000000000..d9e0ff88bd8d
--- /dev/null
+++ b/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+
+namespace PR6285 {
+ template<typename T> struct identity
+ { typedef T type; };
+
+ struct D {
+ template<typename T = short>
+ operator typename identity<T>::type(); // expected-note{{candidate}}
+ };
+
+ int f() { return D(); } // expected-error{{no viable conversion}}
+}
+
diff --git a/test/CXX/stmt.stmt/stmt.select/p3.cpp b/test/CXX/stmt.stmt/stmt.select/p3.cpp
index e674f9708c51..31de685ed35f 100644
--- a/test/CXX/stmt.stmt/stmt.select/p3.cpp
+++ b/test/CXX/stmt.stmt/stmt.select/p3.cpp
@@ -9,3 +9,11 @@ void g() {
int x; // expected-error{{redefinition of 'x'}}
}
}
+
+
+void h() {
+ if (int x = f()) // expected-note 2{{previous definition}}
+ int x; // expected-error{{redefinition of 'x'}}
+ else
+ int x; // expected-error{{redefinition of 'x'}}
+} \ No newline at end of file
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
index cfa14f996bbe..97457ea213bb 100644
--- a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
@@ -1,16 +1,48 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<int I, int J, class T> class X {
+template<int I, int J, class T> struct X {
static const int value = 0;
};
-template<int I, int J> class X<I, J, int> {
+template<int I, int J> struct X<I, J, int> {
static const int value = 1;
};
-template<int I> class X<I, I, int> {
+template<int I> struct X<I, I, int> {
static const int value = 2;
};
int array0[X<0, 0, float>::value == 0? 1 : -1];
int array1[X<0, 1, int>::value == 1? 1 : -1];
int array2[X<0, 0, int>::value == 2? 1 : -1];
+
+namespace DependentSubstPartialOrdering {
+ template<typename T, typename U = void, typename V = void>
+ struct X {
+ static const unsigned value = 1;
+ };
+
+ template<typename T, typename U>
+ struct X<T, U, typename T::is_b> {
+ static const unsigned value = 2;
+ };
+
+ template<typename T>
+ struct X<T, typename T::is_a, typename T::is_b> {
+ static const unsigned value = 3;
+ };
+
+ struct X1 { };
+
+ struct X2 {
+ typedef void is_b;
+ };
+
+ struct X3 {
+ typedef void is_a;
+ typedef void is_b;
+ };
+
+ int check_X1[X<X1, void, void>::value == 1? 1 : -1];
+ int check_X2[X<X2, void, void>::value == 2? 1 : -1];
+ int check_X3[X<X3, void, void>::value == 3? 1 : -1];
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index c9dc5460a0f6..073b2a146354 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faccess-control -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -verify -emit-llvm-only %s
namespace test0 {
template <typename T> struct Num {
@@ -155,7 +155,7 @@ namespace Dependent {
}
namespace test7 {
- template <class T> class A { // expected-note {{previous definition is here}}
+ template <class T> class A { // expected-note {{declared here}}
friend class B;
int x; // expected-note {{declared private here}}
};
@@ -174,7 +174,7 @@ namespace test7 {
// This shouldn't crash.
template <class T> class D {
- friend class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
+ friend class A; // expected-error {{elaborated type refers to a template}}
};
template class D<int>;
}
@@ -216,3 +216,80 @@ namespace test9 {
template class A<int>; // expected-note {{in instantiation}}
}
+
+namespace test10 {
+ template <class T> class A;
+ template <class T> A<T> bar(const T*, const A<T>&);
+ template <class T> class A {
+ private:
+ void foo(); // expected-note {{declared private here}}
+ friend A bar<>(const T*, const A<T>&);
+ };
+
+ template <class T> A<T> bar(const T *l, const A<T> &r) {
+ A<T> l1;
+ l1.foo();
+
+ A<char> l2;
+ l2.foo(); // expected-error {{'foo' is a private member of 'test10::A<char>'}}
+
+ return l1;
+ }
+
+ template A<int> bar<int>(const int *, const A<int> &); // expected-note {{in instantiation}}
+}
+
+// PR6752: this shouldn't crash.
+namespace test11 {
+ struct Foo {
+ template<class A>
+ struct IteratorImpl {
+ template<class T> friend class IteratorImpl;
+ };
+ };
+
+ template struct Foo::IteratorImpl<int>;
+ template struct Foo::IteratorImpl<long>;
+}
+
+// PR6827
+namespace test12 {
+ template <typename T> class Foo;
+ template <typename T> Foo<T> foo(T* t){ return Foo<T>(t, true); }
+
+ template <typename T> class Foo {
+ public:
+ Foo(T*);
+ friend Foo<T> foo<T>(T*);
+ private:
+ Foo(T*, bool); // expected-note {{declared private here}}
+ };
+
+ // Should work.
+ int globalInt;
+ Foo<int> f = foo(&globalInt);
+
+ // Shouldn't work.
+ long globalLong;
+ template <> Foo<long> foo(long *t) {
+ Foo<int> s(&globalInt, false); // expected-error {{calling a private constructor}}
+ return Foo<long>(t, true);
+ }
+}
+
+// PR6514
+namespace test13 {
+ template <int N, template <int> class Temp>
+ class Role : public Temp<N> {
+ friend class Temp<N>;
+ int x;
+ };
+
+ template <int N> class Foo {
+ void foo(Role<N, test13::Foo> &role) {
+ (void) role.x;
+ }
+ };
+
+ template class Foo<0>;
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p3.cpp b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
index 17d8c85df00c..d116e016f1d2 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
@@ -8,6 +8,5 @@ class B {
template <class T> friend class A;
template <class T> friend class Undeclared;
- // FIXME: Diagnostic below could be (and was) better.
- template <class T> friend typename A<T>::Member; // expected-error {{classes or functions}}
+ template <class T> friend typename A<T>::Member; // expected-warning {{non-class type 'typename A<T>::Member' cannot be a friend}}
};
diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
index b057eedf93b4..f5f12055c19e 100644
--- a/test/CXX/temp/temp.decls/temp.mem/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
@@ -19,17 +19,17 @@ namespace PR6376 {
template<typename T>
struct X {
template<typename Y>
- struct Y { };
+ struct Y1 { }; //
};
template<>
struct X<float> {
template<typename Y>
- struct Y { };
+ struct Y1 { };
};
template<typename T, typename U>
- struct Z : public X<T>::template Y<U> { };
+ struct Z : public X<T>::template Y1<U> { };
Z<float, int> z0;
}
diff --git a/test/CXX/temp/temp.param/p3.cpp b/test/CXX/temp/temp.param/p3.cpp
index 8fcc2dc85957..dc40c4bb9090 100644
--- a/test/CXX/temp/temp.param/p3.cpp
+++ b/test/CXX/temp/temp.param/p3.cpp
@@ -26,3 +26,15 @@ template<class T, T i> struct X2 {
// expected-error{{no viable conversion}}
}
};
+
+namespace PR6831 {
+ namespace NA { struct S; }
+ namespace NB { struct S; }
+
+ using namespace NA;
+ using namespace NB;
+
+ template <typename S> void foo();
+ template <int S> void bar();
+ template <template<typename> class S> void baz();
+}
diff --git a/test/CXX/temp/temp.res/temp.local/p3.cpp b/test/CXX/temp/temp.res/temp.local/p3.cpp
new file mode 100644
index 000000000000..88f8963e6b62
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify %s
+
+template <class T> struct Base { // expected-note 4 {{member found by ambiguous name lookup}}
+ static void f();
+};
+
+struct X0 { };
+
+template <class T> struct Derived: Base<int>, Base<char> {
+ typename Derived::Base b; // expected-error{{member 'Base' found in multiple base classes of different types}}
+ typename Derived::Base<double> d; // OK
+
+ void g(X0 *t) {
+ t->Derived::Base<T>::f();
+ t->Base<T>::f();
+ t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \
+ // expected-error{{no member named 'f' in 'X0'}} \
+ // expected-error{{expected a class or namespace}}
+ }
+};
+
+namespace PR6717 {
+ template <typename T>
+ class WebVector {
+ }
+
+ WebVector(const WebVector<T>& other) { }
+
+ template <typename C>
+ WebVector<T>& operator=(const C& other) { } // expected-error{{unknown type name 'WebVector'}} \
+ // expected-error{{unqualified-id}}
+}
diff --git a/test/CXX/temp/temp.spec/p5.cpp b/test/CXX/temp/temp.spec/p5.cpp
index c37817cc49b8..ba99dd7093a2 100644
--- a/test/CXX/temp/temp.spec/p5.cpp
+++ b/test/CXX/temp/temp.spec/p5.cpp
@@ -27,3 +27,20 @@ template union X0<float>::Inner; // expected-error{{duplicate explicit instantia
template float X0<float>::value; // expected-note{{previous explicit instantiation}}
template float X0<float>::value; // expected-error{{duplicate explicit instantiation}}
+
+// Make sure that we don't get tricked by redeclarations of nested classes.
+namespace NestedClassRedecls {
+ template<typename T>
+ struct X {
+ struct Nested;
+ friend struct Nested;
+
+ struct Nested {
+ Nested() {}
+ } nested;
+ };
+
+ X<int> xi;
+
+ template struct X<int>;
+}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
index e30f046c2bd1..e9758bcdec2c 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp
@@ -8,12 +8,11 @@ template void f0(int); // okay
// A definition of the class or class template containing a member function
// template shall be in scope at the point of the explicit instantiation of
// the member function template.
-struct X0; // expected-note 3{{forward declaration}}
-template<typename> struct X1; // expected-note 8{{declared here}}
+struct X0; // expected-note {{forward declaration}}
+template<typename> struct X1; // expected-note 5{{declared here}}
-// FIXME: Repeated diagnostics here!
-template void X0::f0<int>(int); // expected-error 3{{incomplete type}} // expected-error{{invalid token after top level declarator}}
-template void X1<int>::f0<int>(int); // expected-error 3{{implicit instantiation of undefined template}} // expected-error{{invalid token after top level declarator}}
+template void X0::f0<int>(int); // expected-error {{incomplete type}}
+template void X1<int>::f0<int>(int); // expected-error {{implicit instantiation of undefined template}}
// A definition of a class template or class member template shall be in scope
// at the point of the explicit instantiation of the class template or class
@@ -33,11 +32,10 @@ template struct X2<int>::Inner<float>; // expected-error{{explicit instantiation
// A definition of a class template shall be in scope at the point of an
// explicit instantiation of a member function or a static data member of the
// class template.
-template void X1<int>::f1(int); // expected-error 2{{undefined template}} \
- // expected-error{{does not refer}}
+template void X1<int>::f1(int); // expected-error {{undefined template}}
+template void X1<int>::f1<int>(int); // expected-error {{undefined template}}
-template int X1<int>::member; // expected-error 2{{undefined template}} \
- // expected-error{{does not refer}}
+template int X1<int>::member; // expected-error {{undefined template}}
// 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.
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
index 2b852136f303..d30437411513 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
template<typename T> void f0(T); // expected-note{{here}}
template void f0(int); // expected-error{{explicit instantiation of undefined function template}}
@@ -16,20 +16,20 @@ template void X0<int>::f1(); // expected-error{{explicit instantiation of undefi
template int X0<int>::value; // expected-error{{explicit instantiation of undefined static data member}}
-template<> void f0(long);
-template void f0(long); // okay
+template<> void f0(long); // expected-note{{previous template specialization is here}}
+template void f0(long); // expected-warning{{explicit instantiation of 'f0<long>' that occurs after an explicit specialization will be ignored}}
-template<> void X0<long>::f1();
-template void X0<long>::f1();
+template<> void X0<long>::f1(); // expected-note{{previous template specialization is here}}
+template void X0<long>::f1(); // expected-warning{{explicit instantiation of 'f1' that occurs after an explicit specialization will be ignored}}
-template<> struct X0<long>::Inner;
-template struct X0<long>::Inner;
+template<> struct X0<long>::Inner; // expected-note{{previous template specialization is here}}
+template struct X0<long>::Inner; // expected-warning{{explicit instantiation of 'Inner' that occurs after an explicit specialization will be ignored}}
-template<> long X0<long>::value;
-template long X0<long>::value;
+template<> long X0<long>::value; // expected-note{{previous template specialization is here}}
+template long X0<long>::value; // expected-warning{{explicit instantiation of 'value' that occurs after an explicit specialization will be ignored}}
-template<> struct X0<double>;
-template struct X0<double>;
+template<> struct X0<double>; // expected-note{{previous template specialization is here}}
+template struct X0<double>; // expected-warning{{explicit instantiation of 'X0<double>' that occurs after an explicit specialization will be ignored}}
// PR 6458
namespace test0 {
diff --git a/test/CXX/temp/temp.spec/temp.inst/p11.cpp b/test/CXX/temp/temp.spec/temp.inst/p11.cpp
new file mode 100644
index 000000000000..818407102cfd
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.inst/p11.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -verify -emit-llvm-only %s
+
+// rdar://problem/7838962
+namespace test0 {
+ template<typename T> unsigned f0() {
+ return T::MaxSize; // expected-error {{'int' cannot be used prior to '::'}}
+ };
+ template<typename T> struct A {
+ void Allocate(unsigned Alignment
+ = f0<T>()) // expected-note {{in instantiation}}
+ {}
+ };
+ void f1(A<int> x) { x.Allocate(); }
+
+}
diff --git a/test/CodeCompletion/call.cpp b/test/CodeCompletion/call.cpp
index 04d2a2f0c981..1df958ed2cc0 100644
--- a/test/CodeCompletion/call.cpp
+++ b/test/CodeCompletion/call.cpp
@@ -18,6 +18,7 @@ void f();
void test() {
f(Y(), 0, 0);
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s
+ // CHECK-CC1: COMPLETION: Pattern : dynamic_cast<<#type-id#>>(<#expression#>)
// CHECK-CC1: f(N::Y y, <#int ZZ#>)
// CHECK-CC1-NEXT: f(int i, <#int j#>, int k)
// CHECK-CC1-NEXT: f(float x, <#float y#>)
diff --git a/test/CodeCompletion/macros.c b/test/CodeCompletion/macros.c
index 6330d25172c0..0758bbf76887 100644
--- a/test/CodeCompletion/macros.c
+++ b/test/CodeCompletion/macros.c
@@ -19,11 +19,7 @@ void test(struct Point *p) {
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s
- // CC1: BAR(<#X#>, <#Y#>)
// CC1: color
- // CC1: FOO
- // CC1: IDENTITY(<#X#>)
- // CC1: WIBBLE
// CC1: x
// CC1: y
// CC1: z
diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp
index d938c79eae33..699b01de74ff 100644
--- a/test/CodeCompletion/ordinary-name.cpp
+++ b/test/CodeCompletion/ordinary-name.cpp
@@ -21,7 +21,7 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: float
// CHECK-CC1-NEXT: COMPLETION: foo : [#void#]foo()
// CHECK-CC1-NEXT: COMPLETION: Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){<#statements#>
- // CHECK-CC1: COMPLETION: Pattern : goto <#identifier#>;
+ // CHECK-CC1: COMPLETION: Pattern : goto <#identifier#>
// CHECK-CC1-NEXT: COMPLETION: Pattern : if(<#condition#>){<#statements#>
// CHECK-CC1: COMPLETION: int
// CHECK-CC1-NEXT: COMPLETION: long
@@ -29,7 +29,7 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: Pattern : new <#type-id#>[<#size#>](<#expressions#>)
// CHECK-CC1-NEXT: COMPLETION: operator
// CHECK-CC1-NEXT: COMPLETION: Pattern : reinterpret_cast<<#type-id#>>(<#expression#>)
- // CHECK-CC1-NEXT: COMPLETION: Pattern : return;
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : return
// CHECK-CC1-NEXT: COMPLETION: short
// CHECK-CC1-NEXT: COMPLETION: signed
// CHECK-CC1-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
@@ -48,7 +48,7 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
// CHECK-CC1-NEXT: COMPLETION: union
// CHECK-CC1-NEXT: COMPLETION: unsigned
- // CHECK-CC1-NEXT: COMPLETION: Pattern : using namespace <#identifier#>;
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : using namespace <#identifier#>
// CHECK-CC1-NEXT: COMPLETION: void
// CHECK-CC1-NEXT: COMPLETION: volatile
// CHECK-CC1-NEXT: COMPLETION: wchar_t
@@ -58,7 +58,7 @@ void foo() {
// CHECK-CC1-NEXT: COMPLETION: z : [#void#]z(<#int#>)
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
- // CHECK-CC2: COMPLETION: Pattern : asm(<#string-literal#>);
+ // CHECK-CC2: COMPLETION: Pattern : asm(<#string-literal#>)
// CHECK-CC2-NEXT: COMPLETION: bool
// CHECK-CC2-NEXT: COMPLETION: char
// CHECK-CC2-NEXT: COMPLETION: class
@@ -71,14 +71,14 @@ void foo() {
// CHECK-CC2-NEXT: COMPLETION: int
// CHECK-CC2-NEXT: COMPLETION: long
// CHECK-CC2-NEXT: COMPLETION: Pattern : namespace <#identifier#>{<#declarations#>
- // CHECK-CC2: COMPLETION: Pattern : namespace <#identifier#> = <#identifier#>;
+ // CHECK-CC2: COMPLETION: Pattern : namespace <#identifier#> = <#identifier#>
// CHECK-CC2-NEXT: COMPLETION: operator
// CHECK-CC2-NEXT: COMPLETION: short
// CHECK-CC2-NEXT: COMPLETION: signed
// CHECK-CC2-NEXT: COMPLETION: static
// CHECK-CC2-NEXT: COMPLETION: struct
// CHECK-CC2-NEXT: COMPLETION: t : t
- // CHECK-CC2-NEXT: COMPLETION: Pattern : template <#declaration#>;
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : template <#declaration#>
// CHECK-CC2-NEXT: COMPLETION: Pattern : template<<#parameters#>>
// CHECK-CC2-NEXT: COMPLETION: TYPEDEF : TYPEDEF
// CHECK-CC2-NEXT: COMPLETION: typedef
@@ -86,8 +86,8 @@ void foo() {
// CHECK-CC2-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
// CHECK-CC2-NEXT: COMPLETION: union
// CHECK-CC2-NEXT: COMPLETION: unsigned
- // CHECK-CC2-NEXT: COMPLETION: Pattern : using namespace <#identifier#>;
- // CHECK-CC2-NEXT: COMPLETION: Pattern : using <#qualified-id#>;
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : using namespace <#identifier#>
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : using <#qualified-id#>
// CHECK-CC2-NEXT: COMPLETION: void
// CHECK-CC2-NEXT: COMPLETION: volatile
// CHECK-CC2-NEXT: COMPLETION: wchar_t
@@ -122,7 +122,7 @@ void foo() {
// CHECK-CC3-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
// CHECK-CC3-NEXT: COMPLETION: union
// CHECK-CC3-NEXT: COMPLETION: unsigned
- // CHECK-CC3-NEXT: COMPLETION: Pattern : using <#qualified-id#>;
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : using <#qualified-id#>
// CHECK-CC3-NEXT: COMPLETION: virtual
// CHECK-CC3-NEXT: COMPLETION: void
// CHECK-CC3-NEXT: COMPLETION: volatile
diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index 99be46996ed5..1db37de4bb27 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -1,4 +1,8 @@
// RUN: %clang -ccc-host-triple i386-apple-darwin10 -S -g -dA %s -o - | FileCheck %s
int global;
-// CHECK: asciz "global" ## External Name
-int main() { return 0;}
+// CHECK: asciz "global" ## External Name
+// CHECK: asciz "localstatic" ## External Name
+int main() {
+ static int localstatic;
+ return 0;
+}
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index d313a9b3310f..72fd7c3f8b71 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -28,13 +28,13 @@ struct s4 { struct s4_0 { int f0; } f0; };
struct s4 f4(void) {}
// APCS-GNU: define arm_apcscc void @f5(
-// APCS-GNU: struct.s5* noalias sret
+// APCS-GNU: struct.s5* sret
// AAPCS: define arm_aapcscc i32 @f5()
struct s5 { struct { } f0; int f1; };
struct s5 f5(void) {}
// APCS-GNU: define arm_apcscc void @f6(
-// APCS-GNU: struct.s6* noalias sret
+// APCS-GNU: struct.s6* sret
// AAPCS: define arm_aapcscc i32 @f6()
struct s6 { int f0[1]; };
struct s6 f6(void) {}
@@ -45,7 +45,7 @@ struct s7 { struct { int : 0; } f0; };
struct s7 f7(void) {}
// APCS-GNU: define arm_apcscc void @f8(
-// APCS-GNU: struct.s8* noalias sret
+// APCS-GNU: struct.s8* sret
// AAPCS: define arm_aapcscc void @f8()
struct s8 { struct { int : 0; } f0[1]; };
struct s8 f8(void) {}
@@ -61,7 +61,7 @@ struct s10 { int f0; int : 0; int : 0; };
struct s10 f10(void) {}
// APCS-GNU: define arm_apcscc void @f11(
-// APCS-GNU: struct.s10* noalias sret
+// APCS-GNU: struct.s10* sret
// AAPCS: define arm_aapcscc i32 @f11()
struct s11 { int : 0; int f0; };
struct s11 f11(void) {}
@@ -72,7 +72,7 @@ union u12 { char f0; short f1; int f2; };
union u12 f12(void) {}
// APCS-GNU: define arm_apcscc void @f13(
-// APCS-GNU: struct.s13* noalias sret
+// APCS-GNU: struct.s13* sret
// FIXME: This should return a float.
// AAPCS-FIXME: define arm_aapcscc float @f13()
@@ -80,7 +80,7 @@ struct s13 { float f0; };
struct s13 f13(void) {}
// APCS-GNU: define arm_apcscc void @f14(
-// APCS-GNU: struct.s13* noalias sret
+// APCS-GNU: struct.s13* sret
// AAPCS: define arm_aapcscc i32 @f14()
union u14 { float f0; };
union u14 f14(void) {}
@@ -104,18 +104,18 @@ struct s18 { short f0; char f1 : 4; };
struct s18 f18(void) {}
// APCS-GNU: define arm_apcscc void @f19(
-// APCS-GNU: struct.s19* noalias sret
+// APCS-GNU: struct.s19* 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
+// APCS-GNU: struct.s20* 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()
+// APCS-GNU: define arm_apcscc i8 @f21()
// AAPCS: define arm_aapcscc i32 @f21()
struct s21 { struct {} f1; int f0 : 4; };
struct s21 f21(void) {}
@@ -128,10 +128,10 @@ struct s21 f21(void) {}
// 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
+// AAPCS: define arm_aapcscc void @f24({{.*}} sret
+// AAPCS: define arm_aapcscc void @f25({{.*}} sret
+// AAPCS: define arm_aapcscc void @f26({{.*}} sret
+// AAPCS: define arm_aapcscc void @f27({{.*}} sret
_Complex char f22(void) {}
_Complex short f23(void) {}
_Complex int f24(void) {}
@@ -149,7 +149,7 @@ struct s28 f28() {}
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
+// APCS-GNU: define arm_apcscc void @f30({{.*}} sret
+// AAPCS: define arm_aapcscc void @f30({{.*}} sret
struct s30 { _Complex int f0; };
struct s30 f30() {}
diff --git a/test/CodeGen/arm_asm_clobber.c b/test/CodeGen/arm_asm_clobber.c
deleted file mode 100644
index a7ca0b5332b0..000000000000
--- a/test/CodeGen/arm_asm_clobber.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: %clang_cc1 -triple armv6-unknown-unknown -emit-llvm -o %t %s
-
-void test0(void) {
- asm volatile("mov r0, r0" :: );
-}
-void test1(void) {
- asm volatile("mov r0, r0" :::
- "cc", "memory" );
-}
-void test2(void) {
- asm volatile("mov r0, r0" :::
- "r0", "r1", "r2", "r3");
- asm volatile("mov r0, r0" :::
- "r4", "r5", "r6", "r8");
-}
-void test3(void) {
- asm volatile("mov r0, r0" :::
- "a1", "a2", "a3", "a4");
- asm volatile("mov r0, r0" :::
- "v1", "v2", "v3", "v5");
-}
diff --git a/test/CodeGen/asm-errors.c b/test/CodeGen/asm-errors.c
new file mode 100644
index 000000000000..7323e61b591a
--- /dev/null
+++ b/test/CodeGen/asm-errors.c
@@ -0,0 +1,8 @@
+// RUN: not %clang_cc1 -triple i386-apple-darwin10 -emit-obj %s > %t 2>&1
+// RUN: FileCheck %s < %t
+
+int test1(int X) {
+// CHECK: error: unrecognized instruction
+ __asm__ ("abc incl %0" : "+r" (X));
+ return X;
+}
diff --git a/test/CodeGen/asm.c b/test/CodeGen/asm.c
index ace0db9af6d4..507702887866 100644
--- a/test/CodeGen/asm.c
+++ b/test/CodeGen/asm.c
@@ -147,3 +147,24 @@ int t19(unsigned data) {
// CHECK: = call {{.*}}asm "x$(abc$|def$|ghi$)z"
}
+
+// PR6845 - Mismatching source/dest fp types.
+double t20(double x) {
+ register long double result;
+ __asm __volatile ("frndint" : "=t" (result) : "0" (x));
+ return result;
+
+ // CHECK: @t20
+ // CHECK: fpext double {{.*}} to x86_fp80
+ // CHECK-NEXT: call x86_fp80 asm sideeffect "frndint"
+ // CHECK: fptrunc x86_fp80 {{.*}} to double
+}
+
+float t21(long double x) {
+ register float result;
+ __asm __volatile ("frndint" : "=t" (result) : "0" (x));
+ return result;
+ // CHECK: @t21
+ // CHECK: call x86_fp80 asm sideeffect "frndint"
+ // CHECK-NEXT: fptrunc x86_fp80 {{.*}} to float
+}
diff --git a/test/CodeGen/asm_arm.c b/test/CodeGen/asm_arm.c
new file mode 100644
index 000000000000..aac47d57dc5a
--- /dev/null
+++ b/test/CodeGen/asm_arm.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple armv6-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+void test0(void) {
+ asm volatile("mov r0, r0" :: );
+}
+void test1(void) {
+ asm volatile("mov r0, r0" :::
+ "cc", "memory" );
+}
+void test2(void) {
+ asm volatile("mov r0, r0" :::
+ "r0", "r1", "r2", "r3");
+ asm volatile("mov r0, r0" :::
+ "r4", "r5", "r6", "r8");
+}
+void test3(void) {
+ asm volatile("mov r0, r0" :::
+ "a1", "a2", "a3", "a4");
+ asm volatile("mov r0, r0" :::
+ "v1", "v2", "v3", "v5");
+}
+
+
+// {} should not be treated as asm variants.
+void test4(float *a, float *b) {
+ // CHECK: @test4
+ // CHECK: call void asm sideeffect "vld1.32 {d8[],d9[]},
+ __asm__ volatile (
+ "vld1.32 {d8[],d9[]}, [%1,:32] \n\t"
+ "vst1.32 {q4}, [%0,:128] \n\t"
+ :: "r"(a), "r"(b));
+}
diff --git a/test/CodeGen/bitfield-2.c b/test/CodeGen/bitfield-2.c
new file mode 100644
index 000000000000..e91859fb7287
--- /dev/null
+++ b/test/CodeGen/bitfield-2.c
@@ -0,0 +1,368 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64 -O3 -o %t.opt.ll %s \
+// RUN: -fdump-record-layouts 2> %t.dump.txt
+// RUN: FileCheck -check-prefix=CHECK-RECORD < %t.dump.txt %s
+// RUN: FileCheck -check-prefix=CHECK-OPT < %t.opt.ll %s
+
+/****/
+
+// Check that we don't read off the end a packed 24-bit structure.
+// PR6176
+
+// CHECK-RECORD: *** Dumping IRgen Record Layout
+// CHECK-RECORD: Record: struct s0
+// CHECK-RECORD: Layout: <CGRecordLayout
+// CHECK-RECORD: LLVMType:<{ [3 x i8] }>
+// CHECK-RECORD: ContainsPointerToDataMember:0
+// CHECK-RECORD: BitFields:[
+// CHECK-RECORD: <CGBitFieldInfo Size:24 IsSigned:1
+// CHECK-RECORD: NumComponents:2 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:16>
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:16 TargetBitWidth:8>
+struct __attribute((packed)) s0 {
+ int f0 : 24;
+};
+
+struct s0 g0 = { 0xdeadbeef };
+
+int f0_load(struct s0 *a0) {
+ int size_check[sizeof(struct s0) == 3 ? 1 : -1];
+ return a0->f0;
+}
+int f0_store(struct s0 *a0) {
+ return (a0->f0 = 1);
+}
+int f0_reload(struct s0 *a0) {
+ return (a0->f0 += 1);
+}
+
+// CHECK-OPT: define i64 @test_0()
+// CHECK-OPT: ret i64 1
+// CHECK-OPT: }
+unsigned long long test_0() {
+ struct s0 g0 = { 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g0.f0;
+ res ^= f0_load(&g0) ^ f0_store(&g0) ^ f0_reload(&g0);
+ res ^= g0.f0;
+ return res;
+}
+
+/****/
+
+// PR5591
+
+// CHECK-RECORD: *** Dumping IRgen Record Layout
+// CHECK-RECORD: Record: struct s1
+// CHECK-RECORD: Layout: <CGRecordLayout
+// CHECK-RECORD: LLVMType:<{ [2 x i8], i8 }>
+// CHECK-RECORD: ContainsPointerToDataMember:0
+// CHECK-RECORD: BitFields:[
+// CHECK-RECORD: <CGBitFieldInfo Size:10 IsSigned:1
+// CHECK-RECORD: NumComponents:1 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:10>
+// CHECK-RECORD: ]>
+// CHECK-RECORD: <CGBitFieldInfo Size:10 IsSigned:1
+// CHECK-RECORD: NumComponents:2 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:10 AccessWidth:16
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:6>
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:6 TargetBitWidth:4>
+
+#pragma pack(push)
+#pragma pack(1)
+struct __attribute((packed)) s1 {
+ signed f0 : 10;
+ signed f1 : 10;
+};
+#pragma pack(pop)
+
+struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };
+
+int f1_load(struct s1 *a0) {
+ int size_check[sizeof(struct s1) == 3 ? 1 : -1];
+ return a0->f1;
+}
+int f1_store(struct s1 *a0) {
+ return (a0->f1 = 1234);
+}
+int f1_reload(struct s1 *a0) {
+ return (a0->f1 += 1234);
+}
+
+// CHECK-OPT: define i64 @test_1()
+// CHECK-OPT: ret i64 210
+// CHECK-OPT: }
+unsigned long long test_1() {
+ struct s1 g1 = { 0xdeadbeef, 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g1.f0 ^ g1.f1;
+ res ^= f1_load(&g1) ^ f1_store(&g1) ^ f1_reload(&g1);
+ res ^= g1.f0 ^ g1.f1;
+ return res;
+}
+
+/****/
+
+// Check that we don't access beyond the bounds of a union.
+//
+// PR5567
+
+// CHECK-RECORD: *** Dumping IRgen Record Layout
+// CHECK-RECORD: Record: union u2
+// CHECK-RECORD: Layout: <CGRecordLayout
+// CHECK-RECORD: LLVMType:<{ i8 }>
+// CHECK-RECORD: ContainsPointerToDataMember:0
+// CHECK-RECORD: BitFields:[
+// CHECK-RECORD: <CGBitFieldInfo Size:3 IsSigned:0
+// CHECK-RECORD: NumComponents:1 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:8
+// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:3>
+
+union __attribute__((packed)) u2 {
+ unsigned long long f0 : 3;
+};
+
+union u2 g2 = { 0xdeadbeef };
+
+int f2_load(union u2 *a0) {
+ return a0->f0;
+}
+int f2_store(union u2 *a0) {
+ return (a0->f0 = 1234);
+}
+int f2_reload(union u2 *a0) {
+ return (a0->f0 += 1234);
+}
+
+// CHECK-OPT: define i64 @test_2()
+// CHECK-OPT: ret i64 2
+// CHECK-OPT: }
+unsigned long long test_2() {
+ union u2 g2 = { 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g2.f0;
+ res ^= f2_load(&g2) ^ f2_store(&g2) ^ f2_reload(&g2);
+ res ^= g2.f0;
+ return res;
+}
+
+/***/
+
+// PR5039
+
+struct s3 {
+ long long f0 : 32;
+ long long f1 : 32;
+};
+
+struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };
+
+int f3_load(struct s3 *a0) {
+ a0->f0 = 1;
+ return a0->f0;
+}
+int f3_store(struct s3 *a0) {
+ a0->f0 = 1;
+ return (a0->f0 = 1234);
+}
+int f3_reload(struct s3 *a0) {
+ a0->f0 = 1;
+ return (a0->f0 += 1234);
+}
+
+// CHECK-OPT: define i64 @test_3()
+// CHECK-OPT: ret i64 -559039940
+// CHECK-OPT: }
+unsigned long long test_3() {
+ struct s3 g3 = { 0xdeadbeef, 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g3.f0 ^ g3.f1;
+ res ^= f3_load(&g3) ^ f3_store(&g3) ^ f3_reload(&g3);
+ res ^= g3.f0 ^ g3.f1;
+ return res;
+}
+
+/***/
+
+// This is a case where the bitfield access will straddle an alignment boundary
+// of its underlying type.
+
+struct s4 {
+ unsigned f0 : 16;
+ unsigned f1 : 28 __attribute__ ((packed));
+};
+
+struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };
+
+int f4_load(struct s4 *a0) {
+ return a0->f0 ^ a0->f1;
+}
+int f4_store(struct s4 *a0) {
+ return (a0->f0 = 1234) ^ (a0->f1 = 5678);
+}
+int f4_reload(struct s4 *a0) {
+ return (a0->f0 += 1234) ^ (a0->f1 += 5678);
+}
+
+// CHECK-OPT: define i64 @test_4()
+// CHECK-OPT: ret i64 4860
+// CHECK-OPT: }
+unsigned long long test_4() {
+ struct s4 g4 = { 0xdeadbeef, 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g4.f0 ^ g4.f1;
+ res ^= f4_load(&g4) ^ f4_store(&g4) ^ f4_reload(&g4);
+ res ^= g4.f0 ^ g4.f1;
+ return res;
+}
+
+/***/
+
+struct s5 {
+ unsigned f0 : 2;
+ _Bool f1 : 1;
+ _Bool f2 : 1;
+};
+
+struct s5 g5 = { 0xdeadbeef, 0xdeadbeef };
+
+int f5_load(struct s5 *a0) {
+ return a0->f0 ^ a0->f1;
+}
+int f5_store(struct s5 *a0) {
+ return (a0->f0 = 0xF) ^ (a0->f1 = 0xF) ^ (a0->f2 = 0xF);
+}
+int f5_reload(struct s5 *a0) {
+ return (a0->f0 += 0xF) ^ (a0->f1 += 0xF) ^ (a0->f2 += 0xF);
+}
+
+// CHECK-OPT: define i64 @test_5()
+// CHECK-OPT: ret i64 2
+// CHECK-OPT: }
+unsigned long long test_5() {
+ struct s5 g5 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g5.f0 ^ g5.f1 ^ g5.f2;
+ res ^= f5_load(&g5) ^ f5_store(&g5) ^ f5_reload(&g5);
+ res ^= g5.f0 ^ g5.f1 ^ g5.f2;
+ return res;
+}
+
+/***/
+
+struct s6 {
+ _Bool f0 : 2;
+};
+
+struct s6 g6 = { 0xF };
+
+int f6_load(struct s6 *a0) {
+ return a0->f0;
+}
+int f6_store(struct s6 *a0) {
+ return a0->f0 = 0x0;
+}
+int f6_reload(struct s6 *a0) {
+ return (a0->f0 += 0xF);
+}
+
+// CHECK-OPT: define zeroext i1 @test_6()
+// CHECK-OPT: ret i1 true
+// CHECK-OPT: }
+_Bool test_6() {
+ struct s6 g6 = { 0xF };
+ unsigned long long res = 0;
+ res ^= g6.f0;
+ res ^= f6_load(&g6);
+ res ^= g6.f0;
+ return res;
+}
+
+/***/
+
+// Check that we compute the best alignment possible for each access.
+//
+// CHECK-RECORD: *** Dumping IRgen Record Layout
+// CHECK-RECORD: Record: struct s7
+// CHECK-RECORD: Layout: <CGRecordLayout
+// CHECK-RECORD: LLVMType:{ i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
+// CHECK-RECORD: ContainsPointerToDataMember:0
+// CHECK-RECORD: BitFields:[
+// CHECK-RECORD: <CGBitFieldInfo Size:5 IsSigned:1
+// CHECK-RECORD: NumComponents:1 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:12 FieldBitStart:0 AccessWidth:32
+// CHECK-RECORD: AccessAlignment:4 TargetBitOffset:0 TargetBitWidth:5>
+// CHECK-RECORD: ]>
+// CHECK-RECORD: <CGBitFieldInfo Size:29 IsSigned:1
+// CHECK-RECORD: NumComponents:1 Components: [
+// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:16 FieldBitStart:0 AccessWidth:32
+// CHECK-RECORD: AccessAlignment:16 TargetBitOffset:0 TargetBitWidth:29>
+
+struct __attribute__((aligned(16))) s7 {
+ int a, b, c;
+ int f0 : 5;
+ int f1 : 29;
+};
+
+int f7_load(struct s7 *a0) {
+ return a0->f0;
+}
+
+/***/
+
+// This is a case where we narrow the access width immediately.
+
+struct __attribute__((packed)) s8 {
+ char f0 : 4;
+ char f1;
+ int f2 : 4;
+ char f3 : 4;
+};
+
+struct s8 g8 = { 0xF };
+
+int f8_load(struct s8 *a0) {
+ return a0->f0 ^ a0 ->f2 ^ a0->f3;
+}
+int f8_store(struct s8 *a0) {
+ return (a0->f0 = 0xFD) ^ (a0->f2 = 0xFD) ^ (a0->f3 = 0xFD);
+}
+int f8_reload(struct s8 *a0) {
+ return (a0->f0 += 0xFD) ^ (a0->f2 += 0xFD) ^ (a0->f3 += 0xFD);
+}
+
+// CHECK-OPT: define i32 @test_8()
+// CHECK-OPT: ret i32 -3
+// CHECK-OPT: }
+unsigned test_8() {
+ struct s8 g8 = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
+ unsigned long long res = 0;
+ res ^= g8.f0 ^ g8.f2 ^ g8.f3;
+ res ^= f8_load(&g8) ^ f8_store(&g8) ^ f8_reload(&g8);
+ res ^= g8.f0 ^ g8.f2 ^ g8.f3;
+ return res;
+}
+
+/***/
+
+// This is another case where we narrow the access width immediately.
+//
+// <rdar://problem/7893760>
+
+struct __attribute__((packed)) s9 {
+ unsigned f0 : 7;
+ unsigned f1 : 7;
+ unsigned f2 : 7;
+ unsigned f3 : 7;
+ unsigned f4 : 7;
+ unsigned f5 : 7;
+ unsigned f6 : 7;
+ unsigned f7 : 7;
+};
+
+int f9_load(struct s9 *a0) {
+ return a0->f7;
+}
diff --git a/test/CodeGen/blocks.c b/test/CodeGen/blocks.c
index 0ef10c14e009..e7625b19542c 100644
--- a/test/CodeGen/blocks.c
+++ b/test/CodeGen/blocks.c
@@ -12,7 +12,7 @@ struct s0 {
int a[64];
};
-// RUN: grep 'internal void @__f2_block_invoke_(.struct.s0\* noalias sret .*, .*, .* byval .*)' %t
+// RUN: grep 'internal void @__f2_block_invoke_(.struct.s0\* sret .*, .*, .* byval .*)' %t
struct s0 f2(struct s0 a0) {
return ^(struct s0 a1){ return a1; }(a0);
}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
new file mode 100644
index 000000000000..04249cc1ee70
--- /dev/null
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -0,0 +1,332 @@
+// RUN: %clang_cc1 -faltivec -triple powerpc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+#include "altivec.h"
+
+int main ()
+{
+ vector signed char vsc = { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15, -16 };
+ vector unsigned char vuc = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ vector short vs = { -1, 2, -3, 4, -5, 6, -7, 8 };
+ vector unsigned short vus = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ vector int vi = { -1, 2, -3, 4 };
+ vector unsigned int vui = { 1, 2, 3, 4 };
+ vector float vf = { -1.5, 2.5, -3.5, 4.5 };
+
+ vector signed char res_vsc;
+ vector unsigned char res_vuc;
+ vector short res_vs;
+ vector unsigned short res_vus;
+ vector int res_vi;
+ vector unsigned int res_vui;
+ vector float res_vf;
+
+ int param_i;
+ int res_i;
+
+ /* vec_abs */
+ vsc = vec_abs(vsc); // CHECK: sub <16 x i8> zeroinitializer
+ // CHECK: @llvm.ppc.altivec.vmaxsb
+
+ vs = __builtin_vec_abs(vs); // CHECK: sub <8 x i16> zeroinitializer
+ // CHECK: @llvm.ppc.altivec.vmaxsh
+
+ vi = vec_abs(vi); // CHECK: sub <4 x i32> zeroinitializer
+ // CHECK: @llvm.ppc.altivec.vmaxsw
+
+ vf = vec_abs(vf); // CHECK: store <4 x i32> <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647>
+ // CHECK: and <4 x i32>
+
+ /* vec_abs */
+ vsc = vec_abss(vsc); // CHECK: @llvm.ppc.altivec.vsubsbs
+ // CHECK: @llvm.ppc.altivec.vmaxsb
+
+ vs = __builtin_vec_abss(vs); // CHECK: @llvm.ppc.altivec.vsubshs
+ // CHECK: @llvm.ppc.altivec.vmaxsh
+
+ vi = vec_abss(vi); // CHECK: @llvm.ppc.altivec.vsubsws
+ // CHECK: @llvm.ppc.altivec.vmaxsw
+
+ /* vec_add */
+ res_vsc = vec_add(vsc, vsc); // CHECK: add nsw <16 x i8>
+ res_vuc = vec_vaddubm(vuc, vuc); // CHECK: add <16 x i8>
+ res_vs = __builtin_altivec_vadduhm(vs, vs); // CHECK: add nsw <8 x i16>
+ res_vus = vec_vadduhm(vus, vus); // CHECK: add <8 x i16>
+ res_vi = __builtin_vec_vadduwm(vi, vi); // CHECK: add nsw <4 x i32>
+ res_vui = vec_vadduwm(vui, vui); // CHECK: add <4 x i32>
+ res_vf = __builtin_vec_vaddfp(vf, vf); // CHECK: fadd <4 x float>
+
+ /* vec_addc */
+ res_vui = vec_vaddcuw(vui, vui); // HECK: @llvm.ppc.altivec.vaddcuw
+
+ /* vec_adds */
+ res_vsc = vec_adds(vsc, vsc); // CHECK: @llvm.ppc.altivec.vaddsbs
+ res_vuc = vec_vaddubs(vuc, vuc); // CHECK: @llvm.ppc.altivec.vaddubs
+ res_vs = __builtin_vec_vaddshs(vs, vs); // CHECK: @llvm.ppc.altivec.vaddshs
+ res_vus = vec_vadduhs(vus, vus); // CHECK: @llvm.ppc.altivec.vadduhs
+ res_vi = __builtin_vec_vaddsws(vi, vi); // CHECK: @llvm.ppc.altivec.vaddsws
+ res_vui = vec_vadduws(vui, vui); // CHECK: @llvm.ppc.altivec.vadduws
+
+ /* vec_sub */
+ res_vsc = vec_sub(vsc, vsc); // CHECK: sub nsw <16 x i8>
+ res_vuc = vec_vsububm(vuc, vuc); // CHECK: sub <16 x i8>
+ res_vs = __builtin_altivec_vsubuhm(vs, vs); // CHECK: sub nsw <8 x i16>
+ res_vus = vec_vsubuhm(vus, vus); // CHECK: sub <8 x i16>
+ res_vi = __builtin_vec_vsubuwm(vi, vi); // CHECK: sub nsw <4 x i32>
+ res_vui = vec_vsubuwm(vui, vui); // CHECK: sub <4 x i32>
+ res_vf = __builtin_vec_vsubfp(vf, vf); // CHECK: fsub <4 x float>
+
+ /* vec_subs */
+ res_vsc = vec_subs(vsc, vsc); // CHECK: @llvm.ppc.altivec.vsubsbs
+ res_vuc = vec_vsububs(vuc, vuc); // CHECK: @llvm.ppc.altivec.vsububs
+ res_vs = __builtin_vec_vsubshs(vs, vs); // CHECK: @llvm.ppc.altivec.vsubshs
+ res_vus = vec_vsubuhs(vus, vus); // CHECK: @llvm.ppc.altivec.vsubuhs
+ res_vi = __builtin_vec_vsubsws(vi, vi); // CHECK: @llvm.ppc.altivec.vsubsws
+ res_vui = vec_vsubuws(vui, vui); // CHECK: @llvm.ppc.altivec.vsubuws
+
+ /* vec_avg */
+ res_vsc = vec_avg(vsc, vsc); // CHECK: @llvm.ppc.altivec.vavgsb
+ res_vuc = __builtin_vec_vavgub(vuc, vuc); // CHECK: @llvm.ppc.altivec.vavgub
+ res_vs = vec_vavgsh(vs, vs); // CHECK: @llvm.ppc.altivec.vavgsh
+ res_vus = __builtin_vec_vavguh(vus, vus); // CHECK: @llvm.ppc.altivec.vavguh
+ res_vi = vec_vavgsw(vi, vi); // CHECK: @llvm.ppc.altivec.vavgsw
+ res_vui = __builtin_vec_vavguw(vui, vui); // CHECK: @llvm.ppc.altivec.vavguw
+
+ /* vec_st */
+ param_i = 5;
+ vec_st(vsc, 0, &res_vsc); // CHECK: @llvm.ppc.altivec.stvx
+ __builtin_vec_st(vuc, param_i, &res_vuc); // CHECK: @llvm.ppc.altivec.stvx
+ vec_stvx(vs, 1, &res_vs); // CHECK: @llvm.ppc.altivec.stvx
+ vec_st(vus, 1000, &res_vus); // CHECK: @llvm.ppc.altivec.stvx
+ vec_st(vi, 0, &res_vi); // CHECK: @llvm.ppc.altivec.stvx
+ vec_st(vui, 0, &res_vui); // CHECK: @llvm.ppc.altivec.stvx
+ vec_st(vf, 0, &res_vf); // CHECK: @llvm.ppc.altivec.stvx
+
+ /* vec_stl */
+ param_i = 10000;
+ vec_stl(vsc, param_i, &res_vsc); // CHECK: @llvm.ppc.altivec.stvxl
+ __builtin_vec_stl(vuc, 1, &res_vuc); // CHECK: @llvm.ppc.altivec.stvxl
+ vec_stvxl(vs, 0, &res_vs); // CHECK: @llvm.ppc.altivec.stvxl
+ vec_stl(vus, 0, &res_vus); // CHECK: @llvm.ppc.altivec.stvxl
+ vec_stl(vi, 0, &res_vi); // CHECK: @llvm.ppc.altivec.stvxl
+ vec_stl(vui, 0, &res_vui); // CHECK: @llvm.ppc.altivec.stvxl
+ vec_stl(vf, 0, &res_vf); // CHECK: @llvm.ppc.altivec.stvxl
+
+ /* vec_ste */
+ param_i = 10000;
+ vec_ste(vsc, param_i, &res_vsc); // CHECK: @llvm.ppc.altivec.stvebx
+ vec_stvebx(vuc, 1, &res_vuc); // CHECK: @llvm.ppc.altivec.stvebx
+ __builtin_vec_stvehx(vs, 0, &res_vs); // CHECK: @llvm.ppc.altivec.stvehx
+ vec_stvehx(vus, 0, &res_vus); // CHECK: @llvm.ppc.altivec.stvehx
+ vec_stvewx(vi, 0, &res_vi); // CHECK: @llvm.ppc.altivec.stvewx
+ __builtin_vec_stvewx(vui, 0, &res_vui); // CHECK: @llvm.ppc.altivec.stvewx
+ vec_stvewx(vf, 0, &res_vf); // CHECK: @llvm.ppc.altivec.stvewx
+
+ /* vec_cmpb */
+ res_vi = vec_vcmpbfp(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpbfp
+
+ /* vec_cmpeq */
+ res_vi = vec_cmpeq(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpequb
+ res_vi = __builtin_vec_cmpeq(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpequb
+ res_vi = vec_cmpeq(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpequh
+ res_vi = vec_cmpeq(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpequh
+ res_vi = vec_cmpeq(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpequw
+ res_vi = vec_cmpeq(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpequw
+ res_vi = vec_cmpeq(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp
+
+ /* vec_cmpge */
+ res_vi = __builtin_vec_cmpge(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp
+
+ /* vec_cmpgt */
+ res_vi = vec_cmpgt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb
+ res_vi = vec_vcmpgtub(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub
+ res_vi = __builtin_vec_vcmpgtsh(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh
+ res_vi = vec_cmpgt(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh
+ res_vi = vec_cmpgt(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw
+ res_vi = vec_cmpgt(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw
+ res_vi = vec_cmpgt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp
+
+ /* vec_cmple */
+ res_vi = __builtin_vec_cmple(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp
+
+ /* vec_cmplt */
+ res_vi = vec_cmplt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb
+ res_vi = __builtin_vec_cmplt(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub
+ res_vi = vec_cmplt(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh
+ res_vi = vec_cmplt(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh
+ res_vi = vec_cmplt(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw
+ res_vi = vec_cmplt(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw
+ res_vi = vec_cmplt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp
+
+ /* vec_max */
+ res_vsc = vec_max(vsc, vsc); // CHECK: @llvm.ppc.altivec.vmaxsb
+ res_vuc = __builtin_vec_vmaxub(vuc, vuc); // CHECK: @llvm.ppc.altivec.vmaxub
+ res_vs = vec_vmaxsh(vs, vs); // CHECK: @llvm.ppc.altivec.vmaxsh
+ res_vus = vec_max(vus, vus); // CHECK: @llvm.ppc.altivec.vmaxuh
+ res_vi = __builtin_vec_vmaxsw(vi, vi); // CHECK: @llvm.ppc.altivec.vmaxsw
+ res_vui = vec_vmaxuw(vui, vui); // CHECK: @llvm.ppc.altivec.vmaxuw
+ res_vf = __builtin_vec_max(vf, vf); // CHECK: @llvm.ppc.altivec.vmaxfp
+
+ /* vec_mfvscr */
+ vf = vec_mfvscr(); // CHECK: @llvm.ppc.altivec.mfvscr
+
+ /* vec_min */
+ res_vsc = vec_min(vsc, vsc); // CHECK: @llvm.ppc.altivec.vminsb
+ res_vuc = __builtin_vec_vminub(vuc, vuc); // CHECK: @llvm.ppc.altivec.vminub
+ res_vs = vec_vminsh(vs, vs); // CHECK: @llvm.ppc.altivec.vminsh
+ res_vus = vec_min(vus, vus); // CHECK: @llvm.ppc.altivec.vminuh
+ res_vi = __builtin_vec_vminsw(vi, vi); // CHECK: @llvm.ppc.altivec.vminsw
+ res_vui = vec_vminuw(vui, vui); // CHECK: @llvm.ppc.altivec.vminuw
+ res_vf = __builtin_vec_min(vf, vf); // CHECK: @llvm.ppc.altivec.vminfp
+
+ /* vec_mtvscr */
+ vec_mtvscr(vsc); // CHECK: @llvm.ppc.altivec.mtvscr
+
+ /* ------------------------------ predicates -------------------------------------- */
+
+ res_i = __builtin_vec_vcmpeq_p(__CR6_EQ, vsc, vui); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+ res_i = __builtin_vec_vcmpge_p(__CR6_EQ, vs, vi); // CHECK: @llvm.ppc.altivec.vcmpgefp.p
+ res_i = __builtin_vec_vcmpgt_p(__CR6_EQ, vuc, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_eq */
+ res_i = vec_all_eq(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_all_eq(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_all_eq(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_all_eq(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_all_eq(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_all_eq(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_all_eq(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_all_ge */
+ res_i = vec_all_ge(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_all_ge(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_all_ge(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_all_ge(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_all_ge(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_all_ge(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_all_ge(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_gt */
+ res_i = vec_all_gt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_all_gt(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_all_gt(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_all_gt(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_all_gt(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_all_gt(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_all_gt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_in */
+ res_i = vec_all_in(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpbfp.p
+
+ /* vec_all_le */
+ res_i = vec_all_le(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_all_le(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_all_le(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_all_le(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_all_le(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_all_le(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_all_le(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_nan */
+ res_i = vec_all_nan(vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_all_ne */
+ res_i = vec_all_ne(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_all_ne(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_all_ne(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_all_ne(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_all_ne(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_all_ne(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_all_ne(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_all_nge */
+ res_i = vec_all_nge(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp.p
+
+ /* vec_all_ngt */
+ res_i = vec_all_ngt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_nle */
+ res_i = vec_all_nle(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp.p
+
+ /* vec_all_nlt */
+ res_i = vec_all_nlt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_all_numeric */
+ res_i = vec_all_numeric(vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_any_eq */
+ res_i = vec_any_eq(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_any_eq(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_any_eq(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_any_eq(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_any_eq(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_any_eq(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_any_eq(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_any_ge */
+ res_i = vec_any_ge(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_any_ge(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_any_ge(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_any_ge(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_any_ge(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_any_ge(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_any_ge(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_gt */
+ res_i = vec_any_gt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_any_gt(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_any_gt(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_any_gt(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_any_gt(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_any_gt(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_any_gt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_le */
+ res_i = vec_any_le(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_any_le(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_any_le(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_any_le(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_any_le(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_any_le(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_any_le(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_lt */
+ res_i = vec_any_lt(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p
+ res_i = vec_any_lt(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpgtub.p
+ res_i = vec_any_lt(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p
+ res_i = vec_any_lt(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p
+ res_i = vec_any_lt(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p
+ res_i = vec_any_lt(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p
+ res_i = vec_any_lt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_nan */
+ res_i = vec_any_nan(vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_any_ne */
+ res_i = vec_any_ne(vsc, vsc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_any_ne(vuc, vuc); // CHECK: @llvm.ppc.altivec.vcmpequb.p
+ res_i = vec_any_ne(vs, vs); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_any_ne(vus, vus); // CHECK: @llvm.ppc.altivec.vcmpequh.p
+ res_i = vec_any_ne(vi, vi); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_any_ne(vui, vui); // CHECK: @llvm.ppc.altivec.vcmpequw.p
+ res_i = vec_any_ne(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_any_nge */
+ res_i = vec_any_nge(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp.p
+
+ /* vec_any_ngt */
+ res_i = vec_any_ngt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_nle */
+ res_i = vec_any_nle(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgefp.p
+
+ /* vec_any_nlt */
+ res_i = vec_any_nlt(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p
+
+ /* vec_any_numeric */
+ res_i = vec_any_numeric(vf); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p
+
+ /* vec_any_out */
+ res_i = vec_any_out(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpbfp.p
+
+ return 0;
+}
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
new file mode 100644
index 000000000000..fef1587fad00
--- /dev/null
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fcatch-undefined-behavior -emit-llvm-only %s
+
+// PR6805
+void foo() {
+ union { int i; } u;
+ u.i=1;
+}
diff --git a/test/CodeGen/const-unordered-compare.c b/test/CodeGen/const-unordered-compare.c
new file mode 100644
index 000000000000..ac7d35bcd542
--- /dev/null
+++ b/test/CodeGen/const-unordered-compare.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// Checks folding of an unordered comparison
+int nan_ne_check() {
+ // CHECK: store i32 1
+ return (__builtin_nanf("") != __builtin_nanf("")) ? 1 : 0;
+}
diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c
index 6d068134b589..7ffb7006b05b 100644
--- a/test/CodeGen/decl.c
+++ b/test/CodeGen/decl.c
@@ -1,10 +1,14 @@
-// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -w -emit-llvm < %s | FileCheck %s
// CHECK: @test1.x = internal constant [12 x i32] [i32 1
// CHECK: @test2.x = internal constant [13 x i32] [i32 1,
// CHECK: @test5w = global %0 { i32 2, [4 x i8] undef }
// CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 }
+// CHECK: @test6.x = internal constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
+
+// CHECK: @test7 = global [2 x %struct.test7s] [%struct.test7s { i32 1, i32 2 }, %struct.test7s { i32 4, i32 0 }]
+
void test1() {
// This should codegen as a "@test1.x" global.
const int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23 };
@@ -59,3 +63,29 @@ void test5() {
union test5u test5w = (union test5u)2;
union test5u test5y = (union test5u)73.0;
+
+
+// PR6660 - sqlite miscompile
+struct SelectDest {
+ unsigned char eDest;
+ unsigned char affinity;
+ int iParm;
+ int iMem;
+};
+
+void test6() {
+ struct SelectDest x = {1, 2, 3};
+ test6f(&x);
+}
+
+// rdar://7657600
+struct test7s { int a; int b; } test7[] = {
+ {1, 2},
+ {4},
+};
+
+// rdar://7872531
+#pragma pack(push, 2)
+struct test8s { int f0; char f1; } test8g = {};
+
+
diff --git a/test/CodeGen/designated-initializers.c b/test/CodeGen/designated-initializers.c
index 652238f06d56..49f57ad062c5 100644
--- a/test/CodeGen/designated-initializers.c
+++ b/test/CodeGen/designated-initializers.c
@@ -1,22 +1,37 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o %t
-// RUN: grep "{ i8\* null, i32 1024 }" %t
-// RUN: grep "i32 0, i32 22" %t
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
struct foo {
void *a;
int b;
};
+// CHECK: @u = global %union.anon zeroinitializer
union { int i; float f; } u = { };
-int main(int argc, char **argv)
-{
- union { int i; float f; } u2 = { };
- static struct foo foo = {
- .b = 1024,
- };
-}
+// CHECK: @u2 = global %0 { i32 0, [4 x i8] undef }
+union { int i; double f; } u2 = { };
+// CHECK: @u3 = global %1 zeroinitializer
+union { double f; int i; } u3 = { };
+
+// CHECK: @b = global [2 x i32] [i32 0, i32 22]
int b[2] = {
- [1] 22
+ [1] = 22
};
+
+int main(int argc, char **argv)
+{
+ // CHECK: internal global %struct.foo { i8* null, i32 1024 }
+ static struct foo foo = {
+ .b = 1024,
+ };
+
+ // CHECK: bitcast %union.anon* %u2
+ // CHECK: call void @llvm.memset
+ union { int i; float f; } u2 = { };
+
+ // CHECK-NOT: call void @llvm.memset
+ union { int i; float f; } u3;
+
+ // CHECK: ret i32
+}
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index 5629ef582a60..a2c692d0ce3e 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -47,3 +47,15 @@ void f7(float f, float g) {
// CHECK: define void @f7(float{{.*}}, float{{.*}})
// CHECK: call void @f6(float{{.*}}, float{{.*}})
}
+
+// PR6911 - incomplete function types
+struct Incomplete;
+void f8_callback(struct Incomplete);
+void f8_user(void (*callback)(struct Incomplete));
+void f8_test() {
+ f8_user(&f8_callback);
+// CHECK: define void @f8_test()
+// CHECK: call void @f8_user({{.*}}* bitcast (void ()* @f8_callback to {{.*}}*))
+// CHECK: declare void @f8_user({{.*}}*)
+// CHECK: declare void @f8_callback()
+}
diff --git a/test/CodeGen/global-init.c b/test/CodeGen/global-init.c
index e166fb44659d..351ca9e35ac7 100644
--- a/test/CodeGen/global-init.c
+++ b/test/CodeGen/global-init.c
@@ -12,19 +12,41 @@ int c __attribute__((weak))= 0;
// CHECK: @c = weak global i32 0
-
// Since this is marked const, it should get weak_odr linkage, since all
// definitions have to be the same.
// CHECK: @d = weak_odr constant i32 0
const int d __attribute__((weak))= 0;
+// PR6168 "too many undefs"
+struct ManyFields {
+ int a;
+ int b;
+ int c;
+ char d;
+ int e;
+ int f;
+};
+
+// CHECK: global %0 { i32 1, i32 2, i32 0, i8 0, i32 0, i32 0 }
+struct ManyFields FewInits = {1, 2};
+
+
+// PR6766
+// CHECK: @l = global %1 { [24 x i8] c"f\00\00\00o\00\00\00o\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", i32 1 }
+typedef __WCHAR_TYPE__ wchar_t;
+struct K {
+ wchar_t L[6];
+ int M;
+} l = { { L"foo" }, 1 };
+
+
+// CHECK: @yuv_types = global [4 x [6 x i8]] {{\[}}[6 x i8] c"4:0:0\00", [6 x i8] c"4:2:0\00", [6 x i8] c"4:2:2\00", [6 x i8] c"4:4:4\00"]
+char yuv_types[4][6]= {"4:0:0","4:2:0","4:2:2","4:4:4"};
// NOTE: tentative definitions are processed at the end of the translation unit.
// This shouldn't be emitted as common because it has an explicit section.
// rdar://7119244
-int b __attribute__((section("foo")));
-
// CHECK: @b = global i32 0, section "foo"
-
+int b __attribute__((section("foo")));
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index 13ffad173137..d48e723c58a1 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o %t
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
void f1() {
// Scalars in braces.
@@ -22,8 +22,8 @@ void f3() {
}
// Constants
-// RUN: grep '@g3 = constant i32 10' %t
-// RUN: grep '@f4.g4 = internal constant i32 12' %t
+// CHECK: @g3 = constant i32 10
+// CHECK: @f4.g4 = internal constant i32 12
const int g3 = 10;
int f4() {
static const int g4 = 12;
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index a96176afe5be..828d7de6cb08 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -1,22 +1,52 @@
-// RUN: %clang_cc1 -fmath-errno -emit-llvm -o %t %s -triple i386-unknown-unknown
-// RUN: grep "declare " %t | count 6
-// RUN: grep "declare " %t | grep "@llvm." | count 1
-// RUN: %clang_cc1 -emit-llvm -o %t %s -triple i386-unknown-unknown
-// RUN: grep "declare " %t | count 6
-// RUN: grep "declare " %t | grep -v "@llvm." | count 0
-
-// IRgen only pays attention to const; it should always call llvm for
-// this.
-float sqrtf(float) __attribute__((const));
+// RUN: %clang_cc1 -fmath-errno -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix YES %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix NO %s
+// CHECK-YES: define void @test_sqrt
+// CHECK-NO: define void @test_sqrt
void test_sqrt(float a0, double a1, long double a2) {
+ // Following llvm-gcc's lead, we never emit these as intrinsics;
+ // no-math-errno isn't good enough. We could probably use intrinsics
+ // with appropriate guards if it proves worthwhile.
+
+ // CHECK-YES: call float @sqrtf
+ // CHECK-NO: call float @sqrtf
float l0 = sqrtf(a0);
+
+ // CHECK-YES: call double @sqrt
+ // CHECK-NO: call double @sqrt
double l1 = sqrt(a1);
+
+ // CHECK-YES: call x86_fp80 @sqrtl
+ // CHECK-NO: call x86_fp80 @sqrtl
long double l2 = sqrtl(a2);
}
+// CHECK-YES: declare float @sqrtf(float)
+// CHECK-YES: declare double @sqrt(double)
+// CHECK-YES: declare x86_fp80 @sqrtl(x86_fp80)
+// CHECK-NO: declare float @sqrtf(float) readnone
+// CHECK-NO: declare double @sqrt(double) readnone
+// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) readnone
+
+// CHECK-YES: define void @test_pow
+// CHECK-NO: define void @test_pow
void test_pow(float a0, double a1, long double a2) {
+ // CHECK-YES: call float @powf
+ // CHECK-NO: call float @llvm.pow.f32
float l0 = powf(a0, a0);
+
+ // CHECK-YES: call double @pow
+ // CHECK-NO: call double @llvm.pow.f64
double l1 = pow(a1, a1);
+
+ // CHECK-YES: call x86_fp80 @powl
+ // CHECK-NO: call x86_fp80 @llvm.pow.f80
long double l2 = powl(a2, a2);
}
+
+// CHECK-YES: declare float @powf(float, float)
+// CHECK-YES: declare double @pow(double, double)
+// CHECK-YES: declare x86_fp80 @powl(x86_fp80, x86_fp80)
+// CHECK-NO: declare float @llvm.pow.f32(float, float) nounwind readonly
+// CHECK-NO: declare double @llvm.pow.f64(double, double) nounwind readonly
+// CHECK-NO: declare x86_fp80 @llvm.pow.f80(x86_fp80, x86_fp80) nounwind readonly
diff --git a/test/CodeGen/palignr.c b/test/CodeGen/palignr.c
index 627e309bd940..6297b2e990f4 100644
--- a/test/CodeGen/palignr.c
+++ b/test/CodeGen/palignr.c
@@ -1,13 +1,9 @@
// RUN: %clang_cc1 %s -triple=i686-apple-darwin -target-feature +ssse3 -O1 -S -o - | FileCheck %s
#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
-#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8)))
-typedef __attribute__((vector_size(8))) int int2;
typedef __attribute__((vector_size(16))) int int4;
// CHECK: palignr
-int2 mmx_align1(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 7); }
-// CHECK: palignr
int4 align1(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 15); }
// CHECK: ret
// CHECK: ret
@@ -17,3 +13,18 @@ int4 align2(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 16); }
int4 align3(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 17); }
// CHECK: xor
int4 align4(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 32); }
+
+#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n)))
+typedef __attribute__((vector_size(8))) int int2;
+
+// CHECK-NOT: palignr
+int2 align5(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 8); }
+
+// CHECK: psrlq
+int2 align6(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 9); }
+
+// CHECK: xor
+int2 align7(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 16); }
+
+// CHECK: palignr
+int2 align8(int2 a, int2 b) { return _mm_alignr_pi8(a, b, 7); } \ No newline at end of file
diff --git a/test/CodeGen/struct-passing.c b/test/CodeGen/struct-passing.c
index b351d8148e91..409d14e22d39 100644
--- a/test/CodeGen/struct-passing.c
+++ b/test/CodeGen/struct-passing.c
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o %t %s
// RUN: grep 'declare i32 @f0() readnone$' %t
// RUN: grep 'declare i32 @f1() readonly$' %t
-// RUN: grep 'declare void @f2(.* noalias sret)$' %t
-// RUN: grep 'declare void @f3(.* noalias sret)$' %t
+// RUN: grep 'declare void @f2(.* sret)$' %t
+// RUN: grep 'declare void @f3(.* sret)$' %t
// RUN: grep 'declare void @f4(.* byval)$' %t
// RUN: grep 'declare void @f5(.* byval)$' %t
// PR3835
diff --git a/test/CodeGen/union-init2.c b/test/CodeGen/union-init2.c
index ac469cd4b512..1386c27cc0bd 100644
--- a/test/CodeGen/union-init2.c
+++ b/test/CodeGen/union-init2.c
@@ -1,4 +1,13 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | grep "bitcast (%0\* @r to %union.x\*), \[4 x i8\] undef"
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s
// Make sure we generate something sane instead of a ptrtoint
+// CHECK: bitcast (%0* @r to %union.x*), [4 x i8] undef
union x {long long b;union x* a;} r = {.a = &r};
+
+
+// CHECK: global %1 { [3 x i8] zeroinitializer, [5 x i8] undef }
+union z {
+ char a[3];
+ long long b;
+};
+union z y = {};
diff --git a/test/CodeGen/x86_32-arguments.c b/test/CodeGen/x86_32-arguments.c
index eb98e1a2282a..01c3e236f3bd 100644
--- a/test/CodeGen/x86_32-arguments.c
+++ b/test/CodeGen/x86_32-arguments.c
@@ -1,45 +1,45 @@
// RUN: %clang_cc1 -fblocks -triple i386-apple-darwin9 -emit-llvm -o %t %s
-// RUN: grep 'define signext i8 @f0()' %t
-// RUN: grep 'define signext i16 @f1()' %t
-// RUN: grep 'define i32 @f2()' %t
-// RUN: grep 'define float @f3()' %t
-// RUN: grep 'define double @f4()' %t
-// RUN: grep 'define x86_fp80 @f5()' %t
-// RUN: grep 'define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8\* %a4)' %t
-// RUN: grep 'define void @f7(i32 %a0)' %t
-// RUN: grep 'define i64 @f8_1()' %t
-// RUN: grep 'define void @f8_2(i32 %a0.0, i32 %a0.1)' %t
+// RUN: FileCheck < %t %s
+// CHECK: define signext i8 @f0()
char f0(void) {
return 0;
}
+// CHECK: define signext i16 @f1()
short f1(void) {
return 0;
}
+// CHECK: define i32 @f2()
int f2(void) {
return 0;
}
+// CHECK: define float @f3()
float f3(void) {
return 0;
}
+// CHECK: define double @f4()
double f4(void) {
return 0;
}
+// CHECK: define x86_fp80 @f5()
long double f5(void) {
return 0;
}
+// CHECK: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
void f6(char a0, short a1, int a2, long long a3, void *a4) {}
-typedef enum { A, B, C } E;
-
-void f7(E a0) {}
+// CHECK: define void @f7(i32 %a0)
+typedef enum { A, B, C } e7;
+void f7(e7 a0) {}
+// CHECK: define i64 @f8_1()
+// CHECK: define void @f8_2(i32 %a0.0, i32 %a0.1)
struct s8 {
int a;
int b;
@@ -49,11 +49,11 @@ void f8_2(struct s8 a0) {}
// This should be passed just as s8.
-// RUN: grep 'define i64 @f9_1()' %t
+// CHECK: define i64 @f9_1()
// FIXME: llvm-gcc expands this, this may have some value for the
// backend in terms of optimization but doesn't change the ABI.
-// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t
+// CHECK: define void @f9_2(%struct.s9* byval %a0)
struct s9 {
int a : 17;
int b;
@@ -63,7 +63,7 @@ void f9_2(struct s9 a0) {}
// Return of small structures and unions
-// RUN: grep 'float @f10()' %t
+// CHECK: float @f10()
struct s10 {
union { };
float f;
@@ -71,12 +71,12 @@ struct s10 {
// Small vectors and 1 x {i64,double} are returned in registers
-// RUN: grep 'i32 @f11()' %t
-// RUN: grep -F 'void @f12(<2 x i32>* noalias sret %agg.result)' %t
-// RUN: grep 'i64 @f13()' %t
-// RUN: grep 'i64 @f14()' %t
-// RUN: grep '<2 x i64> @f15()' %t
-// RUN: grep '<2 x i64> @f16()' %t
+// CHECK: i32 @f11()
+// CHECK: void @f12(<2 x i32>* sret %agg.result)
+// CHECK: i64 @f13()
+// CHECK: i64 @f14()
+// CHECK: <2 x i64> @f15()
+// CHECK: <2 x i64> @f16()
typedef short T11 __attribute__ ((vector_size (4)));
T11 f11(void) { while (1) {} }
typedef int T12 __attribute__ ((vector_size (8)));
@@ -93,12 +93,12 @@ T16 f16(void) { while (1) {} }
// And when the single element in a struct (but not for 64 and
// 128-bits).
-// RUN: grep 'i32 @f17()' %t
-// RUN: grep -F 'void @f18(%2* noalias sret %agg.result)' %t
-// RUN: grep -F 'void @f19(%3* noalias sret %agg.result)' %t
-// RUN: grep -F 'void @f20(%4* noalias sret %agg.result)' %t
-// RUN: grep -F 'void @f21(%5* noalias sret %agg.result)' %t
-// RUN: grep -F 'void @f22(%6* noalias sret %agg.result)' %t
+// CHECK: i32 @f17()
+// CHECK: void @f18(%2* sret %agg.result)
+// CHECK: void @f19(%3* sret %agg.result)
+// CHECK: void @f20(%4* sret %agg.result)
+// CHECK: void @f21(%5* sret %agg.result)
+// CHECK: void @f22(%6* sret %agg.result)
struct { T11 a; } f17(void) { while (1) {} }
struct { T12 a; } f18(void) { while (1) {} }
struct { T13 a; } f19(void) { while (1) {} }
@@ -108,97 +108,109 @@ struct { T16 a; } f22(void) { while (1) {} }
// Single element structures are handled specially
-// RUN: grep -F 'float @f23()' %t
-// RUN: grep -F 'float @f24()' %t
-// RUN: grep -F 'float @f25()' %t
+// CHECK: float @f23()
+// CHECK: float @f24()
+// CHECK: float @f25()
struct { float a; } f23(void) { while (1) {} }
struct { float a[1]; } f24(void) { while (1) {} }
struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} }
// Small structures are handled recursively
-// RUN: grep -F 'i32 @f26()' %t
-// RUN: grep 'void @f27(%.truct.s27\* noalias sret %agg.result)' %t
+// CHECK: i32 @f26()
+// CHECK: void @f27(%struct.s27* sret %agg.result)
struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} }
struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} }
-// RUN: grep 'void @f28(%.truct.s28\* noalias sret %agg.result)' %t
+// CHECK: void @f28(%struct.s28* sret %agg.result)
struct s28 { int a; int b[]; } f28(void) { while (1) {} }
-// RUN: grep 'define i16 @f29()' %t
+// CHECK: define i16 @f29()
struct s29 { struct { } a[1]; char b; char c; } f29(void) { while (1) {} }
-// RUN: grep 'define i16 @f30()' %t
+// CHECK: define i16 @f30()
struct s30 { char a; char b : 4; } f30(void) { while (1) {} }
-// RUN: grep 'define float @f31()' %t
+// CHECK: define float @f31()
struct s31 { char : 0; float b; char : 0; } f31(void) { while (1) {} }
-// RUN: grep 'define i32 @f32()' %t
+// CHECK: define i32 @f32()
struct s32 { char a; unsigned : 0; } f32(void) { while (1) {} }
-// RUN: grep 'define float @f33()' %t
+// CHECK: define float @f33()
struct s33 { float a; long long : 0; } f33(void) { while (1) {} }
-// RUN: grep 'define float @f34()' %t
+// CHECK: define float @f34()
struct s34 { struct { int : 0; } a; float b; } f34(void) { while (1) {} }
-// RUN: grep 'define i16 @f35()' %t
+// CHECK: define i16 @f35()
struct s35 { struct { int : 0; } a; char b; char c; } f35(void) { while (1) {} }
-// RUN: grep 'define i16 @f36()' %t
+// CHECK: define i16 @f36()
struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while (1) {} }
-// RUN: grep 'define float @f37()' %t
+// CHECK: define float @f37()
struct s37 { float c[1][1]; } f37(void) { while (1) {} }
-// RUN: grep 'define void @f38(.struct.s38. noalias sret .agg.result)' %t
+// CHECK: define void @f38(%struct.s38* sret %agg.result)
struct s38 { char a[3]; short b; } f38(void) { while (1) {} }
-// RUN: grep 'define void @f39(.struct.s39. byval align 16 .x)' %t
+// CHECK: define void @f39(%struct.s39* byval align 16 %x)
typedef int v39 __attribute((vector_size(16)));
struct s39 { v39 x; };
void f39(struct s39 x) {}
// <rdar://problem/7247671>
-// RUN: grep 'define i32 @f40()' %t
+// CHECK: define i32 @f40()
enum e40 { ec0 = 0 };
enum e40 f40(void) { }
-// RUN: grep 'define void ()\* @f41()' %t
+// CHECK: define void ()* @f41()
typedef void (^vvbp)(void);
vvbp f41(void) { }
-// RUN: grep 'define i32 @f42()' %t
+// CHECK: define i32 @f42()
struct s42 { enum e40 f0; } f42(void) { }
-// RUN: grep 'define i64 @f43()' %t
+// CHECK: define i64 @f43()
struct s43 { enum e40 f0; int f1; } f43(void) { }
-// RUN: grep 'define i32 @f44()' %t
+// CHECK: define i32 @f44()
struct s44 { vvbp f0; } f44(void) { }
-// RUN: grep 'define i64 @f45()' %t
+// CHECK: define i64 @f45()
struct s45 { vvbp f0; int f1; } f45(void) { }
-// RUN: grep 'define void @f46(i32 %a0)' %t
+// CHECK: define void @f46(i32 %a0)
void f46(enum e40 a0) { }
-// RUN: grep 'define void @f47(void ()\* %a1)' %t
+// CHECK: define void @f47(void ()* %a1)
void f47(vvbp a1) { }
-// RUN: grep 'define void @f48(i32 %a0.0)' %t
+// CHECK: define void @f48(i32 %a0.0)
struct s48 { enum e40 f0; };
void f48(struct s48 a0) { }
-// RUN: grep 'define void @f49(i32 %a0.0, i32 %a0.1)' %t
+// CHECK: define void @f49(i32 %a0.0, i32 %a0.1)
struct s49 { enum e40 f0; int f1; };
void f49(struct s49 a0) { }
-// RUN: grep 'define void @f50(void ()\* %a0.0)' %t
+// CHECK: define void @f50(void ()* %a0.0)
struct s50 { vvbp f0; };
void f50(struct s50 a0) { }
-// RUN: grep 'define void @f51(void ()\* %a0.0, i32 %a0.1)' %t
+// CHECK: define void @f51(void ()* %a0.0, i32 %a0.1)
struct s51 { vvbp f0; int f1; };
void f51(struct s51 a0) { }
+// CHECK: define void @f52(%struct.s52* byval align 16 %x)
+struct s52 {
+ long double a;
+};
+void f52(struct s52 x) {}
+
+// CHECK: define void @f53(%struct.s53* byval align 32 %x)
+struct __attribute__((aligned(32))) s53 {
+ int x;
+ int y;
+};
+void f53(struct s53 x) {}
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index d6b9b2936045..47b2eb1585e2 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -1,49 +1,51 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o %t %s
-// RUN: grep 'define signext i8 @f0()' %t
-// RUN: grep 'define signext i16 @f1()' %t
-// RUN: grep 'define i32 @f2()' %t
-// RUN: grep 'define float @f3()' %t
-// RUN: grep 'define double @f4()' %t
-// RUN: grep 'define x86_fp80 @f5()' %t
-// RUN: grep 'define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8\* %a4)' %t
-// RUN: grep 'define void @f7(i32 %a0)' %t
-// RUN: grep '.0 = type { i64, double }' %t
-// RUN: grep 'define .0 @f8_1()' %t
-// RUN: grep 'define void @f8_2(.0)' %t
+// RUN: FileCheck < %t %s
+// CHECK: %0 = type { i64, double }
+
+// CHECK: define signext i8 @f0()
char f0(void) {
return 0;
}
+// CHECK: define signext i16 @f1()
short f1(void) {
return 0;
}
+// CHECK: define i32 @f2()
int f2(void) {
return 0;
}
+// CHECK: define float @f3()
float f3(void) {
return 0;
}
+// CHECK: define double @f4()
double f4(void) {
return 0;
}
+// CHECK: define x86_fp80 @f5()
long double f5(void) {
return 0;
}
+// CHECK: define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8* %a4)
void f6(char a0, short a1, int a2, long long a3, void *a4) {
}
-typedef enum { A, B, C } E;
-
-void f7(E a0) {
+// CHECK: define void @f7(i32 %a0)
+typedef enum { A, B, C } e7;
+void f7(e7 a0) {
}
// Test merging/passing of upper eightbyte with X87 class.
+//
+// CHECK: define %0 @f8_1()
+// CHECK: define void @f8_2(%0)
union u8 {
long double a;
int b;
@@ -51,48 +53,63 @@ union u8 {
union u8 f8_1() { while (1) {} }
void f8_2(union u8 a0) {}
-// RUN: grep 'define i64 @f9()' %t
+// CHECK: define i64 @f9()
struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} }
-// RUN: grep 'define void @f10(i64)' %t
+// CHECK: define void @f10(i64)
struct s10 { int a; int b; int : 0; };
void f10(struct s10 a0) {}
-// RUN: grep 'define void @f11(.union.anon. noalias sret .agg.result)' %t
+// CHECK: define void @f11(%struct.s19* sret %agg.result)
union { long double a; float b; } f11() { while (1) {} }
-// RUN: grep 'define i64 @f12_0()' %t
-// RUN: grep 'define void @f12_1(i64)' %t
+// CHECK: define i64 @f12_0()
+// CHECK: define void @f12_1(i64)
struct s12 { int a __attribute__((aligned(16))); };
struct s12 f12_0(void) { while (1) {} }
void f12_1(struct s12 a0) {}
// Check that sret parameter is accounted for when checking available integer
// registers.
-// RUN: grep 'define void @f13(.struct.s13_0. noalias sret .agg.result, i32 .a, i32 .b, i32 .c, i32 .d, .struct.s13_1. byval .e, i32 .f)' %t
+// CHECK: define void @f13(%struct.s13_0* sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, %struct.s13_1* byval %e, i32 %f)
struct s13_0 { long long f0[3]; };
struct s13_1 { long long f0[2]; };
-struct s13_0 f13(int a, int b, int c, int d,
+struct s13_0 f13(int a, int b, int c, int d,
struct s13_1 e, int f) { while (1) {} }
-// RUN: grep 'define void @f14(.*, i8 signext .X)' %t
-void f14(int a, int b, int c, int d, int e, int f,
- char X) {}
-// RUN: grep 'define void @f15(.*, i8\* .X)' %t
-void f15(int a, int b, int c, int d, int e, int f,
- void *X) {}
-// RUN: grep 'define void @f16(.*, float .X)' %t
+// CHECK: define void @f14({{.*}}, i8 signext %X)
+void f14(int a, int b, int c, int d, int e, int f, char X) {}
+
+// CHECK: define void @f15({{.*}}, i8* %X)
+void f15(int a, int b, int c, int d, int e, int f, void *X) {}
+
+// CHECK: define void @f16({{.*}}, float %X)
void f16(float a, float b, float c, float d, float e, float f, float g, float h,
float X) {}
-// RUN: grep 'define void @f17(.*, x86_fp80 .X)' %t
+
+// CHECK: define void @f17({{.*}}, x86_fp80 %X)
void f17(float a, float b, float c, float d, float e, float f, float g, float h,
long double X) {}
// Check for valid coercion.
-// RUN: grep '.. = bitcast i64. .* to .struct.f18_s0.' %t
-// RUN: grep '.. = load .struct.f18_s0. .., align 1' %t
-// RUN: grep 'store .struct.f18_s0 .., .struct.f18_s0. .f18_arg1' %t
+// CHECK: [[f18_t0:%.*]] = bitcast i64* {{.*}} to %struct.f18_s0*
+// CHECK: [[f18_t1:%.*]] = load %struct.f18_s0* [[f18_t0]], align 1
+// CHECK: store %struct.f18_s0 [[f18_t1]], %struct.f18_s0* %f18_arg1
struct f18_s0 { int f0; };
void f18(int a, struct f18_s0 f18_arg1) { while (1) {} }
+// Check byval alignment.
+
+// CHECK: define void @f19(%struct.s19* byval align 16 %x)
+struct s19 {
+ long double a;
+};
+void f19(struct s19 x) {}
+
+// CHECK: define void @f20(%struct.s20* byval align 32 %x)
+struct __attribute__((aligned(32))) s20 {
+ int x;
+ int y;
+};
+void f20(struct s20 x) {}
diff --git a/test/CodeGenCXX/PR6747.cpp b/test/CodeGenCXX/PR6747.cpp
new file mode 100644
index 000000000000..5a07ce622013
--- /dev/null
+++ b/test/CodeGenCXX/PR6747.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+struct foo {
+ virtual void bar();
+// CHECK: define available_externally void @_ZN3foo3bazEv
+ virtual void baz() {}
+};
+void zed() {
+ foo b;
+ b.baz();
+}
diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp
index c5fa89d86d41..162c6e5754f3 100644
--- a/test/CodeGenCXX/address-of-fntemplate.cpp
+++ b/test/CodeGenCXX/address-of-fntemplate.cpp
@@ -11,3 +11,17 @@ void test() {
}
// CHECK: define linkonce_odr void @_Z1fIiEvT_
// CHECK: define linkonce_odr void @_Z1fIiEvv
+
+namespace PR6973 {
+ template<typename T>
+ struct X {
+ void f(const T&);
+ };
+
+ template<typename T>
+ int g();
+
+ void h(X<int (*)()> xf) {
+ xf.f(&g<int>);
+ }
+}
diff --git a/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
index ea3eafc99553..adb395021e73 100644
--- a/test/CodeGenCXX/anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/anonymous-union-member-initializer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s
struct A {
union {
@@ -10,3 +10,27 @@ struct A {
};
A a;
+
+namespace PR7021 {
+ struct X
+ {
+ union { long l; };
+ };
+
+ // CHECK: define void @_ZN6PR70211fENS_1XES0_
+ void f(X x, X z) {
+ X x1;
+
+ // CHECK: store i64 1, i64
+ x1.l = 1;
+
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
+ X x2(x1);
+
+ X x3;
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
+ x3 = x1;
+
+ // CHECK: ret void
+ }
+}
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
new file mode 100644
index 000000000000..5cca7885b7d7
--- /dev/null
+++ b/test/CodeGenCXX/arm.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - | FileCheck %s
+
+class foo {
+public:
+ foo();
+ virtual ~foo();
+};
+
+class bar : public foo {
+public:
+ bar();
+};
+
+// The global dtor needs the right calling conv with -fno-use-cxa-atexit
+// rdar://7817590
+bar baz;
+
+// CHECK: @_GLOBAL__D_a()
+// CHECK: call arm_apcscc void @_ZN3barD1Ev(%class.bar* @baz)
+
diff --git a/test/CodeGenCXX/assign-operator.cpp b/test/CodeGenCXX/assign-operator.cpp
index cb8867f2f6a3..c4b64e6e51ad 100644
--- a/test/CodeGenCXX/assign-operator.cpp
+++ b/test/CodeGenCXX/assign-operator.cpp
@@ -1,9 +1,19 @@
-// RUN: %clang_cc1 %s -emit-llvm-only -verify
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -verify -o - |FileCheck %s
class x {
-int operator=(int);
+public: int operator=(int);
};
void a() {
x a;
a = 1u;
}
+
+void f(int i, int j) {
+ // CHECK: load i32
+ // CHECK: load i32
+ // CHECK: add nsw i32
+ // CHECK: store i32
+ // CHECK: store i32 17, i32
+ // CHECK: ret
+ (i += j) = 17;
+}
diff --git a/test/CodeGenCXX/bitfield-layout.cpp b/test/CodeGenCXX/bitfield-layout.cpp
new file mode 100644
index 000000000000..15f33d27658d
--- /dev/null
+++ b/test/CodeGenCXX/bitfield-layout.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP64 %s
+// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP32 %s
+
+// CHECK-LP64: %union.Test1 = type { i32, [4 x i8] }
+union Test1 {
+ int a;
+ int b: 39;
+} t1;
+
+// CHECK-LP64: %union.Test2 = type { i8 }
+union Test2 {
+ int : 6;
+} t2;
+
+// CHECK-LP64: %union.Test3 = type { [2 x i8] }
+union Test3 {
+ int : 9;
+} t3;
+
+
+#define CHECK(x) if (!(x)) return __LINE__
+
+int f() {
+ struct {
+ int a;
+
+ unsigned long long b : 65;
+
+ int c;
+ } c;
+
+ c.a = 0;
+ c.b = (unsigned long long)-1;
+ c.c = 0;
+
+ CHECK(c.a == 0);
+ CHECK(c.b == (unsigned long long)-1);
+ CHECK(c.c == 0);
+
+// CHECK-LP64: ret i32 0
+// CHECK-LP32: ret i32 0
+ return 0;
+}
diff --git a/test/CodeGenCXX/block-destruct.cpp b/test/CodeGenCXX/block-destruct.cpp
new file mode 100644
index 000000000000..f809ca2699de
--- /dev/null
+++ b/test/CodeGenCXX/block-destruct.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
+
+struct A { ~A(); };
+
+void f() {
+ __block A a;
+}
+
+// CHECK: call void @_ZN1AD1Ev
diff --git a/test/CodeGenCXX/c-linkage.cpp b/test/CodeGenCXX/c-linkage.cpp
new file mode 100644
index 000000000000..b1f07b7b7562
--- /dev/null
+++ b/test/CodeGenCXX/c-linkage.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// pr6644
+
+extern "C" {
+ namespace N {
+ struct X {
+ virtual void f();
+ };
+ void X::f() { }
+ }
+}
+
+// CHECK: define void @_ZN1N1X1fEv
diff --git a/test/CodeGenCXX/constructor-init-reference.cpp b/test/CodeGenCXX/constructor-init-reference.cpp
index c2f41e1f0cbf..5e7515976518 100644
--- a/test/CodeGenCXX/constructor-init-reference.cpp
+++ b/test/CodeGenCXX/constructor-init-reference.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -emit-llvm -o - %s | grep "store i32\* @x, i32\*\*"
int x;
-class A {
+struct A {
int& y;
A() : y(x) {}
};
diff --git a/test/CodeGenCXX/constructors.cpp b/test/CodeGenCXX/constructors.cpp
index 2c95c91e1114..a8dc7fcec703 100644
--- a/test/CodeGenCXX/constructors.cpp
+++ b/test/CodeGenCXX/constructors.cpp
@@ -12,7 +12,7 @@ struct ValueClass {
/* Test basic functionality. */
-class A {
+struct A {
A(struct Undeclared &);
A(ValueClass);
Member mem;
@@ -92,3 +92,15 @@ D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {}
// CHECK: call void @_ZN10ValueClassC1Eii(
// CHECK: call void @_ZN1AC2E10ValueClass(
// CHECK: call void @_ZN6MemberC1Ei(
+
+
+// PR6622: this shouldn't crash
+namespace test0 {
+ struct A {};
+ struct B : virtual A { int x; };
+ struct C : B {};
+
+ void test(C &in) {
+ C tmp = in;
+ }
+}
diff --git a/test/CodeGenCXX/default-arg-temps.cpp b/test/CodeGenCXX/default-arg-temps.cpp
index e523eb0cfd23..e4a06770cd9b 100644
--- a/test/CodeGenCXX/default-arg-temps.cpp
+++ b/test/CodeGenCXX/default-arg-temps.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t -triple=x86_64-apple-darwin9
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
struct T {
T();
@@ -13,20 +13,62 @@ public:
X(const X&, const T& t = T());
};
+// CHECK: define void @_Z1gv()
void g() {
- // RUN: grep "call void @_ZN1TC1Ev" %t | count 4
- // RUN: grep "call void @_ZN1TD1Ev" %t | count 4
+ // CHECK: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG1:%.*]])
+ // CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG1]])
+ // CHECK-NEXT: call void @_ZN1TD1Ev([[T]]* [[AGG1]])
f();
+
+ // CHECK-NEXT: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG2:%.*]])
+ // CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG2]])
+ // CHECK-NEXT: call void @_ZN1TD1Ev([[T]]* [[AGG2]])
f();
+ // CHECK-NEXT: call void @_ZN1XC1Ev(
X a;
+
+ // CHECK-NEXT: call void @_ZN1TC1Ev(
+ // CHECK-NEXT: call void @_ZN1XC1ERKS_RK1T(
+ // CHECK-NEXT: call void @_ZN1TD1Ev(
X b(a);
+
+ // CHECK-NEXT: call void @_ZN1TC1Ev(
+ // CHECK-NEXT: call void @_ZN1XC1ERKS_RK1T(
+ // CHECK-NEXT: call void @_ZN1TD1Ev(
X c = a;
}
-// RUN: grep memset %t
class obj{ int a; float b; double d; };
+// CHECK: define void @_Z1hv()
void h() {
+ // CHECK: call void @llvm.memset.p0i8.i64(
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(
obj o = obj();
}
+
+// PR7028 - mostly this shouldn't crash
+namespace test1 {
+ struct A { A(); };
+ struct B { B(); ~B(); };
+
+ struct C {
+ C(const B &file = B());
+ };
+ C::C(const B &file) {}
+
+ struct D {
+ C c;
+ A a;
+
+ // CHECK: define linkonce_odr void @_ZN5test11DC2Ev(
+ // CHECK: call void @_ZN5test11BC1Ev(
+ // CHECK-NEXT: call void @_ZN5test11CC1ERKNS_1BE(
+ // CHECK-NEXT: call void @_ZN5test11BD1Ev(
+ // CHECK: call void @_ZN5test11AC1Ev(
+ D() : c(), a() {}
+ };
+
+ D d;
+}
diff --git a/test/CodeGenCXX/default-destructor-nested.cpp b/test/CodeGenCXX/default-destructor-nested.cpp
index 86942743d4e1..565a7279c56e 100644
--- a/test/CodeGenCXX/default-destructor-nested.cpp
+++ b/test/CodeGenCXX/default-destructor-nested.cpp
@@ -2,7 +2,7 @@
// PR6294
class A {
- virtual ~A();
+public: virtual ~A();
};
class B {
class C;
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 7cc264f5c5f5..87f8698b84c3 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o %t
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
void t1(int *a) {
delete a;
@@ -19,8 +19,11 @@ struct T {
int a;
};
+// CHECK: define void @_Z2t4P1T
void t4(T *t) {
- // RUN: grep "call void @_ZN1TD1Ev" %t | count 1
+ // CHECK: call void @_ZN1TD1Ev
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @_ZdlPv
delete t;
}
@@ -35,3 +38,22 @@ void f() {
delete a;
}
+
+namespace test0 {
+ struct A {
+ void *operator new(__SIZE_TYPE__ sz);
+ void operator delete(void *p) { ::operator delete(p); }
+ ~A() {}
+ };
+
+ // CHECK: define void @_ZN5test04testEPNS_1AE(
+ void test(A *a) {
+ // CHECK: call void @_ZN5test01AD1Ev
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @_ZN5test01AdlEPv
+ delete a;
+ }
+
+ // CHECK: define linkonce_odr void @_ZN5test01AD1Ev
+ // CHECK: define linkonce_odr void @_ZN5test01AdlEPv
+}
diff --git a/test/CodeGenCXX/destructor-debug-info.cpp b/test/CodeGenCXX/destructor-debug-info.cpp
new file mode 100644
index 000000000000..9e32275d3394
--- /dev/null
+++ b/test/CodeGenCXX/destructor-debug-info.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -g -S -emit-llvm -o %t %s
+// RUN: grep "i32 20, i32 3, metadata" %t | count 1
+// Check there is a line number entry for line 20 where b1 is destructed.
+class A { int a; };
+class B {
+public:
+ B() { a = new A; }
+ ~B() { delete a; }
+private:
+ A *a;
+};
+
+void fn(B b);
+
+int i;
+void foo() {
+ if (i) {
+ B b1;
+ fn (b1);
+ }
+}
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index afd9da698646..f2629d19d902 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
+// RUN: %clang_cc1 -fexceptions -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s
struct test1_D {
@@ -9,14 +9,18 @@ void test1() {
throw d1;
}
-// CHECK: define void @_Z5test1v() nounwind {
-// CHECK: %{{exception.ptr|1}} = alloca i8*
-// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{exception.ptr|1}}
-// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test1_D*
-// CHECK-NEXT: %{{tmp|4}} = bitcast %struct.test1_D* %{{0|3}} to i8*
-// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{tmp|4}}, i8* bitcast (%struct.test1_D* @d1 to i8*), i64 8, i32 8, i1 false)
-// CHECK-NEXT: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
+// CHECK: define void @_Z5test1v()
+// CHECK: [[FREEVAR:%.*]] = alloca i1
+// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
+// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
+// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
+// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false)
+// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -31,14 +35,19 @@ void test2() {
throw d2;
}
-// CHECK: define void @_Z5test2v() nounwind {
-// CHECK: %{{exception.ptr|1}} = alloca i8*
-// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 16)
-// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{\1}}
-// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test2_D*
-// CHECK: invoke void @_ZN7test2_DC1ERKS_(%struct.test2_D* %{{0|3}}, %struct.test2_D* @d2)
-// CHECK-NEXT: to label %{{invoke.cont|8}} unwind label %{{terminate.handler|4}}
-// CHECK: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%{{0|3}}* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK: define void @_Z5test2v()
+// CHECK: [[FREEVAR:%.*]] = alloca i1
+// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
+// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
+// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
+// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
+// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
+// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}}
+// : [[CONT]]: (can't check this in Release-Asserts builds)
+// CHECK: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -52,20 +61,46 @@ void test3() {
throw (volatile test3_D *)0;
}
-// CHECK: define void @_Z5test3v() nounwind {
-// CHECK: %{{exception.ptr|1}} = alloca i8*
-// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{exception.ptr|1}}
-// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test3_D**
-// CHECK-NEXT: store %struct.test3_D* null, %struct.test3_D**
-// CHECK-NEXT: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
-// CHECK-NEXT: unreachable
+// CHECK: define void @_Z5test3v()
+// CHECK: [[FREEVAR:%.*]] = alloca i1
+// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
+// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
+// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
+// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSS:%[^*]*\*]]*
+// CHECK-NEXT: store [[DSS]] null, [[DSS]]* [[EXN]]
+// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
+// CHECK-NEXT: unreachable
void test4() {
throw;
}
-// CHECK: define void @_Z5test4v() nounwind {
+// CHECK: define void @_Z5test4v()
// CHECK: call void @__cxa_rethrow() noreturn
// CHECK-NEXT: unreachable
+
+
+// rdar://problem/7696549
+namespace test5 {
+ struct A {
+ A();
+ A(const A&);
+ ~A();
+ };
+
+ void test() {
+ try { throw A(); } catch (A &x) {}
+ }
+// CHECK: define void @_ZN5test54testEv()
+// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1)
+// CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]*
+// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]])
+// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn
+// CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]]
+// : [[HANDLER]]: (can't check this in Release-Asserts builds)
+// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*))
+}
diff --git a/test/CodeGenCXX/empty-classes.cpp b/test/CodeGenCXX/empty-classes.cpp
new file mode 100644
index 000000000000..59124e3d55b2
--- /dev/null
+++ b/test/CodeGenCXX/empty-classes.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
+
+struct Empty { };
+
+struct A {
+ explicit A(unsigned a = 0xffffffff) : a(a) { }
+
+ unsigned a;
+};
+
+struct B : A, Empty {
+ B() : A(), Empty() { }
+};
+
+struct C : A, Empty {
+ C() : A(), Empty() { }
+ C(const C& other) : A(0x12345678), Empty(other) { }
+};
+
+struct D : A, Empty {
+ D& operator=(const D& other) {
+ a = 0x87654321;
+ Empty::operator=(other);
+
+ return *this;
+ }
+};
+
+#define CHECK(x) if (!(x)) return __LINE__
+
+// PR7012
+// CHECK: define i32 @_Z1fv()
+int f() {
+ B b1;
+
+ // Check that A::a is not overwritten by the Empty default constructor.
+ CHECK(b1.a == 0xffffffff);
+
+ C c1;
+ C c2(c1);
+
+ // Check that A::a has the value set in the C::C copy constructor.
+ CHECK(c2.a == 0x12345678);
+
+ D d1, d2;
+ d2 = d1;
+
+ // Check that A::as has the value set in the D copy assignment operator.
+ CHECK(d2.a == 0x87654321);
+
+ // Success!
+ // CHECK: ret i32 0
+ return 0;
+}
+
+#ifdef HARNESS
+extern "C" void printf(const char *, ...);
+
+int main() {
+ int result = f();
+
+ if (result == 0)
+ printf("success!\n");
+ else
+ printf("test on line %d failed!\n", result);
+
+ return result;
+}
+#endif
diff --git a/test/CodeGenCXX/exceptions-no-rtti.cpp b/test/CodeGenCXX/exceptions-no-rtti.cpp
new file mode 100644
index 000000000000..c26abb26af9c
--- /dev/null
+++ b/test/CodeGenCXX/exceptions-no-rtti.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fno-rtti -fexceptions %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: @_ZTIN5test11AE = weak_odr constant
+// CHECK: @_ZTIN5test11BE = weak_odr constant
+// CHECK: @_ZTIN5test11CE = weak_odr constant
+// CHECK: @_ZTIN5test11DE = weak_odr constant
+// CHECK: @_ZTIPN5test11DE = weak_odr constant {{.*}} @_ZTIN5test11DE
+
+// PR6974: this shouldn't crash
+namespace test0 {
+ class err {};
+
+ void f(void) {
+ try {
+ } catch (err &) {
+ }
+ }
+}
+
+namespace test1 {
+ // These classes have key functions defined out-of-line.
+ // Under normal circumstances, we wouldn't generate RTTI for them;
+ // under -fno-rtti, we generate RTTI only when required by EH.
+ class A { virtual void foo(); };
+ class B { virtual void foo(); };
+ class C { virtual void foo(); };
+ class D { virtual void foo(); };
+
+ void opaque();
+
+ void test0() {
+ throw A();
+ }
+
+ void test1() throw(B) {
+ opaque();
+ }
+
+ void test2() {
+ try {
+ opaque();
+ } catch (C&) {}
+ }
+
+ void test3(D *ptr) {
+ throw ptr;
+ };
+}
diff --git a/test/CodeGenCXX/field-access-debug-info.cpp b/test/CodeGenCXX/field-access-debug-info.cpp
new file mode 100644
index 000000000000..907fe04be57d
--- /dev/null
+++ b/test/CodeGenCXX/field-access-debug-info.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -g -S -masm-verbose -o %t %s
+// RUN: grep DW_AT_accessibility %t
+
+class A {
+public:
+ int p;
+private:
+ int pr;
+};
+
+A a;
diff --git a/test/CodeGenCXX/implicit-copy-assign-operator.cpp b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
new file mode 100644
index 000000000000..0ec89fceec5b
--- /dev/null
+++ b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s
+struct A {
+ A &operator=(const A&);
+ A &operator=(A&);
+};
+
+struct B {
+ B &operator=(B&);
+};
+
+struct C {
+ virtual C& operator=(const C&);
+};
+
+struct POD {
+ int array[3][4];
+};
+
+struct CopyByValue {
+ CopyByValue(const CopyByValue&);
+ CopyByValue &operator=(CopyByValue);
+};
+
+struct D : A, B, virtual C {
+ int scalar;
+ int scalar_array[2][3];
+ B class_member;
+ C class_member_array[2][3];
+ POD pod_array[2][3];
+
+ union {
+ int x;
+ float f[3];
+ };
+
+ CopyByValue by_value;
+};
+
+void test_D(D d1, D d2) {
+ d1 = d2;
+}
+
+// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_
+// CHECK: {{call.*_ZN1AaSERS_}}
+// CHECK: {{call.*_ZN1BaSERS_}}
+// CHECK: {{call.*_ZN1CaSERKS_}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: {{call.*_ZN1BaSERS_}}
+// CHECK: br
+// CHECK: {{call.*_ZN1CaSERKS_}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: call void @_ZN11CopyByValueC1ERKS_
+// CHECK: {{call.*_ZN11CopyByValueaSES_}}
+// CHECK: ret
+
diff --git a/test/CodeGenCXX/instantiate-init-list.cpp b/test/CodeGenCXX/instantiate-init-list.cpp
index 676d2994e7ed..49c6f51c7751 100644
--- a/test/CodeGenCXX/instantiate-init-list.cpp
+++ b/test/CodeGenCXX/instantiate-init-list.cpp
@@ -5,7 +5,7 @@ struct F {
};
void G();
template<class T> class A {
- A();
+public: A();
};
template<class T> A<T>::A() {
static F f = { G };
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
index 22949da64ad8..6a2994407167 100644
--- a/test/CodeGenCXX/mangle-template.cpp
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -104,3 +104,43 @@ namespace test8 {
// CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE
template void f<int>(int_c<sizeof(int)>);
}
+
+namespace test9 {
+ template<typename T>
+ struct supermeta {
+ template<typename U>
+ struct apply {
+ typedef T U::*type;
+ };
+ };
+
+ struct X { };
+
+ template<typename T, typename U>
+ typename supermeta<T>::template apply<U>::type f();
+
+ void test_f() {
+ // CHECK: @_ZN5test91fIiNS_1XEEENS_9supermetaIT_E5applyIT0_E4typeEv()
+ // Note: GCC incorrectly mangles this as
+ // _ZN5test91fIiNS_1XEEENS_9supermetaIT_E5apply4typeEv, while EDG
+ // gets it right.
+ f<int, X>();
+ }
+}
+
+namespace test10 {
+ template<typename T>
+ struct X {
+ template<typename U>
+ struct definition {
+ };
+ };
+
+ // CHECK: _ZN6test101fIidEENS_1XIT_E10definitionIT0_EES2_S5_
+ template<typename T, typename U>
+ typename X<T>::template definition<U> f(T, U) { }
+
+ void g(int i, double d) {
+ f(i, d);
+ }
+}
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index ec9c08c0ccaa..8f3d35684884 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -450,7 +450,7 @@ namespace test7 {
// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv
namespace test8 {
template <int &counter> class A { void inc() { counter++; } };
- class B { static int value; };
+ class B { public: static int value; };
template class A<B::value>;
}
// CHECK: declare void @_ZN5test91fIiNS_3barEEEvRKNT0_3baz1XE
@@ -468,3 +468,12 @@ namespace test9 {
f<int, bar>( 0);
}
}
+
+// <rdar://problem/7825453>
+namespace test10 {
+ template <char P1> struct S {};
+ template <char P2> void f(struct S<false ? 'a' : P2> ) {}
+
+ // CHECK: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE(
+ template void f<(char) 3>(struct S<3>);
+}
diff --git a/test/CodeGenCXX/member-function-pointer-calls.cpp b/test/CodeGenCXX/member-function-pointer-calls.cpp
index e1f2eb78d414..6f0ef81fe35d 100644
--- a/test/CodeGenCXX/member-function-pointer-calls.cpp
+++ b/test/CodeGenCXX/member-function-pointer-calls.cpp
@@ -9,18 +9,17 @@ int f(A* a, int (A::*fp)()) {
}
// CHECK: define i32 @_Z2g1v()
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: ret i32 1
int g1() {
A a;
-
- // CHECK: call i32 @_ZN1A3vf1Ev
- // CHECK-NEXT: ret i32
return f(&a, &A::vf1);
}
+// CHECK: define i32 @_Z2g2v()
+// CHECK-NEXT: {{.*}}:
+// CHECK-NEXT: ret i32 2
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 f7c445b1cb10..e4beee15bb17 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-apple-darwin9 | FileCheck -check-prefix LP32 %s
struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
struct B { int b; virtual void g(); };
@@ -12,10 +13,12 @@ void (C::*pc)();
// 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
+// CHECK: @pa3 = global %0 { i64 1, i64 0 }, align 8
+// CHECK-LP32: @pa3 = global %0 { i32 1, i32 0 }, align 4
void (A::*pa3)() = &A::vf1;
-// CHECK: @pa4 = global %0 { i64 9, i64 0 }, align 8
+// CHECK: @pa4 = global %0 { i64 9, i64 0 }, align 8
+// CHECK-LP32: @pa4 = global %0 { i32 5, i32 0 }, align 4
void (A::*pa4)() = &A::vf2;
// CHECK: @pc2 = global %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8
@@ -51,16 +54,24 @@ void f2() {
// CHECK: store i64 0, i64* [[pa2adj]]
void (A::*pa2)() = &A::f;
- // CHECK: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
- // 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]]
+ // CHECK: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
+ // 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]]
+ // CHECK-LP32: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
+ // CHECK-LP32: store i32 1, i32* [[pa3ptr]]
+ // CHECK-LP32: [[pa3adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 1
+ // CHECK-LP32: store i32 0, i32* [[pa3adj]]
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]]
+ // 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]]
+ // CHECK-LP32: [[pa4ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 0
+ // CHECK-LP32: store i32 5, i32* [[pa4ptr]]
+ // CHECK-LP32: [[pa4adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 1
+ // CHECK-LP32: store i32 0, i32* [[pa4adj]]
void (A::*pa4)() = &A::vf2;
}
@@ -173,3 +184,9 @@ namespace PR6258 {
void (A::*pf)(bool) = &A::f;
}
}
+
+// PR7027
+namespace PR7027 {
+ struct X { void test( ); };
+ void testX() { &X::test; }
+}
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
index 81dcee7e407a..244a164b9fe2 100644
--- a/test/CodeGenCXX/member-initializers.cpp
+++ b/test/CodeGenCXX/member-initializers.cpp
@@ -16,7 +16,7 @@ struct B : A {
int f() {
B b;
- // CHECK: call i32 @_ZN1B1fEv
+ // CHECK: ret i32 2
return b.i;
}
diff --git a/test/CodeGenCXX/namespace-aliases.cpp b/test/CodeGenCXX/namespace-aliases.cpp
index 74b8ebab4a54..8624eb75bf29 100644
--- a/test/CodeGenCXX/namespace-aliases.cpp
+++ b/test/CodeGenCXX/namespace-aliases.cpp
@@ -1,3 +1,9 @@
// RUN: %clang_cc1 -emit-llvm-only %s
namespace A { }
namespace B = A;
+
+namespace b {}
+
+void foo() {
+ namespace a = b;
+}
diff --git a/test/CodeGenCXX/new-operator-phi.cpp b/test/CodeGenCXX/new-operator-phi.cpp
index 38467ad31f9b..49859acf4fa6 100644
--- a/test/CodeGenCXX/new-operator-phi.cpp
+++ b/test/CodeGenCXX/new-operator-phi.cpp
@@ -2,7 +2,7 @@
// PR5454
#include <stddef.h>
-class X {static void * operator new(size_t size) throw(); X(int); };
+struct X {static void * operator new(size_t size) throw(); X(int); };
int a(), b();
void b(int x)
{
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index ca7c52f2cc0d..885158f8a054 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -90,9 +90,19 @@ A* t10() {
return new(1, 2, 3.45, 100) A;
}
-struct B { };
+struct B { int a; };
void t11() {
// CHECK: call noalias i8* @_Znwm
// CHECK: call void @llvm.memset.p0i8.i64(
B* b = new B();
}
+
+struct Empty { };
+
+// We don't need to initialize an empty class.
+void t12() {
+ // CHECK: define void @_Z3t12v
+ // CHECK-NOT: br label
+ // CHECK: ret void
+ (void)new Empty[10];
+}
diff --git a/test/CodeGenCXX/operator-new.cpp b/test/CodeGenCXX/operator-new.cpp
index da64fc1b2d4e..f718faebef00 100644
--- a/test/CodeGenCXX/operator-new.cpp
+++ b/test/CodeGenCXX/operator-new.cpp
@@ -6,6 +6,7 @@
class teste {
int A;
+public:
teste() : A(2) {}
};
diff --git a/test/CodeGenCXX/reference-in-blocks.cpp b/test/CodeGenCXX/reference-in-blocks.cpp
new file mode 100644
index 000000000000..c020bab0f778
--- /dev/null
+++ b/test/CodeGenCXX/reference-in-blocks.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fblocks %s -emit-llvm -o %t
+
+extern "C" int printf(const char*, ...);
+
+template<typename T> class range {
+public:
+T _i;
+ range(T i) {_i = i;};
+ T get() {return _i;};
+};
+
+int main() {
+
+ // works
+ void (^bl)(range<int> ) = ^(range<int> i){printf("Hello Blocks %d\n", i.get()); };
+
+ //crashes in godegen?
+ void (^bl2)(range<int>& ) = ^(range<int>& i){printf("Hello Blocks %d\n", i.get()); };
+ return 0;
+}
+
diff --git a/test/CodeGenCXX/rtti-fundamental.cpp b/test/CodeGenCXX/rtti-fundamental.cpp
index 473f48db67ad..6826321cd5eb 100644
--- a/test/CodeGenCXX/rtti-fundamental.cpp
+++ b/test/CodeGenCXX/rtti-fundamental.cpp
@@ -8,8 +8,10 @@ std::type_info foo() {
namespace __cxxabiv1 {
struct __fundamental_type_info {
- virtual ~__fundamental_type_info() {}
+ virtual ~__fundamental_type_info();
};
+
+ __fundamental_type_info::~__fundamental_type_info() { }
}
// CHECK: @_ZTIv = weak_odr constant
diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp
index a67d137d6a1d..750da02603b3 100644
--- a/test/CodeGenCXX/static-init.cpp
+++ b/test/CodeGenCXX/static-init.cpp
@@ -34,3 +34,14 @@ inline void h2() {
void h3() {
h2();
}
+
+// PR6980: this shouldn't crash
+namespace test0 {
+ struct A { A(); };
+ __attribute__((noreturn)) int throw_exception();
+
+ void test() {
+ throw_exception();
+ static A r;
+ }
+}
diff --git a/test/CodeGenCXX/static-local-in-local-class.cpp b/test/CodeGenCXX/static-local-in-local-class.cpp
new file mode 100644
index 000000000000..d9e044ce9d97
--- /dev/null
+++ b/test/CodeGenCXX/static-local-in-local-class.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm -o %t %s
+// PR6769
+
+struct X {
+ static void f();
+};
+
+void X::f() {
+ static int *i;
+ {
+ struct Y {
+ static void g() {
+ i = new int();
+ *i = 100;
+ (*i) = (*i) +1;
+ }
+ };
+ (void)Y::g();
+ }
+ (void)i;
+}
diff --git a/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp b/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp
index 921113a14841..41ae08470a3d 100644
--- a/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp
+++ b/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp
@@ -4,6 +4,7 @@ class A
{
union { void *d; };
+public:
A() : d(0) { }
};
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index 416c0a1a2072..4a3857542d06 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -40,6 +40,7 @@ namespace test1 {
namespace test2 {
template<typename T1>
class C {
+ public:
virtual ~C();
void zedbar(double) {
}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 4aad3c0056ca..eb543cb54552 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -301,3 +301,22 @@ namespace PR6648 {
zed(foo);
}
}
+
+namespace UserConvertToValue {
+ struct X {
+ X(int);
+ X(const X&);
+ ~X();
+ };
+
+ void f(X);
+
+ // CHECK: void @_ZN18UserConvertToValue1gEv()
+ void g() {
+ // CHECK: call void @_ZN18UserConvertToValue1XC1Ei
+ // CHECK: call void @_ZN18UserConvertToValue1fENS_1XE
+ // CHECK: call void @_ZN18UserConvertToValue1XD1Ev
+ // CHECK: ret void
+ f(1);
+ }
+}
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index 37891bd6af67..35be159aac9d 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -23,3 +23,29 @@ void test_value_init() {
C c = { 17 } ;
// CHECK: call void @_ZN1CD1Ev
}
+
+enum enum_type { negative_number = -1, magic_number = 42 };
+
+class enum_holder
+{
+ enum_type m_enum;
+
+public:
+ enum_holder() : m_enum(magic_number) { }
+};
+
+struct enum_holder_and_int
+{
+ enum_holder e;
+ int i;
+};
+
+// CHECK: _Z24test_enum_holder_and_intv()
+void test_enum_holder_and_int() {
+ // CHECK: alloca
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memset
+ // CHECK-NEXT: call void @_ZN19enum_holder_and_intC1Ev
+ enum_holder_and_int();
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/virt-template-vtable.cpp b/test/CodeGenCXX/virt-template-vtable.cpp
index 76a1240731b2..b968f38c8263 100644
--- a/test/CodeGenCXX/virt-template-vtable.cpp
+++ b/test/CodeGenCXX/virt-template-vtable.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
template<class T> class A {
+public:
A() {}
virtual void a() {}
};
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
deleted file mode 100644
index 874ffb1ddf29..000000000000
--- a/test/CodeGenCXX/virt.cpp
+++ /dev/null
@@ -1,696 +0,0 @@
-// 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 x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t-64.ll
-// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s
-
-
-// CHECK-LP64: main:
-// CHECK-LP64: movl $1, 12(%rax)
-// CHECK-LP64: movl $2, 8(%rax)
-
-struct B {
- virtual void bar1();
- virtual void bar2();
- int b;
-};
-void B::bar1() { }
-void B::bar2() { }
-
-// CHECK-LPLL64:@_ZTV1B = constant [4 x i8*] [i8* null, i8* bitcast (%0* @_ZTI1B to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*)]
-
-struct C {
- virtual void bee1();
- virtual void bee2();
-};
-void C::bee1() { }
-void C::bee2() { }
-
-struct D {
- virtual void boo();
-};
-void D::boo() { }
-
-struct D1 {
- virtual void bar();
- virtual void bar2();
- virtual void bar3();
- virtual void bar4();
- virtual void bar5();
- void *d1;
-};
-void D1::bar() { }
-
-class F : virtual public D1, virtual public D {
-public:
- virtual void foo();
- void *f;
-};
-void F::foo() { }
-
-// CHECK-LPLL64:@_ZTV1F = constant [19 x i8*] [i8* null, i8* inttoptr (i64 16 to i8*), i8* null, i8* null, i8* bitcast (%1* @_ZTI1F to i8*), i8* bitcast (void (%class.test14*)* @_ZN1D3booEv to i8*), i8* bitcast (void (%class.F*)* @_ZN1F3fooEv to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast (%1* @_ZTI1F to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D13barEv to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar2Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar3Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar4Ev to i8*), i8* bitcast (void (%struct.D1*)* @_ZN2D14bar5Ev to i8*)]
-
-
-struct E {
- int e;
-};
-
-static_assert (sizeof (C) == (sizeof(void *)), "vtable pointer layout");
-
-class A : public E, public B, public C {
-public:
- virtual void foo1();
- virtual void foo2();
- A() { }
- int a;
-} *ap;
-void A::foo1() { }
-void A::foo2() { }
-
-// CHECK-LPLL64:@_ZTV1A = constant [10 x i8*] [i8* null, i8* bitcast (%2* @_ZTI1A to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*), i8* bitcast (void (%class.A*)* @_ZN1A4foo1Ev to i8*), i8* bitcast (void (%class.A*)* @_ZN1A4foo2Ev to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI1A to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee1Ev to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee2Ev to i8*)]
-
-int main() {
- A a;
- B b;
- ap->e = 1;
- ap->b = 2;
-}
-
-
-struct test12_A {
- virtual void foo0() { }
- virtual void foo();
-} *test12_pa;
-
-struct test12_B : public test12_A {
- virtual void foo() { }
-} *test12_pb;
-
-struct test12_D : public test12_B {
-} *test12_pd;
-
-
-struct test6_B2 { virtual void funcB2(); char b[1000]; };
-struct test6_B1 : virtual test6_B2 { virtual void funcB1(); };
-
-struct test6_D : test6_B2, virtual test6_B1 {
-};
-
-// CHECK-LP64: .zerofill __DATA,__common,_d6,2024,4
-
-struct test7_B2 { virtual void funcB2(); };
-struct test7_B1 : virtual test7_B2 { virtual void funcB1(); };
-
-struct test7_D : test7_B2, virtual test7_B1 {
-};
-
-// FIXME: we were checking for an alignment of 3 (?)
-// CHECK-LP64: .zerofill __DATA,__common,_d7,16,
-
-
-struct test3_B3 { virtual void funcB3(); };
-struct test3_B2 : virtual test3_B3 { virtual void funcB2(); };
-struct test3_B1 : virtual test3_B2 { virtual void funcB1(); };
-
-struct test3_D : virtual test3_B1 {
- virtual void funcD() { }
-};
-
-// CHECK-LPLL64:@_ZTV7test3_D = weak_odr constant [12 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI7test3_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test3_B36funcB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test3_B26funcB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test3_B16funcB1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN7test3_D5funcDEv to i8*)]
-
-
-struct test4_D : virtual B, virtual C {
-};
-
-// CHECK-LPLL64:@_ZTV7test4_D = weak_odr constant [14 x i8*] [i8* null, i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI7test4_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee1Ev to i8*), i8* bitcast (void (%class.test14*)* @_ZN1C4bee2Ev to i8*), i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI7test4_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar1Ev to i8*), i8* bitcast (void (%struct.B*)* @_ZN1B4bar2Ev to i8*)]
-
-
-struct test5_B3 { virtual void funcB3(); };
-struct test5_B2 : virtual test5_B3 { virtual void funcB2(); };
-struct test5_B1 : virtual test5_B2 { virtual void funcB1(); };
-
-struct test5_B23 { virtual void funcB23(); };
-struct test5_B22 : virtual test5_B23 { virtual void funcB22(); };
-struct test5_B21 : virtual test5_B22 { virtual void funcB21(); };
-
-
-struct B232 { virtual void funcB232(); };
-struct B231 { virtual void funcB231(); };
-
-struct test5_B33 { virtual void funcB33(); };
-struct test5_B32 : virtual test5_B33, virtual B232 { virtual void funcB32(); };
-struct test5_B31 : virtual test5_B32, virtual B231 { virtual void funcB31(); };
-
-struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 {
- virtual void funcD() { }
-};
-
-// CHECK-LPLL64:@_ZTV7test5_D = weak_odr constant [50 x i8*] [i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test5_B36funcB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test5_B26funcB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test5_B16funcB1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN7test5_D5funcDEv to i8*), i8* null, i8* null, i8* null, i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test5_B237funcB23Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test5_B227funcB22Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test5_B217funcB21Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* null, i8* null, i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test5_B337funcB33Ev to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN9test5_B327funcB32Ev to i8*), i8* bitcast (void (%class.test23_D*)* @_ZN9test5_B317funcB31Ev to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN4B2328funcB232Ev to i8*), i8* null, i8* inttoptr (i64 -32 to i8*), i8* bitcast (%2* @_ZTI7test5_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN4B2318funcB231Ev to i8*)]
-
-struct test8_B1 {
- virtual void ftest8_B1() { }
-};
-struct test8_B2aa {
- virtual void ftest8_B2aa() { }
- int i;
-};
-struct test8_B2ab {
- virtual void ftest8_B2ab() { }
- int i;
-};
-struct test8_B2a : virtual test8_B2aa, virtual test8_B2ab {
- virtual void ftest8_B2a() { }
-};
-struct test8_B2b {
- virtual void ftest8_B2b() { }
-};
-struct test8_B2 : test8_B2a, test8_B2b {
- virtual void ftest8_B2() { }
-};
-struct test8_B3 {
- virtual void ftest8_B3() { }
-};
-class test8_D : test8_B1, test8_B2, test8_B3 {
-};
-
-// CHECK-LPLL64:@_ZTV7test8_D = weak_odr constant [25 x i8*] [i8* inttoptr (i64 48 to i8*), i8* inttoptr (i64 32 to i8*), i8* null, i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test8_B19ftest8_B1Ev to i8*), i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* bitcast (void (%struct.test15_D*)* @_ZN8test8_B29ftest8_B2Ev to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test8_B2b10ftest8_B2bEv to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test8_B39ftest8_B3Ev to i8*), i8* null, i8* inttoptr (i64 -32 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -48 to i8*), i8* bitcast (%2* @_ZTI7test8_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)]
-
-// CHECK-LPLL64:@_ZTC7test8_D8_8test8_B2 = internal constant [14 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* bitcast (void (%struct.test15_D*)* @_ZN8test8_B29ftest8_B2Ev to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI8test8_B2 to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)] ; <[14 x i8*]*> [#uses=3]
-
-// CHECK-LPLL64:@_ZTC7test8_D8_9test8_B2a = internal constant [13 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* null, i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN9test8_B2a10ftest8_B2aEv to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2aa11ftest8_B2aaEv to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI9test8_B2a to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test8_B2ab11ftest8_B2abEv to i8*)] ; <[13 x i8*]*> [#uses=3]
-
-// CHECK-LPLL64:@_ZTT7test8_D = weak_odr constant [10 x i8*] [i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 8) to i8*), i8* bitcast (i8** getelementptr inbounds ([13 x i8*]* @_ZTC7test8_D8_9test8_B2a, i64 0, i64 12) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 9) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTC7test8_D8_8test8_B2, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 9) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 20) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTV7test8_D, i64 0, i64 24) to i8*)]
-
-
-struct test9_B3 { virtual void funcB3(); int i; };
-struct test9_B2 : virtual test9_B3 { virtual void funcB2(); int i; };
-struct test9_B1 : virtual test9_B2 { virtual void funcB1(); int i; };
-
-struct test9_B23 { virtual void funcB23(); int i; };
-struct test9_B22 : virtual test9_B23 { virtual void funcB22(); int i; };
-struct test9_B21 : virtual test9_B22 { virtual void funcB21(); int i; };
-
-
-struct test9_B232 { virtual void funcB232(); int i; };
-struct test9_B231 { virtual void funcB231(); int i; };
-
-struct test9_B33 { virtual void funcB33(); int i; };
-struct test9_B32 : virtual test9_B33, virtual test9_B232 { virtual void funcB32(); int i; };
-struct test9_B31 : virtual test9_B32, virtual test9_B231 { virtual void funcB31(); int i; };
-
-struct test9_D : virtual test9_B1, virtual test9_B21, virtual test9_B31 {
- virtual void funcD() { }
-};
-
-// CHECK-LPLL64:@_ZTV7test9_D = weak_odr constant [70 x i8*] [i8* inttoptr (i64 168 to i8*), i8* inttoptr (i64 152 to i8*), i8* inttoptr (i64 136 to i8*), i8* inttoptr (i64 120 to i8*), i8* inttoptr (i64 104 to i8*), i8* inttoptr (i64 88 to i8*), i8* inttoptr (i64 72 to i8*), i8* inttoptr (i64 56 to i8*), i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_D*)* @_ZN7test9_D5funcDEv to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN8test9_B16funcB1Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN8test9_B26funcB2Ev to i8*), i8* null, i8* inttoptr (i64 -40 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test9_B36funcB3Ev to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -56 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN9test9_B217funcB21Ev to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -72 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test9_B227funcB22Ev to i8*), i8* null, i8* inttoptr (i64 -88 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN9test9_B237funcB23Ev to i8*), i8* null, i8* inttoptr (i64 64 to i8*), i8* inttoptr (i64 48 to i8*), i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -104 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B31*)* @_ZN9test9_B317funcB31Ev to i8*), i8* null, i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -120 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.test9_B1*)* @_ZN9test9_B327funcB32Ev to i8*), i8* null, i8* inttoptr (i64 -136 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN9test9_B337funcB33Ev to i8*), i8* null, i8* inttoptr (i64 -152 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test9_B2328funcB232Ev to i8*), i8* null, i8* inttoptr (i64 -168 to i8*), i8* bitcast (%2* @_ZTI7test9_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test9_B2318funcB231Ev to i8*)] ; <[70 x i8*]*> [#uses=12]
-
-
-struct test10_O { int i; };
-
-struct test10_B1 : virtual test10_O {
- virtual void ftest10_B1() { }
-};
-
-struct test10_B2aa : virtual test10_O {
- int i;
-};
-struct test10_B2ab : virtual test10_O {
- int i;
-};
-struct test10_B2a : virtual test10_B2aa, virtual test10_B2ab,virtual test10_O {
- virtual void ftest10_B2a() { }
-};
-struct test10_B2b : virtual test10_O {
- virtual void ftest10_B2b() { }
-};
-struct test10_B2 : test10_B2a {
- virtual void ftest10_B2() { }
-};
-class test10_D : test10_B1, test10_B2 {
-
- void ftest10_B2aa() { }
-};
-
-// CHECK-LPLL64:@_ZTV8test10_D = weak_odr constant [19 x i8*] [i8* inttoptr (i64 40 to i8*), i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* bitcast (void (%struct.test10_B1*)* @_ZN9test10_B110ftest10_B1Ev to i8*), i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* bitcast (void (%struct.test10_B2a*)* @_ZN10test10_B2a11ftest10_B2aEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN9test10_B210ftest10_B2Ev to i8*), i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*), i8* inttoptr (i64 -24 to i8*), i8* inttoptr (i64 -40 to i8*), i8* bitcast (%1* @_ZTI8test10_D to i8*)] ; <[19 x i8*]*> [#uses=4]
-
-
-struct test11_B {
- virtual void B1() { }
- virtual void D() { }
- virtual void B2() { }
-};
-
-struct test11_D : test11_B {
- virtual void D1() { }
- virtual void D() { }
- virtual void D2() { }
-};
-
-// CHECK-LPLL64:@_ZTV8test11_D = weak_odr constant [7 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test11_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test11_B2B1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D1DEv to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test11_B2B2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D2D1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test11_D2D2Ev to i8*)]
-
-
-struct test13_B {
- virtual void B1() { }
- virtual void D() { }
- virtual void Da();
- virtual void Db() { }
- virtual void Dc() { }
- virtual void B2() { }
- int i;
-};
-
-
-struct test13_NV1 {
- virtual void fooNV1() { }
- virtual void D() { }
-};
-
-
-struct test13_B2 : /* test13_NV1, */ virtual test13_B {
- virtual void B2a() { }
- virtual void B2() { }
- virtual void D() { }
- virtual void Da();
- virtual void Dd() { }
- virtual void B2b() { }
- int i;
-};
-
-
-struct test13_D : test13_NV1, virtual test13_B2 {
- virtual void D1() { }
- virtual void D() { }
- virtual void Db() { }
- virtual void Dd() { }
- virtual void D2() { }
- virtual void fooNV1() { }
-};
-
-// CHECK-LPLL64:@_ZTV8test13_D = weak_odr constant [39 x i8*] [i8* inttoptr (i64 24 to i8*), i8* inttoptr (i64 8 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D6fooNV1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D1DEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2D1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2DbEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2DdEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZN8test13_D2D2Ev to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* null, i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B23B2aEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B22B2Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n48_N8test13_D1DEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B22DaEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n64_N8test13_D2DdEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZN9test13_B23B2bEv to i8*), i8* inttoptr (i64 -16 to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -24 to i8*), i8* null, i8* inttoptr (i64 -24 to i8*), i8* bitcast (%1* @_ZTI8test13_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test13_B2B1Ev to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n32_N8test13_D1DEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZTv0_n40_N9test13_B22DaEv to i8*), i8* bitcast (void (%struct.test10_B2*)* @_ZTv0_n48_N8test13_D2DbEv to i8*), i8* bitcast (void (%struct.B*)* @_ZN8test13_B2DcEv to i8*), i8* bitcast (void (%struct.test13_B2*)* @_ZTv0_n64_N9test13_B22B2Ev to i8*)]
-
-
-class test14 {
-public:
- virtual void initWithInt(int a);
- static test14 *withInt(int a);
-};
-
-void test14::initWithInt(int a) { }
-
-test14 *test14::withInt(int a) {
- test14 *me = new test14;
- me->initWithInt(a);
- return me;
-}
-
-
-struct test15_B {
- virtual test15_B *foo1() { return 0; }
- virtual test15_B *foo2() { return 0; }
- virtual test15_B *foo3() { return 0; }
- int i;
-};
-
-struct test15_NV1 {
- virtual void fooNV1() { }
- int i;
-};
-
-struct test15_B2 : test15_NV1, virtual test15_B {
- virtual test15_B2 *foo1() { return 0; }
- virtual test15_B2 *foo2() { return 0; }
- int i;
-};
-
-struct test15_D : test15_NV1, virtual test15_B2 {
- virtual test15_D *foo1() { return 0; }
-};
-
-// CHECK-LPLL64:@_ZTV8test15_D = weak_odr constant [23 x i8*] [i8* inttoptr (i64 32 to i8*), i8* inttoptr (i64 16 to i8*), i8* null, i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test15_NV16fooNV1Ev to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZN8test15_D4foo1Ev to i8*), i8* null, i8* inttoptr (i64 -16 to i8*), i8* null, i8* inttoptr (i64 16 to i8*), i8* inttoptr (i64 -16 to i8*), i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (void (%struct.B*)* @_ZN10test15_NV16fooNV1Ev to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZTcv0_n40_v0_n24_N8test15_D4foo1Ev to i8*), i8* bitcast (%struct.test15_B2* (%struct.test15_B2*)* @_ZN9test15_B24foo2Ev to i8*), i8* null, i8* inttoptr (i64 -16 to i8*), i8* inttoptr (i64 -32 to i8*), i8* inttoptr (i64 -32 to i8*), i8* bitcast (%1* @_ZTI8test15_D to i8*), i8* bitcast (%struct.test15_D* (%struct.test15_D*)* @_ZTcv0_n24_v0_n32_N8test15_D4foo1Ev to i8*), i8* bitcast (%struct.test15_B2* (%struct.test15_B2*)* @_ZTcv0_n32_v0_n24_N9test15_B24foo2Ev to i8*), i8* bitcast (%struct.B* (%struct.B*)* @_ZN8test15_B4foo3Ev to i8*)]
-
-
-struct test16_NV1 {
- virtual void fooNV1() { }
-virtual void foo_NV1() { }
- int i;
-};
-
-struct test16_NV2 {
- virtual test16_NV2* foo1() { return 0; }
-virtual void foo_NV2() { }
-virtual void foo_NV2b() { }
- int i;
-};
-
-struct test16_B : public test16_NV1, test16_NV2 {
- virtual test16_B *foo1() { return 0; }
- virtual test16_B *foo2() { return 0; }
- virtual test16_B *foo3() { return 0; }
-virtual void foo_B() { }
- int i;
-};
-
-struct test16_B2 : test16_NV1, virtual test16_B {
- virtual test16_B2 *foo1() { return 0; }
- virtual test16_B2 *foo2() { return 0; }
-virtual void foo_B2() { }
- int i;
-};
-
-struct test16_D : test16_NV1, virtual test16_B2 {
- virtual void bar() { }
- virtual test16_D *foo1() { return 0; }
-};
-
-// FIXME:
-// CHECK-LP64: __ZTV8test16_D:
-// CHECK-LP64-NEXT: .quad 32
-// CHECK-LP64-NEXT: .quad 16
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad __ZTI8test16_D
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev
-// CHECK-LP64-NEXT: .quad __ZN8test16_D3barEv
-// CHECK-LP64-NEXT: .quad __ZN8test16_D4foo1Ev
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad -16
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 16
-// CHECK-LP64-NEXT: .quad -16
-// CHECK-LP64-NEXT: .quad __ZTI8test16_D
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev
-// 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 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad -16
-// CHECK-LP64-NEXT: .quad -32
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad -32
-// CHECK-LP64-NEXT: .quad __ZTI8test16_D
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV16fooNV1Ev
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV17foo_NV1Ev
-// CHECK-LP64-NEXT: .quad __ZTcv0_n40_v0_n32_N8test16_D4foo1Ev
-// CHECK-LP64-NEXT: .quad __ZTcv0_n48_v0_n24_N9test16_B24foo2Ev
-// CHECK-LP64-NEXT: .quad __ZN8test16_B4foo3Ev
-// 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-NEXT: .quad __ZN10test16_NV27foo_NV2Ev
-// CHECK-LP64-NEXT: .quad __ZN10test16_NV28foo_NV2bEv
-
-
-
-
-class test17_B1 {
- virtual void foo() = 0;
- virtual void bar() { }
-};
-
-class test17_B2 : public test17_B1 {
- void foo() { }
- virtual void bar() = 0;
-};
-
-class test17_D : public test17_B2 {
- void bar() { }
-};
-
-
-// CHECK-LPLL64:@_ZTV8test17_D = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test17_D to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test17_B23fooEv to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN8test17_D3barEv to i8*)]
-
-// CHECK-LPLL64:@_ZTV9test17_B2 = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%4* @_ZTI9test17_B2 to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test17_B23fooEv to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*)]
-
-// CHECK-LPLL64:@_ZTV9test17_B1 = weak_odr constant [4 x i8*] [i8* null, i8* bitcast (%0* @_ZTI9test17_B1 to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test17_B13barEv to i8*)]
-
-
-struct test18_NV1 {
- virtual void fooNV1() { }
-virtual void foo_NV1() { }
- int i;
-};
-
-struct test18_NV2 {
- virtual test18_NV2& foo1() { return *this; }
-virtual void foo_NV2() { }
-virtual void foo_NV2b() { }
- int i;
-};
-
-struct test18_B : public test18_NV1, test18_NV2 {
- virtual test18_B& foo1() { return *this; }
- virtual test18_B *foo2() { return 0; }
- virtual test18_B *foo3() { return 0; }
-virtual void foo_B() { }
- int i;
-};
-
-struct test18_B2 : test18_NV1, virtual test18_B {
- virtual test18_B2& foo1() { return *this; }
- virtual test18_B2 *foo2() { return 0; }
-virtual void foo_B2() { }
- int i;
-};
-
-struct test18_D : test18_NV1, virtual test18_B2 {
- virtual test18_D& foo1() { return *this; }
-};
-
-
-struct test19_VB1 { };
-struct test19_B1 : public virtual test19_VB1 {
- virtual void fB1() { }
- virtual void foB1B2() { }
- virtual void foB1B3() { }
- virtual void foB1B4() { }
-};
-
-struct test19_VB2 { };
-struct test19_B2: public test19_B1, public virtual test19_VB2 {
- virtual void foB1B2() { }
- virtual void foB1B3() { }
- virtual void foB1B4() { }
-
- virtual void fB2() { }
- virtual void foB2B3() { }
- virtual void foB2B4() { }
-};
-
-struct test19_VB3 { };
-struct test19_B3: virtual public test19_B2, public virtual test19_VB3 {
- virtual void foB1B3() { }
- virtual void foB1B4() { }
-
- virtual void foB2B3() { }
- virtual void foB2B4() { }
-
- virtual void fB3() { }
- virtual void foB3B4() { }
-};
-
-struct test19_VB4 { };
-struct test19_B4: public test19_B3, public virtual test19_VB4 {
- virtual void foB1B4() { }
-
- virtual void foB2B4() { }
-
- virtual void foB3B4() { }
-
- virtual void fB4() { }
-};
-
-struct test19_D : virtual test19_B4 {
-};
-
-
-// CHECK-LPLL64:@_ZTV8test19_D = weak_odr constant [28 x i8*] [i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test19_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test19_B13fB1Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B26foB1B2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B36foB1B3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB1B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B23fB2Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B36foB2B3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB2B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B33fB3Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B46foB3B4Ev to i8*), i8* bitcast (void (%class.test17_B2*)* @_ZN9test19_B43fB4Ev to i8*)]
-
-// FIXME:
-// CHECK-LP64: __ZTT8test19_D:
-// CHECK-LP64-NEXT: .quad __ZTV8test19_D+144
-// CHECK-LP64-NEXT: .quad __ZTV8test19_D+144
-// CHECK-LP64-NEXT .quad __ZTV8test19_D+144
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B4+136
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B3+104
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B3+104
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B4+136
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B2+88
-// CHECK-LP64-NEXT .quad __ZTC8test19_D0_9test19_B1+24
-
-class test20_V {
- virtual void foo1();
-};
-class test20_V1 {
- virtual void foo2();
-};
-class test20_B : virtual test20_V {
-} b;
-class test20_B1 : virtual test20_V1 {
-};
-class test20_D : public test20_B, public test20_B1 {
-};
-
-// CHECK-LPLL64:@_ZTV8test20_D = weak_odr constant [11 x i8*] [i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI8test20_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test20_V4foo1Ev to i8*), i8* null, i8* null, i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test20_D to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test20_V14foo2Ev to i8*)]
-
-// CHECK-LPLL64:@_ZTC8test20_D0_8test20_B = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test20_B to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test20_V4foo1Ev to i8*)]
-
-// CHECK-LPLL64:@_ZTC8test20_D8_9test20_B1 = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI9test20_B1 to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test20_V14foo2Ev to i8*)] ; <[5 x i8*]*> [#uses=1]
-
-// FIXME:
-// CHECK-LP64: __ZTT8test20_D:
-// CHECK-LP64-NEXT: .quad __ZTV8test20_D+40
-// CHECK-LP64-NEXT: .quad __ZTC8test20_D0_8test20_B+32
-// CHECK-LP64-NEXT: .quad __ZTC8test20_D0_8test20_B+32
-// CHECK-LP64-NEXT: .quad __ZTC8test20_D8_9test20_B1+32
-// CHECK-LP64-NEXT: .quad __ZTC8test20_D8_9test20_B1+32
-// CHECK-LP64-NEXT .quad __ZTV8test20_D+40
-// CHECK-LP64-NEXT .quad __ZTV8test20_D+80
-// CHECK-LP64-NEXT .quad __ZTV8test20_D+80
-
-
-class test21_V {
- virtual void foo() { }
-};
-class test21_V1 {
- virtual void foo() { }
-};
-class test21_B : virtual test21_V {
-};
-class test21_B1 : virtual test21_V1 {
-};
-class test21_D : public test21_B, public test21_B1 {
- void foo() { }
-};
-
-// CHECK-LPLL64:@_ZTV8test21_D = weak_odr constant [11 x i8*] [i8* inttoptr (i64 8 to i8*), i8* null, i8* null, i8* null, i8* bitcast (%1* @_ZTI8test21_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN8test21_D3fooEv to i8*), i8* null, i8* inttoptr (i64 -8 to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%1* @_ZTI8test21_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZTv0_n24_N8test21_D3fooEv to i8*)]
-
-// CHECK-LPLL64:@_ZTC8test21_D0_8test21_B = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI8test21_B to i8*), i8* bitcast (void (%class.test14*)* @_ZN8test21_V3fooEv to i8*)]
-
-// CHECK-LPLL64:@_ZTC8test21_D8_9test21_B1 = internal constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (%3* @_ZTI9test21_B1 to i8*), i8* bitcast (void (%class.test14*)* @_ZN9test21_V13fooEv to i8*)] ; <[5 x i8*]*> [#uses=1]
-
-// FIXME:
-// CHECK-LP64: __ZTT8test21_D:
-// CHECK-LP64-NEXT: .quad __ZTV8test21_D+40
-// CHECK-LP64-NEXT: .quad __ZTC8test21_D0_8test21_B+32
-// CHECK-LP64-NEXT: .quad __ZTC8test21_D0_8test21_B+32
-// CHECK-LP64-NEXT: .quad __ZTC8test21_D8_9test21_B1+32
-// CHECK-LP64-NEXT: .quad __ZTC8test21_D8_9test21_B1+32
-// CHECK-LP64-NEXT .quad __ZTV8test21_D+40
-// CHECK-LP64-NEXT .quad __ZTV8test21_D+80
-// CHECK-LP64-NEXT .quad __ZTV8test21_D+80
-
-
-struct test22_s1 { virtual void dtor() { } };
-struct test22_s2 { virtual void dtor() { } };
-struct test22_s3 : test22_s1, test22_s2 { virtual void dtor() { } };
-struct test22_D : test22_s3 { virtual void dtor() { } };
-
-// CHECK-LPLL64:@_ZTV8test22_D = weak_odr constant [6 x i8*] [i8* null, i8* bitcast (%4* @_ZTI8test22_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZN8test22_D4dtorEv to i8*), i8* inttoptr (i64 -8 to i8*), i8* bitcast (%4* @_ZTI8test22_D to i8*), i8* bitcast (void (%class.test20_D*)* @_ZThn8_N8test22_D4dtorEv to i8*)]
-
-
-class test23_s1 {
- virtual void fun1(char *t) { }
-};
-class test23_s2 {
- virtual void fun2(char *t) { }
-};
-class test23_s3 {
- virtual void fun3(char *t) { }
-};
-class test23_s4: virtual test23_s1, test23_s2, test23_s3 {
- virtual void fun4(char *t) { }
-};
-class test23_D: virtual test23_s4 {
- virtual void fun5(char *t) { }
-};
-
-
-// FIXME:
-// CHECK-LP64: __ZTV8test23_D:
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 8
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64-NEXT: .quad __ZTI8test23_D
-// CHECK-LP64-NEXT: .quad __ZN9test23_s14fun1EPc
-// CHECK-LP64-NEXT: .quad __ZN8test23_D4fun5EPc
-// CHECK-LP64-NEXT .quad 8
-// CHECK-LP64: .quad 0
-// CHECK-LP64-NEXT: .quad 0
-// CHECK-LP64: .quad -8
-// CHECK-LP64-NEXT: .quad -8
-// CHECK-LP64-NEXT: .quad __ZTI8test23_D
-// CHECK-LP64-NEXT: .quad __ZN9test23_s24fun2EPc
-// CHECK-LP64-NEXT: .quad __ZN9test23_s44fun4EPc
-// CHECK-LP64-NEXT: .quad -16
-// CHECK-LP64-NEXT: .quad __ZTI8test23_D
-// CHECK-LP64-NEXT: .quad __ZN9test23_s34fun3EPc
-
-
-test23_D d23;
-test22_D d22;
-test21_D d21;
-test20_D d20;
-test19_D d19;
-test18_D d18;
-test17_D d17;
-test16_D d16;
-test15_D d15;
-test13_D d13;
-test11_D d11;
-test10_D d10;
-test9_D d9;
-test8_D d8;
-
-test5_D d5;
-test4_D d4;
-test3_D d3;
-
-test6_D d6;
-test7_D d7;
-
-
-int j;
-void *vp;
-void test2() {
- F f;
- static int sz = (char *)(&f.f) - (char *)(&f);
- vp = &sz;
- j = sz;
- // FIXME: These should result in a frontend constant a la fold, no run time
- // initializer
- // CHECK-LPLL64: define void @_Z5test2v()
- // CHECK-LPLL64: = getelementptr inbounds %class.F* %f, i32 0, i32 1
-}
-
-static_assert(sizeof(F) == sizeof(void*)*4, "invalid vbase size");
-
-
-void test12_foo() {
- test12_pa->foo0();
- test12_pb->foo0();
- test12_pd->foo0();
- test12_pa->foo();
- test12_pb->foo();
- test12_pd->foo();
- test12_pa->test12_A::foo();
-}
-
-
-// CHECK-LPLL64:define void @_Z10test12_foov() nounwind {
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}})
-
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index 3a0dae41c3b0..f2f5179d4a19 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -1303,3 +1303,337 @@ struct B : virtual A {
V2 *B::f() { return 0; }
}
+
+namespace Test30 {
+
+// Test that we don't assert when generating a vtable for F.
+struct A { };
+
+struct B : virtual A {
+ int i;
+};
+
+struct C {
+ virtual void f();
+};
+
+struct D : virtual C, B { };
+struct E : virtual D { };
+
+struct F : E {
+ virtual void f();
+};
+void F::f() { }
+
+}
+
+namespace Test31 {
+
+// Test that we don't add D::f twice to the primary vtable.
+struct A {
+ int a;
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, virtual B {
+ virtual void f();
+};
+
+// CHECK: Vtable for 'Test31::D' (11 entries).
+// CHECK-NEXT: 0 | vbase_offset (0)
+// CHECK-NEXT: 1 | vbase_offset (8)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test31::D RTTI
+// CHECK-NEXT: -- (Test31::B, 0) vtable address --
+// CHECK-NEXT: -- (Test31::D, 0) vtable address --
+// CHECK-NEXT: 5 | void Test31::D::f()
+// CHECK-NEXT: 6 | vbase_offset (-8)
+// CHECK-NEXT: 7 | vcall_offset (-8)
+// CHECK-NEXT: 8 | offset_to_top (-8)
+// CHECK-NEXT: 9 | Test31::D RTTI
+// CHECK-NEXT: -- (Test31::C, 8) vtable address --
+// CHECK-NEXT: 10 | void Test31::D::f()
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+struct D : virtual C {
+ virtual void f();
+};
+void D::f() { }
+
+}
+
+namespace Test32 {
+
+// Check that we correctly lay out the virtual bases of 'Test32::D'.
+
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A { };
+struct C : A, virtual B { };
+struct D : virtual B { };
+
+// CHECK: Virtual base offset offsets for 'Test32::E' (3 entries).
+// CHECK-NEXT: Test32::A | -32
+// CHECK-NEXT: Test32::B | -24
+// CHECK-NEXT: Test32::D | -40
+struct E : C, virtual D {
+ virtual void f();
+};
+void E::f() { }
+
+}
+
+namespace Test33 {
+
+// Test that we don't emit too many vcall offsets in 'Test32::F'.
+
+struct A {
+ virtual void a();
+};
+
+struct B {
+ virtual void b();
+};
+
+struct C : virtual A, virtual B {
+ virtual void c();
+};
+
+struct D : virtual C { };
+
+struct E : A, D {
+ virtual void e();
+};
+
+// CHECK: Vtable for 'Test33::F' (30 entries).
+// CHECK-NEXT: 0 | vbase_offset (24)
+// CHECK-NEXT: 1 | vbase_offset (16)
+// CHECK-NEXT: 2 | vbase_offset (16)
+// CHECK-NEXT: 3 | vbase_offset (8)
+// CHECK-NEXT: 4 | offset_to_top (0)
+// CHECK-NEXT: 5 | Test33::F RTTI
+// CHECK-NEXT: -- (Test33::A, 0) vtable address --
+// CHECK-NEXT: -- (Test33::F, 0) vtable address --
+// CHECK-NEXT: 6 | void Test33::A::a()
+// CHECK-NEXT: 7 | void Test33::F::f()
+// CHECK-NEXT: 8 | vcall_offset (0)
+// CHECK-NEXT: 9 | vcall_offset (0)
+// CHECK-NEXT: 10 | vbase_offset (16)
+// CHECK-NEXT: 11 | vbase_offset (8)
+// CHECK-NEXT: 12 | vbase_offset (8)
+// CHECK-NEXT: 13 | offset_to_top (-8)
+// CHECK-NEXT: 14 | Test33::F RTTI
+// CHECK-NEXT: -- (Test33::A, 8) vtable address --
+// CHECK-NEXT: -- (Test33::E, 8) vtable address --
+// CHECK-NEXT: 15 | void Test33::A::a()
+// CHECK-NEXT: 16 | void Test33::E::e()
+// CHECK-NEXT: 17 | vbase_offset (0)
+// CHECK-NEXT: 18 | vcall_offset (0)
+// CHECK-NEXT: 19 | vbase_offset (8)
+// CHECK-NEXT: 20 | vbase_offset (0)
+// CHECK-NEXT: 21 | vcall_offset (0)
+// CHECK-NEXT: 22 | offset_to_top (-16)
+// CHECK-NEXT: 23 | Test33::F RTTI
+// CHECK-NEXT: -- (Test33::A, 16) vtable address --
+// CHECK-NEXT: -- (Test33::C, 16) vtable address --
+// CHECK-NEXT: -- (Test33::D, 16) vtable address --
+// CHECK-NEXT: 24 | void Test33::A::a()
+// CHECK-NEXT: 25 | void Test33::C::c()
+// CHECK-NEXT: 26 | vcall_offset (0)
+// CHECK-NEXT: 27 | offset_to_top (-24)
+// CHECK-NEXT: 28 | Test33::F RTTI
+// CHECK-NEXT: -- (Test33::B, 24) vtable address --
+// CHECK-NEXT: 29 | void Test33::B::b()
+struct F : virtual E, A {
+ virtual void f();
+};
+void F::f() { }
+
+}
+
+namespace Test34 {
+
+// Test that we lay out the construction vtable for 'Test34::E' in 'Test34::F' correctly.
+
+struct A {
+ virtual void a();
+};
+struct B : virtual A { };
+
+struct C : B, A {
+ virtual void c();
+};
+
+struct D : A, C { };
+
+struct E : virtual D {
+ virtual void e();
+};
+
+// CHECK: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries).
+// CHECK-NEXT: 0 | vbase_offset (0)
+// CHECK-NEXT: 1 | vbase_offset (8)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test34::E RTTI
+// CHECK-NEXT: -- (Test34::A, 0) vtable address --
+// CHECK-NEXT: -- (Test34::E, 0) vtable address --
+// CHECK-NEXT: 5 | void Test34::A::a()
+// CHECK-NEXT: 6 | void Test34::E::e()
+// CHECK-NEXT: 7 | vcall_offset (8)
+// CHECK-NEXT: 8 | vcall_offset (0)
+// CHECK-NEXT: 9 | vbase_offset (-8)
+// CHECK-NEXT: 10 | offset_to_top (-8)
+// CHECK-NEXT: 11 | Test34::E RTTI
+// CHECK-NEXT: -- (Test34::A, 8) vtable address --
+// CHECK-NEXT: -- (Test34::D, 8) vtable address --
+// CHECK-NEXT: 12 | void Test34::A::a()
+// CHECK-NEXT: 13 | vbase_offset (-16)
+// CHECK-NEXT: 14 | vcall_offset (-16)
+// CHECK-NEXT: 15 | offset_to_top (-16)
+// CHECK-NEXT: 16 | Test34::E RTTI
+// CHECK-NEXT: -- (Test34::B, 16) vtable address --
+// CHECK-NEXT: -- (Test34::C, 16) vtable address --
+// CHECK-NEXT: 17 | [unused] void Test34::A::a()
+// CHECK-NEXT: 18 | void Test34::C::c()
+// CHECK-NEXT: 19 | offset_to_top (-24)
+// CHECK-NEXT: 20 | Test34::E RTTI
+// CHECK-NEXT: -- (Test34::A, 24) vtable address --
+// CHECK-NEXT: 21 | void Test34::A::a()
+struct F : E {
+ virtual void f();
+};
+void F::f() { }
+
+}
+
+namespace Test35 {
+
+// Test that we lay out the virtual bases of 'Test35::H' in the correct order.
+
+struct A {
+ virtual void a();
+
+ int i;
+};
+
+struct B : virtual A {
+ virtual void b();
+};
+
+struct C {
+ virtual void c();
+};
+
+struct D : C, virtual B {
+ virtual void d();
+};
+
+struct E : D {
+ virtual void e();
+
+ bool b;
+};
+
+struct F : virtual D { };
+struct G : virtual E { };
+
+// CHECK: Vtable for 'Test35::H' (32 entries).
+// CHECK-NEXT: 0 | vbase_offset (32)
+// CHECK-NEXT: 1 | vbase_offset (0)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | vcall_offset (0)
+// CHECK-NEXT: 4 | vbase_offset (16)
+// CHECK-NEXT: 5 | vbase_offset (8)
+// CHECK-NEXT: 6 | offset_to_top (0)
+// CHECK-NEXT: 7 | Test35::H RTTI
+// CHECK-NEXT: -- (Test35::C, 0) vtable address --
+// CHECK-NEXT: -- (Test35::D, 0) vtable address --
+// CHECK-NEXT: -- (Test35::F, 0) vtable address --
+// CHECK-NEXT: -- (Test35::H, 0) vtable address --
+// CHECK-NEXT: 8 | void Test35::C::c()
+// CHECK-NEXT: 9 | void Test35::D::d()
+// CHECK-NEXT: 10 | void Test35::H::h()
+// CHECK-NEXT: 11 | vbase_offset (0)
+// CHECK-NEXT: 12 | vbase_offset (24)
+// CHECK-NEXT: 13 | vcall_offset (0)
+// CHECK-NEXT: 14 | vbase_offset (8)
+// CHECK-NEXT: 15 | offset_to_top (-8)
+// CHECK-NEXT: 16 | Test35::H RTTI
+// CHECK-NEXT: -- (Test35::B, 8) vtable address --
+// CHECK-NEXT: -- (Test35::G, 8) vtable address --
+// CHECK-NEXT: 17 | void Test35::B::b()
+// CHECK-NEXT: 18 | vcall_offset (0)
+// CHECK-NEXT: 19 | offset_to_top (-16)
+// CHECK-NEXT: 20 | Test35::H RTTI
+// CHECK-NEXT: -- (Test35::A, 16) vtable address --
+// CHECK-NEXT: 21 | void Test35::A::a()
+// CHECK-NEXT: 22 | vcall_offset (0)
+// CHECK-NEXT: 23 | vcall_offset (0)
+// CHECK-NEXT: 24 | vcall_offset (0)
+// CHECK-NEXT: 25 | vbase_offset (-16)
+// CHECK-NEXT: 26 | vbase_offset (-24)
+// CHECK-NEXT: 27 | offset_to_top (-32)
+// CHECK-NEXT: 28 | Test35::H RTTI
+// CHECK-NEXT: -- (Test35::C, 32) vtable address --
+// CHECK-NEXT: -- (Test35::D, 32) vtable address --
+// CHECK-NEXT: -- (Test35::E, 32) vtable address --
+// CHECK-NEXT: 29 | void Test35::C::c()
+// CHECK-NEXT: 30 | void Test35::D::d()
+// CHECK-NEXT: 31 | void Test35::E::e()
+
+// CHECK: Virtual base offset offsets for 'Test35::H' (4 entries).
+// CHECK-NEXT: Test35::A | -32
+// CHECK-NEXT: Test35::B | -24
+// CHECK-NEXT: Test35::D | -56
+// CHECK-NEXT: Test35::E | -64
+struct H : F, G {
+ virtual void h();
+};
+void H::h() { }
+
+}
+
+namespace Test36 {
+
+// Test that we don't mark B::f as unused in the vtable for D.
+
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A { };
+
+struct C : virtual A {
+ virtual void f();
+};
+
+// CHECK: Vtable for 'Test36::D' (12 entries).
+// CHECK-NEXT: 0 | vbase_offset (8)
+// CHECK-NEXT: 1 | vbase_offset (8)
+// CHECK-NEXT: 2 | vcall_offset (0)
+// CHECK-NEXT: 3 | offset_to_top (0)
+// CHECK-NEXT: 4 | Test36::D RTTI
+// CHECK-NEXT: -- (Test36::C, 0) vtable address --
+// CHECK-NEXT: -- (Test36::D, 0) vtable address --
+// CHECK-NEXT: 5 | void Test36::C::f()
+// CHECK-NEXT: 6 | void Test36::D::g()
+// CHECK-NEXT: 7 | vbase_offset (0)
+// CHECK-NEXT: 8 | vcall_offset (-8)
+// CHECK-NEXT: 9 | offset_to_top (-8)
+// CHECK-NEXT: 10 | Test36::D RTTI
+// CHECK-NEXT: -- (Test36::A, 8) vtable address --
+// CHECK-NEXT: -- (Test36::B, 8) vtable address --
+// CHECK-NEXT: 11 | void Test36::C::f()
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+struct D : virtual B, C {
+ virtual void g();
+};
+void D::g() { }
+
+}
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index d13c0e4888fd..f8d655145b8f 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -6,7 +6,7 @@ struct S {
int s;
};
-// CHECK: define void @_Z1fv(%struct.S* noalias sret %
+// CHECK: define void @_Z1fv(%struct.S* sret %
S f() { return S(); }
// CHECK: define void @_Z1f1S(%struct.S*)
void f(S) { }
@@ -17,7 +17,7 @@ class C {
double c;
};
-// CHECK: define void @_Z1gv(%class.C* noalias sret %
+// CHECK: define void @_Z1gv(%class.C* sret %
C g() { return C(); }
// CHECK: define void @_Z1f1C(%class.C*)
diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m
new file mode 100644
index 000000000000..2896d379e75a
--- /dev/null
+++ b/test/CodeGenObjC/atomic-aggregate-property.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-gc -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// rdar: // 7849824
+
+struct s {
+ double a, b, c, d;
+};
+
+struct s1 {
+ int i;
+ id j;
+ id k;
+};
+
+@interface A
+@property (readwrite) double x;
+@property (readwrite) struct s y;
+@property (nonatomic, readwrite) struct s1 z;
+@end
+
+@implementation A
+@synthesize x;
+@synthesize y;
+@synthesize z;
+@end
+
+// CHECK-LP64: call void @objc_copyStruct
+// CHECK-LP64: call void @objc_copyStruct
+// CHECK-LP64: call void @objc_copyStruct
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 6dc14107b7c7..8ba319eefee1 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -29,7 +29,7 @@ void foo(T *P) {
@interface B : A @end
@implementation B
-(void) im1 {
- ^(void) { [super im0]; }();
+ ^(void) { [self im0]; }();
}
@end
diff --git a/test/CodeGenObjC/encode-cstyle-method.m b/test/CodeGenObjC/encode-cstyle-method.m
new file mode 100644
index 000000000000..187c9bfa9d63
--- /dev/null
+++ b/test/CodeGenObjC/encode-cstyle-method.m
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// rdar: // 7445205
+
+@interface Foo
+- (id)test:(id)one, id two;
+@end
+
+@implementation Foo
+- (id)test:(id )one, id two {return two; } @end
+
+// CHECK-LP64: internal global [11 x i8] c"@24@0:8@16
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
new file mode 100644
index 000000000000..a74dee95ddab
--- /dev/null
+++ b/test/CodeGenObjC/exceptions.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
+//
+// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
+
+// Just check that we don't emit any dead blocks.
+//
+// RUN: grep 'No predecessors' %t | count 0
+
+@interface NSArray @end
+void f0() {
+ @try {
+ @try {
+ @throw @"a";
+ } @catch(NSArray *e) {
+ }
+ } @catch (id e) {
+ }
+}
diff --git a/test/CodeGenObjC/image-info.m b/test/CodeGenObjC/image-info.m
index 8916d0053fed..2777723f736f 100644
--- a/test/CodeGenObjC/image-info.m
+++ b/test/CodeGenObjC/image-info.m
@@ -1,2 +1,8 @@
-// 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
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix CHECK-FRAGILE < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
+
+// CHECK-FRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__OBJC, __image_info,regular"
+// CHECK-NONFRAGILE: @"\01L_OBJC_IMAGE_INFO" = internal constant [2 x i32] [i32 0, i32 16], section "__DATA, __objc_imageinfo, regular, no_dead_strip"
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 886d53a8287e..dbc06d76cd50 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -emit-llvm -o %t %s
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: grep '@"OBJC_CLASS_$_A" = global' %t
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index dc65382e571f..921168c1616b 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -1,25 +1,40 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
-
-// RUN: grep '@"OBJC_METACLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t
-// RUN: grep '@"OBJC_CLASS_$_A" = global .*section "__DATA, __objc_data", align 8' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH1" = weak global .*section "__DATA,__datacoal_nt,coalesced", align 8' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH2" = external global' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH3" = global .*section "__DATA,__objc_const", align 8' %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix=CHECK-X86_64 < %t %s
// RUN: grep '@"OBJC_EHTYPE_$_EH3"' %t | count 3
-// RUN: grep '@"\\01L_OBJC_CLASS_NAME_" =.*section "__TEXT,__cstring,cstring_literals", align 1' %t | count 1
-// RUN: grep -F 'define internal void @"\01-[A im0]"' %t
-// RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -fvisibility hidden -emit-llvm -o %t %s
+// CHECK-X86_64: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
+// CHECK-X86_64: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 8
+// CHECK-X86_64: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK-X86_64: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 8
+// CHECK-X86_64: @"OBJC_EHTYPE_$_EH2" = external global
+// CHECK-X86_64: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 8
+// CHECK-X86_64: @"\01L_OBJC_LABEL_CLASS_$" = internal global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
+// CHECK-X86_64: define internal void @"\01-[A im0]"
+// CHECK-X86_64: define internal void @"\01-[A(Cat) im1]"
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fvisibility hidden -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix=CHECK-X86_64-HIDDEN < %t %s
+
+// CHECK-X86_64-HIDDEN: @"OBJC_CLASS_$_A" = hidden global {{.*}}, section "__DATA, __objc_data", align 8
+// CHECK-X86_64-HIDDEN: @"OBJC_METACLASS_$_A" = hidden global {{.*}}, section "__DATA, __objc_data", align 8
+// CHECK-X86_64-HIDDEN: @"OBJC_EHTYPE_$_EH1" = weak hidden global {{.*}}, section "__DATA,__datacoal_nt,coalesced"
+// CHECK-X86_64-HIDDEN: @"OBJC_EHTYPE_$_EH2" = external global
+// CHECK-X86_64-HIDDEN: @"OBJC_EHTYPE_$_EH3" = hidden global {{.*}}, section "__DATA,__objc_const", align 8
+// CHECK-X86_64-HIDDEN: define internal void @"\01-[A im0]"
+// CHECK-X86_64-HIDDEN: define internal void @"\01-[A(Cat) im1]"
-// RUN: grep '@"OBJC_METACLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t
-// RUN: grep '@"OBJC_CLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH1" = weak hidden global .*section "__DATA,__datacoal_nt,coalesced"' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH2" = external global' %t
-// RUN: grep '@"OBJC_EHTYPE_$_EH3" = hidden global .*section "__DATA,__objc_const", align 8' %t
-// RUN: grep -F 'define internal void @"\01-[A im0]"' %t
-// RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t
+// RUN: %clang_cc1 -triple armv6-apple-darwin10 -target-abi apcs-gnu -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: FileCheck -check-prefix=CHECK-ARMV6 < %t %s
+// CHECK-ARMV6: @"OBJC_CLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
+// CHECK-ARMV6: @"OBJC_METACLASS_$_A" = global {{.*}}, section "__DATA, __objc_data", align 4
+// CHECK-ARMV6: @"\01L_OBJC_CLASS_NAME_" = {{.*}}, section "__TEXT,__cstring,cstring_literals", align 1
+// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH1" = weak global {{.*}}, section "__DATA,__datacoal_nt,coalesced", align 4
+// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH2" = external global
+// CHECK-ARMV6: @"OBJC_EHTYPE_$_EH3" = global {{.*}}, section "__DATA,__objc_const", align 4
+// CHECK-ARMV6: @"\01L_OBJC_LABEL_CLASS_$" = internal global {{.*}}, section "__DATA, __objc_classlist, regular, no_dead_strip", align 4
+// CHECK-ARMV6: define internal arm_apcscc void @"\01-[A im0]"
+// CHECK-ARMV6: define internal arm_apcscc void @"\01-[A(Cat) im1]"
@interface A
@end
diff --git a/test/CodeGenObjC/next-objc-dispatch.m b/test/CodeGenObjC/next-objc-dispatch.m
new file mode 100644
index 000000000000..a3e8e19641eb
--- /dev/null
+++ b/test/CodeGenObjC/next-objc-dispatch.m
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-dispatch-method=legacy | \
+// RUN: FileCheck -check-prefix CHECK-FRAGILE_LEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_LEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=non-legacy | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_NONLEGACY %s
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o - %s \
+// RUN: -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed | \
+// RUN: FileCheck -check-prefix CHECK-NONFRAGILE_MIXED %s
+//
+// <rdar://problem/7866951>
+
+// There are basically four ways that we end up doing message dispatch for the
+// NeXT runtime. They are:
+// (1) fragile ABI, legacy dispatch
+// (2) non-fragile ABI, legacy dispatch
+// (2) non-fragile ABI, non-legacy dispatch
+// (2) non-fragile ABI, mixed dispatch
+//
+// Note that fragile ABI and non-fragile ABI legacy dispatch are not the same,
+// they use some different API calls (objc_msgSendSuper vs objc_msgSendSuper2).
+
+// CHECK-FRAGILE_LEGACY: ModuleID
+// CHECK-FRAGILE_LEGACY-NOT: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-FRAGILE_LEGACY-NOT: declare i8* @objc_msgSend_fixup(
+// CHECK-FRAGILE_LEGACY: declare i8* @objc_msgSendSuper(
+// CHECK-FRAGILE_LEGACY: declare i8* @objc_msgSend(
+
+// CHECK-NONFRAGILE_LEGACY: ModuleID
+// CHECK-NONFRAGILE_LEGACY-NOT: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_LEGACY-NOT: declare i8* @objc_msgSend_fixup(
+// CHECK-NONFRAGILE_LEGACY: declare i8* @objc_msgSendSuper2(
+// CHECK-NONFRAGILE_LEGACY: declare i8* @objc_msgSend(
+
+// CHECK-NONFRAGILE_NONLEGACY: ModuleID
+// CHECK-NONFRAGILE_NONLEGACY: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_NONLEGACY: declare i8* @objc_msgSend_fixup(
+
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSendSuper2_fixup(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSendSuper2(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSend_fixup(
+// CHECK-NONFRAGILE_MIXED: declare i8* @objc_msgSend(
+
+@interface NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@interface I0 : NSObject
+-(void) im0;
+@end
+
+@implementation I0
++(id) alloc {
+ return [super alloc];
+}
+-(id) init {
+ [super init];
+ return self;
+}
+-(void) im0 {}
+@end
+
+void f0(I0 *a) {
+ [I0 alloc];
+ [a im0];
+}
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
index 021db97de9fa..512ad897c7fe 100644
--- a/test/CodeGenObjC/non-lazy-classes.m
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -1,5 +1,5 @@
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CLASS_$" = internal global \[1 x .*\] .*@"OBJC_CLASS_$_A".*, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8' %t
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CATEGORY_$" = internal global \[1 x .*\] .*@".01l_OBJC_$_CATEGORY_A_$_Cat".*, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8' %t
diff --git a/test/CodeGenObjC/ns-constant-strings.m b/test/CodeGenObjC/ns-constant-strings.m
new file mode 100644
index 000000000000..3ef5f558422c
--- /dev/null
+++ b/test/CodeGenObjC/ns-constant-strings.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -fno-constant-cfstrings -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix CHECK-FRAGILE < %t %s
+
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fno-constant-cfstrings -emit-llvm -o %t %s
+// RUN: FileCheck --check-prefix CHECK-NONFRAGILE < %t %s
+
+@interface NSString @end
+
+@interface NSSimpleCString : NSString {
+@protected
+ char *bytes;
+ unsigned int numBytes;
+}
+@end
+
+@interface NSConstantString : NSSimpleCString
+@end
+
+#if OBJC_API_VERSION >= 2
+extern Class _NSConstantStringClassReference;
+#else
+extern struct objc_class _NSConstantStringClassReference;
+#endif
+
+const NSConstantString *appKey = @"MyApp";
+
+int main() {
+ const NSConstantString *appKey = @"MyApp";
+ const NSConstantString *appKey1 = @"MyApp1";
+}
+
+// CHECK-FRAGILE: @_NSConstantStringClassReference = external global
+// CHECK-NONFRAGILE: @"OBJC_CLASS_$_NSConstantString" = external global
diff --git a/test/CodeGenObjC/objc-gc-aggr-assign.m b/test/CodeGenObjC/objc-gc-aggr-assign.m
deleted file mode 100644
index e127242df257..000000000000
--- a/test/CodeGenObjC/objc-gc-aggr-assign.m
+++ /dev/null
@@ -1,46 +0,0 @@
-// RUN: %clang_cc1 -fobjc-gc -emit-llvm -o %t %s
-// RUN: grep objc_memmove_collectable %t | grep call | count 3
-
-static int count;
-
-typedef struct S {
- int ii;
-} SS;
-
-struct type_s {
- SS may_recurse;
- id id_val;
-};
-
-@interface NamedObject
-{
- struct type_s type_s_ivar;
-}
-- (void) setSome : (struct type_s) arg;
-- (struct type_s) getSome;
-@property(assign) struct type_s aggre_prop;
-@end
-
-@implementation NamedObject
-- (void) setSome : (struct type_s) arg
- {
- type_s_ivar = arg;
- }
-- (struct type_s) getSome
- {
- return type_s_ivar;
- }
-@synthesize aggre_prop = type_s_ivar;
-@end
-
-struct type_s some = {{1234}, (id)0};
-
-struct type_s get(void)
-{
- return some;
-}
-
-void f(const struct type_s *in, struct type_s *out) {
- *out = *in;
-}
-
diff --git a/test/CodeGenObjC/objc2-legacy-dispatch.m b/test/CodeGenObjC/objc2-legacy-dispatch.m
index 4c37573ad564..7a99d15ba0dc 100644
--- a/test/CodeGenObjC/objc2-legacy-dispatch.m
+++ b/test/CodeGenObjC/objc2-legacy-dispatch.m
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_NEW_DISPATCH %s
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed -triple i386-apple-darwin10 -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
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-dispatch-method=legacy -emit-llvm -o - %s | FileCheck -check-prefix=CHECK_OLD_DISPATCH %s
//
// CHECK_OLD_DISPATCH: define void @f0
// CHECK_OLD_DISPATCH: load {{.*}}OBJC_SELECTOR_REFERENCES
diff --git a/test/CodeGenObjC/x86_64-struct-return-gc.m b/test/CodeGenObjC/x86_64-struct-return-gc.m
index 32a321c0b7d0..c62a33f2d162 100644
--- a/test/CodeGenObjC/x86_64-struct-return-gc.m
+++ b/test/CodeGenObjC/x86_64-struct-return-gc.m
@@ -25,7 +25,7 @@ struct Indirect indirect_func(void);
void Indirect_test(void) {
struct Indirect i;
- // CHECK: call void @indirect_func(%struct.Indirect* noalias sret
+ // CHECK: call void @indirect_func(%struct.Indirect* sret
// CHECK: call i8* @objc_memmove_collectable(
i = indirect_func();
}
diff --git a/test/CodeGenObjCXX/ivar-objects.mm b/test/CodeGenObjCXX/ivar-objects.mm
new file mode 100644
index 000000000000..79c1a397e79e
--- /dev/null
+++ b/test/CodeGenObjCXX/ivar-objects.mm
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// CHECK: -[A .cxx_construct]
+// CHECK: -[A .cxx_destruct]
+
+@interface NSObject
+- alloc;
+- init;
+- (void) release;
+@end
+
+extern "C" int printf(const char *, ...);
+
+int count = 17;
+struct X {
+ X() : value(count++) { printf( "X::X()\n"); }
+ ~X() { printf( "X::~X()\n"); }
+ int value;
+};
+
+struct Y {
+ Y() : value(count++) { printf( "Y::Y()\n"); }
+ ~Y() { printf( "Y::~Y()\n"); }
+ int value;
+};
+
+@interface Super : NSObject {
+ Y yvar;
+ Y yvar1;
+ Y ya[3];
+}
+- (void)finalize;
+@end
+
+@interface A : Super {
+ X xvar;
+ X xvar1;
+ X xvar2;
+ X xa[2][2];
+}
+
+- (void)print;
+- (void)finalize;
+@end
+
+@implementation Super
+- (void)print {
+ printf( "yvar.value = %d\n", yvar.value);
+ printf( "yvar1.value = %d\n", yvar1.value);
+ printf( "ya[0..2] = %d %d %d\n", ya[0].value, ya[1].value, ya[2].value);
+}
+- (void)finalize {}
+@end
+
+@implementation A
+- (void)print {
+ printf( "xvar.value = %d\n", xvar.value);
+ printf( "xvar1.value = %d\n", xvar1.value);
+ printf( "xvar2.value = %d\n", xvar2.value);
+ printf( "xa[0..1][0..1] = %d %d %d %d\n",
+ xa[0][0].value, xa[0][1].value, xa[1][0].value, xa[1][1].value);
+ [super print];
+}
+- (void)finalize { [super finalize]; }
+@end
+
+int main() {
+ A *a = [[A alloc] init];
+ [a print];
+ [a release];
+}
+
diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm
index d277c4e51581..7a75a5b40e4c 100644
--- a/test/CodeGenObjCXX/mangle.mm
+++ b/test/CodeGenObjCXX/mangle.mm
@@ -2,6 +2,7 @@
// CHECK: @"_ZZ11+[A shared]E1a" = internal global
// CHECK: @"_ZZ11-[A(Foo) f]E1a" = internal global
+// CHECK: v56@0:8i16i20i24i28i32i36i40i44^i48
@interface A
@end
@@ -30,3 +31,14 @@
return 0;
}
@end
+
+// PR6468
+@interface Test
+- (void) process: (int)r3 :(int)r4 :(int)r5 :(int)r6 :(int)r7 :(int)r8 :(int)r9 :(int)r10 :(int &)i;
+@end
+
+@implementation Test
+- (void) process: (int)r3 :(int)r4 :(int)r5 :(int)r6 :(int)r7 :(int)r8 :(int)r9 :(int)r10 :(int &)i {
+}
+@end
+
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index ce0a5693b046..1a75fb4c6322 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -3,6 +3,6 @@
// RUN: %clang_cc1 -ast-dump %s
// FIXME: %clang_cc1 -ast-print-xml -o %t %s
// RUN: %clang_cc1 -print-decl-contexts %s
-// RUN: %clang_cc1 -dump-record-layouts %s
+// RUN: %clang_cc1 -fdump-record-layouts %s
#include "cxx-language-features.inc"
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 9ae81f178787..76ddaa873278 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -33,7 +33,7 @@
// Note that at conception, this exactly matches gcc.
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -miphoneos-version-min=2.0 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
-// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp" "-L/usr/lib/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../../i686-apple-darwin.*/4.2.1" "-L/usr/lib/gcc/i686-apple-darwin.*/4.2.1/../../.." "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log
+// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-iphoneos_version_min" "2.0" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-L" "ARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-F" "ARG1"' %t.log
// Don't run dsymutil on a fat build of an executable.
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -arch i386 -arch x86_64 -g %s 2> %t.log
diff --git a/test/Driver/darwin-objc-defaults.m b/test/Driver/darwin-objc-defaults.m
new file mode 100644
index 000000000000..4cf83a121d19
--- /dev/null
+++ b/test/Driver/darwin-objc-defaults.m
@@ -0,0 +1,88 @@
+// Check non-fragile ABI and dispatch method defaults.
+
+// i386
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch i386 -mmacosx-version-min=10.5 2> %t
+// RUN: FileCheck --check-prefix CHECK-I386_OSX10_5 < %t %s
+
+// CHECK-CHECK-I386_OSX10_5: "-cc1"
+// CHECK-CHECK-I386_OSX10_5-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_OSX10_5-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-I386_OSX10_5: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch i386 -mmacosx-version-min=10.6 2> %t
+// RUN: FileCheck --check-prefix CHECK-I386_OSX10_6 < %t %s
+
+// CHECK-CHECK-I386_OSX10_6: "-cc1"
+// CHECK-CHECK-I386_OSX10_6-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_OSX10_6-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-I386_OSX10_6: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch i386 -miphoneos-version-min=3.0 2> %t
+// RUN: FileCheck --check-prefix CHECK-I386_IPHONE3_0 < %t %s
+
+// CHECK-CHECK-I386_IPHONE3_0: "-cc1"
+// CHECK-CHECK-I386_IPHONE3_0-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_IPHONE3_0-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-I386_IPHONE3_0: darwin-objc-defaults
+
+// x86_64
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch x86_64 -mmacosx-version-min=10.5 2> %t
+// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_5 < %t %s
+
+// CHECK-CHECK-X86_64_OSX10_5: "-cc1"
+// CHECK-CHECK-X86_64_OSX10_5: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_OSX10_5: -fobjc-dispatch-method=non-legacy
+// CHECK-CHECK-X86_64_OSX10_5: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch x86_64 -mmacosx-version-min=10.6 2> %t
+// RUN: FileCheck --check-prefix CHECK-X86_64_OSX10_6 < %t %s
+
+// CHECK-CHECK-X86_64_OSX10_6: "-cc1"
+// CHECK-CHECK-X86_64_OSX10_6: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_OSX10_6: -fobjc-dispatch-method=mixed
+// CHECK-CHECK-X86_64_OSX10_6: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch x86_64 -miphoneos-version-min=3.0 2> %t
+// RUN: FileCheck --check-prefix CHECK-X86_64_IPHONE3_0 < %t %s
+
+// CHECK-CHECK-X86_64_IPHONE3_0: "-cc1"
+// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_IPHONE3_0: -fobjc-dispatch-method=mixed
+// CHECK-CHECK-X86_64_IPHONE3_0: darwin-objc-defaults
+
+// armv7
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch armv7 -mmacosx-version-min=10.5 2> %t
+// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_5 < %t %s
+
+// CHECK-CHECK-ARMV7_OSX10_5: "-cc1"
+// CHECK-CHECK-ARMV7_OSX10_5: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_OSX10_5-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-ARMV7_OSX10_5: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch armv7 -mmacosx-version-min=10.6 2> %t
+// RUN: FileCheck --check-prefix CHECK-ARMV7_OSX10_6 < %t %s
+
+// CHECK-CHECK-ARMV7_OSX10_6: "-cc1"
+// CHECK-CHECK-ARMV7_OSX10_6: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_OSX10_6-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-ARMV7_OSX10_6: darwin-objc-defaults
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch armv7 -miphoneos-version-min=3.0 2> %t
+// RUN: FileCheck --check-prefix CHECK-ARMV7_IPHONE3_0 < %t %s
+
+// CHECK-CHECK-ARMV7_IPHONE3_0: "-cc1"
+// CHECK-CHECK-ARMV7_IPHONE3_0: -fobjc-nonfragile-abi
+// CHECK-CHECK-ARMV7_IPHONE3_0-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-ARMV7_IPHONE3_0: darwin-objc-defaults
diff --git a/test/Driver/darwin-objc-gc.m b/test/Driver/darwin-objc-gc.m
new file mode 100644
index 000000000000..aecb9a6b146f
--- /dev/null
+++ b/test/Driver/darwin-objc-gc.m
@@ -0,0 +1,19 @@
+// Check that we warn, but accept, -fobjc-gc for iPhone OS.
+
+// RUN: %clang -ccc-host-triple i386-apple-darwin9 -miphoneos-version-min=3.0 -fobjc-gc -flto -S -o %t %s 2> %t.err
+// RUN: FileCheck --check-prefix=IPHONE_OBJC_GC_LL %s < %t
+// RUN: FileCheck --check-prefix=IPHONE_OBJC_GC_STDERR %s < %t.err
+
+// IPHONE_OBJC_GC_LL: define void @f0
+// IPHONE_OBJC_GC_LL-NOT: objc_assign_ivar
+// IPHONE_OBJC_GC_LL: }
+
+// IPHONE_OBJC_GC_STDERR: warning: Objective-C garbage collection is not supported on this platform, ignoring '-fobjc-gc'
+
+@interface A {
+@public
+ id x;
+}
+@end
+
+void f0(A *a, id x) { a->x = x; }
diff --git a/test/Driver/darwin-objc-options.m b/test/Driver/darwin-objc-options.m
new file mode 100644
index 000000000000..bc0b12cf55b0
--- /dev/null
+++ b/test/Driver/darwin-objc-options.m
@@ -0,0 +1,19 @@
+// Check miscellaneous Objective-C options.
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch x86_64 -fobjc-abi-version=1 2> %t
+// RUN: FileCheck --check-prefix CHECK-X86_64_ABI1 < %t %s
+
+// CHECK-CHECK-X86_64_ABI1: "-cc1"
+// CHECK-CHECK-X86_64_ABI1-NOT: -fobjc-nonfragile-abi
+// CHECK-CHECK-X86_64_ABI1-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-X86_64_ABI1: darwin-objc-options
+
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -S -### %s \
+// RUN: -arch i386 -fobjc-abi-version=2 2> %t
+// RUN: FileCheck --check-prefix CHECK-I386_ABI2 < %t %s
+
+// CHECK-CHECK-I386_ABI2: "-cc1"
+// CHECK-CHECK-I386_ABI2: -fobjc-nonfragile-abi
+// CHECK-CHECK-I386_ABI2-NOT: -fobjc-dispatch-method
+// CHECK-CHECK-I386_ABI2: darwin-objc-options
diff --git a/test/FixIt/fixit-at.c b/test/FixIt/fixit-at.c
deleted file mode 100644
index c32aee9ea174..000000000000
--- a/test/FixIt/fixit-at.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang_cc1 -fixit-at=fixit-at.c:3:1 %s -o - | %clang_cc1 -verify -x c -
-
-_Complex cd;
-
-int i0[1] = { { 17 } }; // expected-warning{{braces}}
diff --git a/test/FixIt/fixit-c90.c b/test/FixIt/fixit-c90.c
index e84733f49dbc..0bc1fada8b6b 100644
--- a/test/FixIt/fixit-c90.c
+++ b/test/FixIt/fixit-c90.c
@@ -1,4 +1,10 @@
-/* RUN: %clang_cc1 -std=c90 -pedantic -fixit %s -o - | %clang_cc1 -pedantic -x c -std=c90 -Werror -
+/* RUN: cp %s %t
+ RUN: %clang_cc1 -std=c90 -pedantic -fixit %t
+ RUN: %clang_cc1 -pedantic -x c -std=c90 -Werror %t
+ */
+/* XPASS: *
+ This test passes because clang merely warns for this syntax error even with
+ -pedantic -Werror -std=c90.
*/
/* This is a test of the various code modification hints that are
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 3694b9db1af3..d8a858d9da74 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -1,13 +1,15 @@
-/* RUN: %clang_cc1 -std=c++0x -fixit %s -o - | %clang_cc1 -x c++ -std=c++0x -
- */
+// RUN: %clang_cc1 -verify -std=c++0x %s
+// RUN: cp %s %t
+// RUN: %clang_cc1 -std=c++0x -fixit %t || true
+// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++0x %t
/* This is a test of the various code modification hints that only
apply in C++0x. */
-struct A {
+struct A {
explicit operator int(); // expected-note{{conversion to integral type}}
};
-void x() {
+void x() {
switch(A()) { // expected-error{{explicit conversion to}}
}
}
diff --git a/test/FixIt/fixit-errors-1.c b/test/FixIt/fixit-errors-1.c
index ecad53ceb83d..96f27eb6d0e9 100644
--- a/test/FixIt/fixit-errors-1.c
+++ b/test/FixIt/fixit-errors-1.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o - | %clang_cc1 -pedantic -Werror -x c -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -fixit %t
+// RUN: echo %clang_cc1 -pedantic -Werror -x c %t
+/* XPASS: * */
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c
index 7bf9a58430f1..ff063635f693 100644
--- a/test/FixIt/fixit-errors.c
+++ b/test/FixIt/fixit-errors.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o - | %clang_cc1 -pedantic -Werror -x c -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -verify -fixit -x c %t || true
+// RUN: %clang_cc1 -pedantic -Werror -x c %t
+// XFAIL: *
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index 665ac74441ae..03f28a1b586a 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o %t
-// RUN: %clang_cc1 -pedantic -x objective-c %t -verify
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -fixit -x objective-c %t
+// RUN: %clang_cc1 -pedantic -verify -x objective-c %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -27,7 +28,7 @@ void h(id a);
void f(Test *t) {
NSString *a = "Foo";
id b = "Foo";
- A* c = "Foo"; // expected-warning {{incompatible pointer types initializing 'char [4]', expected 'A *'}}
+ A* c = "Foo"; // expected-warning {{incompatible pointer types initializing 'A *' with an expression of type 'char [4]'}}
g("Foo");
h("Foo");
h(("Foo"));
diff --git a/test/FixIt/fixit-pmem.cpp b/test/FixIt/fixit-pmem.cpp
index 0926309a9ab8..b69eadf15a05 100644
--- a/test/FixIt/fixit-pmem.cpp
+++ b/test/FixIt/fixit-pmem.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -fixit -x c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
+// XFAIL: *
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
diff --git a/test/FixIt/fixit-suffix.c b/test/FixIt/fixit-suffix.c
new file mode 100644
index 000000000000..a1a747a95a58
--- /dev/null
+++ b/test/FixIt/fixit-suffix.c
@@ -0,0 +1,5 @@
+// RUN: cp %s %t.extrasuffix
+// RUN: %clang_cc1 -fixit=fixed -x c %t.extrasuffix
+// RUN: %clang_cc1 -Werror -pedantic -x c %t.fixed.extrasuffix
+
+_Complex cd;
diff --git a/test/FixIt/fixit-unrecoverable.c b/test/FixIt/fixit-unrecoverable.c
new file mode 100644
index 000000000000..8052beb5591c
--- /dev/null
+++ b/test/FixIt/fixit-unrecoverable.c
@@ -0,0 +1,10 @@
+/* FIXME: This is a file containing various typos for which we can
+ suggest corrections but are unable to actually recover from
+ them. Ideally, we would eliminate all such cases and move these
+ tests elsewhere. */
+
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// FIXME: Sadly, the following doesn't work within a function.
+
+unsinged x = 17; // expected-error{{unknown type name 'unsinged'; did you mean 'unsigned'?}}
diff --git a/test/FixIt/fixit-unrecoverable.cpp b/test/FixIt/fixit-unrecoverable.cpp
new file mode 100644
index 000000000000..00ed8978c610
--- /dev/null
+++ b/test/FixIt/fixit-unrecoverable.cpp
@@ -0,0 +1,11 @@
+/* FIXME: This is a file containing various typos for which we can
+ suggest corrections but are unable to actually recover from
+ them. Ideally, we would eliminate all such cases and move these
+ tests elsewhere. */
+
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+float f(int y) {
+ return static_cst<float>(y); // expected-error{{use of undeclared identifier 'static_cst'; did you mean 'static_cast'?}}
+}
+
diff --git a/test/FixIt/fixit.c b/test/FixIt/fixit.c
index 83d724dffc01..b799fa3b3b88 100644
--- a/test/FixIt/fixit.c
+++ b/test/FixIt/fixit.c
@@ -1,6 +1,8 @@
-// RUN: %clang_cc1 -pedantic -fixit %s -o - | grep -v 'CHECK' > %t
-// RUN: %clang_cc1 -pedantic -Werror -x c -
-// RUN: FileCheck -input-file=%t %s
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -fixit -x c %t || true
+// RUN: grep -v CHECK %t > %t2
+// RUN: %clang_cc1 -pedantic -Werror -x c %t
+// RUN: FileCheck -input-file=%t2 %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -25,15 +27,14 @@ struct s s0 = { y: 5 };
// CHECK: int array0[5] = { [3] = 3 };
int array0[5] = { [3] 3 };
-void f1(x, y)
+void f1(x, y)
{
}
int i0 = { 17 };
-int f2(const char *my_string) {
- // FIXME: terminal output isn't so good when "my_string" is shorter
-// CHECK: return strcmp(my_string , "foo") == 0;
- return my_string == "foo";
+int test_cond(int y, int fooBar) {
+// CHECK: int x = y ? 1 : 4+fooBar;
+ int x = y ? 1 4+foobar;
+ return x;
}
-
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 79c294b1d929..b9282c4d9481 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,11 +1,13 @@
-// RUN: %clang_cc1 -pedantic -Wall -fixit %s -o - | %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x c++ -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -pedantic -Wall -fixit -x c++ %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -x c++ %t
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
warnings will be fixed by -fixit, and the resulting file should
compile cleanly with -Werror -pedantic. */
-struct C1 {
+struct C1 {
virtual void f();
static void g();
};
@@ -40,3 +42,12 @@ class B : public A {
void f() throw();
void f(); // expected-warning{{missing exception specification}}
+
+namespace rdar7853795 {
+ struct A {
+ bool getNumComponents() const; // expected-note{{declared here}}
+ void dump() const {
+ getNumComponenets(); // expected-error{{use of undeclared identifier 'getNumComponenets'; did you mean 'getNumComponents'?}}
+ }
+ };
+}
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 72e3d658e7b6..01ff3a09cf3e 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x c -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -fixit -x c %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c %t
struct Point {
float x, y;
};
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index efc9ba890c6f..5b9e68bbfd3d 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -1,7 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -fixit -x c++ %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
namespace std {
template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}}
+ public:
int find(const char *substr); // expected-note{{'find' declared here}}
static const int npos = -1; // expected-note{{'npos' declared here}}
};
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index 86dd383c904e..f161bb8d9948 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,8 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// FIXME: the test below isn't testing quite what we want...
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c -
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -fixit %t || true
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c %t
+// XFAIL: *
-@interface NSString
+@interface NSString // expected-note{{'NSString' declared here}}
+ (int)method:(int)x;
@end
@@ -57,8 +59,7 @@ void test() {
@end
void test_message_send(B* b) {
- // FIXME: Not providing fix-its
- [NSstring method:17]; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}}
+ [NSstring method:17]; // expected-error{{unknown receiver 'NSstring'; did you mean 'NSString'?}}
}
@interface Collide // expected-note{{'Collide' declared here}}
@@ -88,3 +89,52 @@ void test2(Collide *a) {
@interface IPv6 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}}
@end
+
+@interface Super
+- (int)method;
+@end
+
+@interface Sub : Super
+- (int)method;
+@end
+
+@implementation Sub
+- (int)method {
+ return [supper method]; // expected-error{{unknown receiver 'supper'; did you mean 'super'?}}
+}
+
+@end
+
+@interface Ivar
+@end
+
+@protocol Proto
+@property (retain) id ivar;
+@end
+
+@interface User <Proto>
+- (void)method;
+@end
+
+@implementation User
+@synthesize ivar;
+
+- (void)method {
+ [ivar method]; // Test that we don't correct 'ivar' to 'Ivar'
+}
+@end
+
+@interface User2
+@end
+
+@interface User2 (Cat) < Proto>
+- (void)method;
+@end
+
+@implementation User2 (Cat)
+@synthesize ivar;
+
+- (void)method {
+ [ivar method]; // Test that we don't correct 'ivar' to 'Ivar'
+}
+@end
diff --git a/test/Index/Inputs/complete-pch.h b/test/Index/Inputs/complete-pch.h
new file mode 100644
index 000000000000..ddf5253c134d
--- /dev/null
+++ b/test/Index/Inputs/complete-pch.h
@@ -0,0 +1,10 @@
+@interface A
+- (int)instanceMethod1:(int)x;
++ (int)classMethod1:(double)d;
+@end
+
+@interface B
+- (int)instanceMethod2:(int)x;
++ (int)classMethod2:(float)f;
+@end
+
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 1badeb20be79..ce399d34c6f2 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -5,10 +5,11 @@
@implementation Foo
- (int)compare:(Foo*)other {
return 0;
+ (void)@encode(Foo);
}
@end
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:9:5 %s | FileCheck %s
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:10:5 %s | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2]
// CHECK: Identifier: "interface" [1:2 - 1:11]
// CHECK: Identifier: "Foo" [1:12 - 1:15] ObjCInterfaceDecl=Foo:1:12
@@ -44,6 +45,15 @@
// CHECK: Keyword: "return" [7:3 - 7:9]
// CHECK: Literal: "0" [7:10 - 7:11]
// CHECK: Punctuation: ";" [7:11 - 7:12]
-// CHECK: Punctuation: "}" [8:1 - 8:2]
-// CHECK: Punctuation: "@" [9:1 - 9:2]
-// CHECK: Identifier: "end" [9:2 - 9:5]
+// CHECK: Punctuation: "(" [8:3 - 8:4]
+// CHECK: Keyword: "void" [8:4 - 8:8]
+// CHECK: Punctuation: ")" [8:8 - 8:9]
+// CHECK: Punctuation: "@" [8:9 - 8:10]
+// CHECK: Identifier: "encode" [8:10 - 8:16]
+// CHECK: Punctuation: "(" [8:16 - 8:17]
+// CHECK: Identifier: "Foo" [8:17 - 8:20] ObjCClassRef=Foo:1:12
+// CHECK: Punctuation: ")" [8:20 - 8:21]
+// CHECK: Punctuation: ";" [8:21 - 8:22]
+// CHECK: Punctuation: "}" [9:1 - 9:2]
+// CHECK: Punctuation: "@" [10:1 - 10:2]
+// CHECK: Identifier: "end" [10:2 - 10:5]
diff --git a/test/Index/complete-at-directives.m b/test/Index/complete-at-directives.m
index 1d0a471dbbca..811bca00efb0 100644
--- a/test/Index/complete-at-directives.m
+++ b/test/Index/complete-at-directives.m
@@ -6,7 +6,7 @@
@end
// RUN: c-index-test -code-completion-at=%s:2:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: {TypedText class}{HorizontalSpace }{Placeholder identifier}{SemiColon ;}
+// CHECK-CC1: {TypedText class}{HorizontalSpace }{Placeholder identifier}
// CHECK-CC1: {TypedText compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
// CHECK-CC1: {TypedText implementation}{HorizontalSpace }{Placeholder class}
// CHECK-CC1: {TypedText interface}{HorizontalSpace }{Placeholder class}
@@ -24,7 +24,7 @@
// CHECK-CC3: {TypedText synthesize}{HorizontalSpace }{Placeholder property}
// RUN: c-index-test -code-completion-at=%s:2:1 %s | FileCheck -check-prefix=CHECK-CC4 %s
-// CHECK-CC4: NotImplemented:{TypedText @class}{HorizontalSpace }{Placeholder identifier}{SemiColon ;}
+// CHECK-CC4: NotImplemented:{TypedText @class}{HorizontalSpace }{Placeholder identifier}
// CHECK-CC4: NotImplemented:{TypedText @compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
// CHECK-CC4: NotImplemented:{TypedText @implementation}{HorizontalSpace }{Placeholder class}
// CHECK-CC4: NotImplemented:{TypedText @interface}{HorizontalSpace }{Placeholder class}
diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m
index e8efc3cf46f1..87e554ff22ae 100644
--- a/test/Index/complete-at-exprstmt.m
+++ b/test/Index/complete-at-exprstmt.m
@@ -14,7 +14,7 @@
// CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
// CHECK-CC1: {TypedText synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
-// CHECK-CC1: {TypedText throw}{HorizontalSpace }{Placeholder expression}{SemiColon ;}
+// CHECK-CC1: {TypedText throw}{HorizontalSpace }{Placeholder expression}
// CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
@@ -25,7 +25,7 @@
// CHECK-CC3: NotImplemented:{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC3: NotImplemented:{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )}
// CHECK-CC3: NotImplemented:{TypedText @synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
-// CHECK-CC3: NotImplemented:{TypedText @throw}{HorizontalSpace }{Placeholder expression}{SemiColon ;}
+// CHECK-CC3: NotImplemented:{TypedText @throw}{HorizontalSpace }{Placeholder expression}
// CHECK-CC3: NotImplemented:{TypedText @try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
// CHECK-CC3: NotImplemented:{ResultType SEL}{TypedText _cmd}
// CHECK-CC3: ParmDecl:{ResultType int}{TypedText arg}
diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c
new file mode 100644
index 000000000000..efc82f90a9e6
--- /dev/null
+++ b/test/Index/complete-exprs.c
@@ -0,0 +1,15 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+int f(int);
+
+int test(int i, int j, int k, int l) {
+ return i | j | k & l;
+}
+
+// RUN: c-index-test -code-completion-at=%s:7:9 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )}
+// CHECK-CC1: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )}
+// RUN: c-index-test -code-completion-at=%s:7:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:18 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: c-index-test -code-completion-at=%s:7:22 %s | FileCheck -check-prefix=CHECK-CC1 %s
diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m
new file mode 100644
index 000000000000..c18994ec20a9
--- /dev/null
+++ b/test/Index/complete-method-decls.m
@@ -0,0 +1,82 @@
+/* Note: the RUN lines are near the end of the file, since line/column
+ matter for this test. */
+
+@protocol P1
+- (id)abc;
+- (id)initWithInt:(int)x;
+- (id)initWithTwoInts:(int)x second:(int)y;
+- (int)getInt;
+- (id)getSelf;
+@end
+
+@protocol P2<P1>
++ (id)alloc;
+@end
+
+@interface A <P1>
+- (id)init;
+- (int)getValue;
+@end
+
+@interface B : A<P2>
+- (id)initWithInt:(int)x;
+- (int)getSecondValue;
+- (id)getSelf;
+- (int)setValue:(int)x;
+@end
+
+@interface B (FooBar)
+- (id)categoryFunction:(int)x;
+@end
+
+@implementation B
+- (int)getSecondValue { return 0; }
+- (id)init { return self; }
+- (id)getSelf { return self; }
+- (void)setValue:(int)x { }
+- (id)initWithTwoInts:(int)x second:(int)y { return self; }
++ (id)alloc { return 0; }
+@end
+
+@implementation B (FooBar)
+- (id)categoryFunction:(int)x { return self; }
+@end
+
+// RUN: c-index-test -code-completion-at=%s:17:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText abc}
+// CHECK-CC1: NotImplemented:{LeftParen (}{Text int}{RightParen )}{TypedText getInt}
+// CHECK-CC1: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}
+// CHECK-CC1: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}
+// CHECK-CC1: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}
+// RUN: c-index-test -code-completion-at=%s:17:7 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: NotImplemented:{TypedText abc}
+// CHECK-CC2-NEXT: NotImplemented:{TypedText getSelf}
+// CHECK-CC2: NotImplemented:{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}
+// CHECK-CC2: NotImplemented:{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}
+// RUN: c-index-test -code-completion-at=%s:24:7 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: NotImplemented:{TypedText abc}
+// CHECK-CC3-NEXT: NotImplemented:{TypedText getSelf}
+// CHECK-CC3: NotImplemented:{TypedText init}
+// CHECK-CC3: NotImplemented:{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}
+// CHECK-CC3: NotImplemented:{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}
+// RUN: c-index-test -code-completion-at=%s:33:3 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text int}{RightParen )}{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text int}{RightParen )}{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC4: NotImplemented:{LeftParen (}{Text int}{RightParen )}{TypedText setValue}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// RUN: c-index-test -code-completion-at=%s:33:8 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: NotImplemented:{TypedText getInt}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC5: NotImplemented:{TypedText getSecondValue}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC5-NOT: {TypedText getSelf}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC5: NotImplemented:{TypedText setValue}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// RUN: c-index-test -code-completion-at=%s:37:7 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: NotImplemented:{TypedText abc}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC6-NOT: getSelf
+// CHECK-CC6: NotImplemented:{TypedText initWithInt}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// CHECK-CC6: NotImplemented:{TypedText initWithTwoInts}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{Text second}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text y}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+// RUN: c-index-test -code-completion-at=%s:42:3 %s | FileCheck -check-prefix=CHECK-CC7 %s
+// CHECK-CC7: NotImplemented:{LeftParen (}{Text id}{RightParen )}{TypedText categoryFunction}{Colon :}{LeftParen (}{Text int}{RightParen )}{Text x}{HorizontalSpace }{LeftBrace {}{VerticalSpace
+
diff --git a/test/Index/complete-objc-message-id.m b/test/Index/complete-objc-message-id.m
new file mode 100644
index 000000000000..a75ee4a81d5c
--- /dev/null
+++ b/test/Index/complete-objc-message-id.m
@@ -0,0 +1,42 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@interface A
++ (id)alloc;
++ (id)init;
++ (id)new;
++ (Class)class;
++ (Class)superclass;
+- (id)retain;
+- (id)autorelease;
+- (id)superclass;
+@end
+
+@interface B : A
+- (int)B_method;
+@end
+
+@interface Unrelated
++ (id)icky;
+@end
+
+void message_id(B *b) {
+ [[A alloc] init];
+ [[b retain] B_method];
+ [[b superclass] B_method];
+}
+
+// RUN: c-index-test -code-completion-at=%s:24:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC1-NOT: B_method
+// CHECK-CC1: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+// RUN: c-index-test -code-completion-at=%s:25:15 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText B_method}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+// RUN: c-index-test -code-completion-at=%s:26:19 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType id}{TypedText autorelease}
+// CHECK-CC3-NOT: B_method
+// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType id}{TypedText retain}
+
+
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index 096ed24c221c..e65a056e36c3 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -103,6 +103,25 @@ void f(Ellipsis *e) {
[e Method:1, 2, 3];
}
+@interface Overload2
++ (int)Method:(int)i;
++ (int)Method;
++ (int)Method:(float)f Arg1:(int)i1 Arg2:(int)i2;
++ (int)Method:(float)f Arg1:(int)i1 OtherArg:(id)obj;
++ (int)Method:(float)f SomeArg:(int)i1 OtherArg:(id)obj;
++ (int)OtherMethod:(float)f Arg1:(int)i1 Arg2:(int)i2;
+@end
+
+void test_overload2(void) {
+ [Overload2 Method:1 Arg1:1 OtherArg:ovl];
+}
+
+void msg_id(id x) {
+ [x Method:1 Arg1:1 OtherArg:ovl];
+ [[x blarg] Method:1 Arg1:1 OtherArg:ovl];
+ [id Method:1 Arg1:1 OtherArg:ovl];
+}
+
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText categoryClassMethod}
// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)b}
@@ -153,3 +172,62 @@ void f(Ellipsis *e) {
// CHECK-CCA: {TypedText super}
// RUN: c-index-test -code-completion-at=%s:103:6 %s | FileCheck -check-prefix=CHECK-CCB %s
// CHECK-CCB: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}{Placeholder , ...}
+// RUN: c-index-test -code-completion-at=%s:116:14 %s | FileCheck -check-prefix=CHECK-CCC %s
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText Method}
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCC: ObjCClassMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// RUN: c-index-test -code-completion-at=%s:116:23 %s | FileCheck -check-prefix=CHECK-CCD %s
+// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText }
+// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCD: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{TypedText SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// RUN: c-index-test -code-completion-at=%s:116:30 %s | FileCheck -check-prefix=CHECK-CCE %s
+// CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)i2}
+// CHECK-CCE: ObjCClassMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)obj}
+// RUN: c-index-test -code-completion-at=%s:61:11 %s | FileCheck -check-prefix=CHECK-CCF %s
+// CHECK-CCF: {ResultType SEL}{TypedText _cmd}
+// CHECK-CCF: TypedefDecl:{TypedText Class}
+// CHECK-CCF: ObjCInterfaceDecl:{TypedText Foo}
+// CHECK-CCF: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{RightParen )}
+// CHECK-CCF: TypedefDecl:{TypedText id}
+// CHECK-CCF: ObjCInterfaceDecl:{TypedText MyClass}
+// CHECK-CCF: ObjCInterfaceDecl:{TypedText MySubClass}
+// CHECK-CCF: TypedefDecl:{TypedText SEL}
+// CHECK-CCF: {ResultType Class}{TypedText self}
+// CHECK-CCF: {TypedText super}
+// RUN: c-index-test -code-completion-at=%s:120:6 %s | FileCheck -check-prefix=CHECK-CCG %s
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText categoryInstanceMethod}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText instanceMethod1}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod:}{Placeholder (id)obj}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType id}{TypedText protocolInstanceMethod:}{Placeholder (int)value}
+// CHECK-CCG: ObjCInstanceMethodDecl:{ResultType int}{TypedText secondProtocolInstanceMethod}
+// RUN: c-index-test -code-completion-at=%s:121:14 %s | FileCheck -check-prefix=CHECK-CCG %s
+// RUN: c-index-test -code-completion-at=%s:122:7 %s | FileCheck -check-prefix=CHECK-CCH %s
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText categoryClassMethod}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod1:}{Placeholder (id)a}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)b}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType void}{TypedText classMethod2}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MyClassMethod:}{Placeholder (id)obj}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MyPrivateMethod}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MySubClassMethod}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText MySubPrivateMethod}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText new}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CCH: ObjCClassMethodDecl:{ResultType id}{TypedText protocolClassMethod}
+
diff --git a/test/Index/complete-pch.m b/test/Index/complete-pch.m
new file mode 100644
index 000000000000..09192ae1139d
--- /dev/null
+++ b/test/Index/complete-pch.m
@@ -0,0 +1,26 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@interface C
+- (int)instanceMethod3:(int)x;
++ (int)classMethod3:(float)f;
+@end
+
+void msg_id(id x) {
+ [id classMethod1:1.0];
+ [x instanceMethod1:5];
+}
+
+// Build the precompiled header
+// RUN: %clang -x objective-c-header -o %t.h.pch %S/Inputs/complete-pch.h
+
+// Run the actual tests
+// RUN: c-index-test -code-completion-at=%s:10:7 -include %t.h %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod1:}{Placeholder (double)d}
+// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod2:}{Placeholder (float)f}
+// CHECK-CC1: ObjCClassMethodDecl:{ResultType int}{TypedText classMethod3:}{Placeholder (float)f}
+
+// RUN: c-index-test -code-completion-at=%s:11:6 -include %t.h %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod1:}{Placeholder (int)x}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod2:}{Placeholder (int)x}
+// CHECK-CC2: ObjCInstanceMethodDecl:{ResultType int}{TypedText instanceMethod3:}{Placeholder (int)x}
diff --git a/test/Index/invalid-code-rdar_7833619.m b/test/Index/invalid-code-rdar_7833619.m
new file mode 100644
index 000000000000..0034539ad102
--- /dev/null
+++ b/test/Index/invalid-code-rdar_7833619.m
@@ -0,0 +1,4 @@
+// RUN: c-index-test -test-load-source all %s
+// All we care about in this test is that it doesn't crash.
+typedef r7833619_a (*r7833619_b)(r7833619_c *r7833619_d, r7833619_c *r7833619_e);
+
diff --git a/test/Index/load-exprs.c b/test/Index/load-exprs.c
index f72f1046c2e8..248bc6ebf580 100644
--- a/test/Index/load-exprs.c
+++ b/test/Index/load-exprs.c
@@ -7,12 +7,49 @@ void f(void *ptr) {
void *xx = ptr ? : &x;
}
-// RUN: c-index-test -test-load-source all %s | FileCheck %s
+int test_blocks(int x) {
+ __block int y = x;
+ ^{
+ static int z = 0;
+ y = (++z) + x;
+ ^{
+ ++z;
+ ++y;
+ }();
+ }();
+ return y;
+}
+
+// RUN: c-index-test -test-load-source all %s -fblocks | FileCheck %s
+// CHECK: load-exprs.c:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14]
+// CHECK: load-exprs.c:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23]
+// CHECK: load-exprs.c:2:16: FieldDecl=a:2:16 (Definition) Extent=[2:16 - 2:17]
+// CHECK: load-exprs.c:2:19: FieldDecl=b:2:19 (Definition) Extent=[2:19 - 2:20]
+// CHECK: load-exprs.c:3:6: FunctionDecl=f:3:6 (Definition) Extent=[3:6 - 8:2]
+// CHECK: load-exprs.c:3:14: ParmDecl=ptr:3:14 (Definition) Extent=[3:8 - 3:17]
+// CHECK: load-exprs.c:4:6: VarDecl=t_ptr:4:6 (Definition) Extent=[4:3 - 4:22]
+// CHECK: load-exprs.c:4:3: TypeRef=T:1:13 Extent=[4:3 - 4:4]
// CHECK: load-exprs.c:4:15: TypeRef=T:1:13 Extent=[4:15 - 4:16]
+// CHECK: load-exprs.c:4:19: DeclRefExpr=ptr:3:14 Extent=[4:19 - 4:22]
// CHECK: load-exprs.c:5:16: TypeRef=T:1:13 Extent=[5:16 - 5:17]
+// CHECK: load-exprs.c:6:12: VarDecl=x:6:12 (Definition) Extent=[6:10 - 6:32]
// CHECK: load-exprs.c:6:10: TypeRef=struct X:2:8 Extent=[6:10 - 6:11]
// CHECK: load-exprs.c:6:24: TypeRef=struct X:2:8 Extent=[6:24 - 6:25]
// CHECK: load-exprs.c:7:9: VarDecl=xx:7:9 (Definition) Extent=[7:3 - 7:24]
// CHECK: load-exprs.c:7:14: DeclRefExpr=ptr:3:14 Extent=[7:14 - 7:17]
// CHECK: load-exprs.c:7:23: DeclRefExpr=x:6:12 Extent=[7:23 - 7:24]
+// CHECK: load-exprs.c:10:5: FunctionDecl=test_blocks:10:5 (Definition) Extent=[10:5 - 21:2]
+// CHECK: load-exprs.c:10:21: ParmDecl=x:10:21 (Definition) Extent=[10:17 - 10:22]
+// CHECK: load-exprs.c:11:15: VarDecl=y:11:15 (Definition) Extent=[11:11 - 11:20]
+// CHECK: load-exprs.c:11:19: DeclRefExpr=x:10:21 Extent=[11:19 - 11:20]
+// CHECK: load-exprs.c:12:3: CallExpr= Extent=[12:3 - 19:7]
+// CHECK: load-exprs.c:13:17: VarDecl=z:13:17 (Definition) Extent=[13:13 - 13:22]
+// CHECK: load-exprs.c:14:6: DeclRefExpr= Extent=[14:6 - 14:7]
+// CHECK: load-exprs.c:14:13: DeclRefExpr=z:13:17 Extent=[14:13 - 14:14]
+// CHECK: load-exprs.c:14:18: DeclRefExpr= Extent=[14:18 - 14:19]
+// CHECK: load-exprs.c:15:6: CallExpr= Extent=[15:6 - 18:9]
+// CHECK: load-exprs.c:16:10: DeclRefExpr=z:13:17 Extent=[16:10 - 16:11]
+// CHECK: load-exprs.c:17:10: DeclRefExpr= Extent=[17:10 - 17:11]
+// CHECK: load-exprs.c:20:10: DeclRefExpr=y:11:15 Extent=[20:10 - 20:11]
+
diff --git a/test/Index/local-symbols.m b/test/Index/local-symbols.m
new file mode 100644
index 000000000000..8557e7f49b2d
--- /dev/null
+++ b/test/Index/local-symbols.m
@@ -0,0 +1,26 @@
+// RUN: c-index-test -test-load-source local %s | FileCheck %s
+
+// From: <rdar://problem/7568881>
+// The method 'bar' was also being reported outside the @implementation
+
+@interface Foo {
+ id x;
+}
+- (id) bar;
+@end
+
+@implementation Foo
+- (id) bar {
+ return 0;
+}
+@end
+
+// CHECK: local-symbols.m:6:12: ObjCInterfaceDecl=Foo:6:12 Extent=[6:1 - 10:5]
+// CHECK: local-symbols.m:7:6: ObjCIvarDecl=x:7:6 (Definition) Extent=[7:6 - 7:7]
+// CHECK: local-symbols.m:7:3: TypeRef=id:0:0 Extent=[7:3 - 7:5]
+// CHECK: local-symbols.m:9:1: ObjCInstanceMethodDecl=bar:9:1 Extent=[9:1 - 9:12]
+// CHECK: local-symbols.m:9:4: TypeRef=id:0:0 Extent=[9:4 - 9:6]
+// CHECK: local-symbols.m:12:1: ObjCImplementationDecl=Foo:12:1 (Definition) Extent=[12:1 - 16:2]
+// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) Extent=[13:1 - 15:2]
+// CHECK: local-symbols.m:13:4: TypeRef=id:0:0 Extent=[13:4 - 13:6]
+
diff --git a/test/Index/print-usrs.c b/test/Index/print-usrs.c
index 9cd64f786e6c..898778b11e7d 100644
--- a/test/Index/print-usrs.c
+++ b/test/Index/print-usrs.c
@@ -8,8 +8,8 @@ ObjCMethod baz:with 1 c:objc(cs)NSObject
ObjCProperty gimme c:objc(cs)NSObject
ObjCProtocol blah
// CHECK: c:objc(cs)NSObject
-// CHECK: c:objc(cy)NSObject^foo
-// CHECK: c:objc(cs)NSObject@^x
+// CHECK: c:objc(cy)NSObject@foo
+// CHECK: c:objc(cs)NSObject@x
// CHECK: c:objc(cs)NSObject(cm)foo:
// CHECK: c:objc(cs)NSObject(im)baz:with
// CHECK: c:objc(cs)NSObject(py)gimme
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
new file mode 100644
index 000000000000..eb0817c27c81
--- /dev/null
+++ b/test/Index/usrs.m
@@ -0,0 +1,87 @@
+// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
+
+static inline int my_helper(int x, int y) { return x + y; }
+
+enum {
+ ABA,
+ CADABA
+};
+
+enum {
+ FOO,
+ BAR
+};
+
+typedef struct {
+ int wa;
+ int moo;
+} MyStruct;
+
+enum Pizza {
+ CHEESE,
+ MUSHROOMS
+};
+
+@interface Foo {
+ id x;
+ id y;
+}
+- (id) godzilla;
++ (id) kingkong;
+@property int d1;
+@end
+
+@implementation Foo
+- (id) godzilla {
+ static int a = 0;
+ extern int z;
+ return 0;
+}
++ (id) kingkong {
+ int local_var;
+ return 0;
+}
+@synthesize d1;
+@end
+
+int z;
+
+static int local_func(int x) { return x; }
+
+// CHECK: usrs.m c:usrs.m@3:19@F@my_helper Extent=[3:19 - 3:60]
+// CHECK: usrs.m c:usrs.m@3:29@x Extent=[3:29 - 3:34]
+// CHECK: usrs.m c:usrs.m@3:36@y Extent=[3:36 - 3:41]
+// CHECK: usrs.m c:@Ea@usrs.m@5:1 Extent=[5:1 - 8:2]
+// CHECK: usrs.m c:@Ea@usrs.m@5:1@ABA Extent=[6:3 - 6:6]
+// CHECK: usrs.m c:@Ea@usrs.m@5:1@CADABA Extent=[7:3 - 7:9]
+// CHECK: usrs.m c:@Ea@usrs.m@10:1 Extent=[10:1 - 13:2]
+// CHECK: usrs.m c:@Ea@usrs.m@10:1@FOO Extent=[11:3 - 11:6]
+// CHECK: usrs.m c:@Ea@usrs.m@10:1@BAR Extent=[12:3 - 12:6]
+// CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2]
+// CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:7 - 16:9]
+// CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:7 - 17:10]
+// CHECK: usrs.m c:@T@usrs.m@18:3@MyStruct Extent=[18:3 - 18:11]
+// CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2]
+// CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9]
+// CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12]
+// CHECK: usrs.m c:objc(cs)Foo Extent=[25:1 - 32:5]
+// CHECK: usrs.m c:objc(cs)Foo@x Extent=[26:6 - 26:7]
+// CHECK: usrs.m c:objc(cs)Foo@y Extent=[27:6 - 27:7]
+// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[31:15 - 31:17]
+// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[29:1 - 29:17]
+// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[30:1 - 30:17]
+// CHECK: usrs.m c:objc(cs)Foo(im)d1 Extent=[31:15 - 31:17]
+// CHECK: usrs.m c:objc(cs)Foo(im)setD1: Extent=[31:15 - 31:17]
+// CHECK: usrs.m c:usrs.m@31:15@d1 Extent=[31:15 - 31:17]
+// CHECK: usrs.m c:objc(cs)Foo Extent=[34:1 - 45:2]
+// CHECK: usrs.m c:objc(cs)Foo(im)godzilla Extent=[35:1 - 39:2]
+// CHECK: usrs.m c:usrs.m@36:10@a Extent=[36:10 - 36:19]
+// CHECK: usrs.m c:@z Extent=[37:10 - 37:15]
+// CHECK: usrs.m c:objc(cs)Foo(cm)kingkong Extent=[40:1 - 43:2]
+// CHECK: usrs.m c:usrs.m@41:3@local_var Extent=[41:3 - 41:16]
+// CHECK: usrs.m c:objc(cs)Foo@d1 Extent=[44:13 - 44:15]
+// CHECK: usrs.m c:objc(cs)Foo(py)d1 Extent=[44:1 - 44:15]
+// CHECK: usrs.m c:@z Extent=[47:1 - 47:6]
+// CHECK: usrs.m c:usrs.m@49:12@F@local_func Extent=[49:12 - 49:43]
+// CHECK: usrs.m c:usrs.m@49:23@x Extent=[49:23 - 49:28]
+
diff --git a/test/Lexer/gnu_keywords.c b/test/Lexer/gnu_keywords.c
new file mode 100644
index 000000000000..3234f58114a6
--- /dev/null
+++ b/test/Lexer/gnu_keywords.c
@@ -0,0 +1,12 @@
+// RUN: %clang -DGNU_KEYWORDS -std=gnu89 -fsyntax-only -verify %s
+// RUN: %clang -DGNU_KEYWORDS -std=c99 -fgnu-keywords -fsyntax-only -verify %s
+// RUN: %clang -std=c99 -fsyntax-only -verify %s
+// RUN: %clang -std=gnu89 -fno-gnu-keywords -fsyntax-only -verify %s
+
+void f() {
+#ifdef GNU_KEYWORDS
+ asm ("ret" : :);
+#else
+ int asm;
+#endif
+}
diff --git a/test/Lexer/utf-16.c b/test/Lexer/utf-16.c
new file mode 100644
index 000000000000..2b313e49fd2d
--- /dev/null
+++ b/test/Lexer/utf-16.c
@@ -0,0 +1,6 @@
+// RUN: not %clang %s -fsyntax-only -verify
+// rdar://7876588
+
+// This test verifies that clang gives a decent error for UTF-16 source files.
+
+#include "utf-16.c.txt" // expected-error {{UTF-16 (LE) byte order mark detected}}
diff --git a/test/Lexer/utf-16.c.txt b/test/Lexer/utf-16.c.txt
new file mode 100644
index 000000000000..4f3d1694bb6f
--- /dev/null
+++ b/test/Lexer/utf-16.c.txt
Binary files differ
diff --git a/test/Misc/message-length.c b/test/Misc/message-length.c
index 3c746052fd3c..3e69b6a206ee 100644
--- a/test/Misc/message-length.c
+++ b/test/Misc/message-length.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fmessage-length 72 %s 2>&1 | FileCheck -strict-whitespace %s
-// RUN: %clang_cc1 -fmessage-length 1 %s
-
+// RUN: not %clang_cc1 -fmessage-length 72 %s 2>&1 | FileCheck -strict-whitespace %s
+// RUN: not %clang_cc1 -fmessage-length 1 %s
+// RUN: not %clang_cc1 -fmessage-length 8 %s 2>&1 | FileCheck -check-prefix=CHECK-DOT %s
// Hack so we can check things better, force the file name and line.
# 1 "FILE" 1
@@ -30,3 +30,13 @@ void a_very_long_line(int *ip, float *FloatPointer) {
// CHECK: FILE:23:78
// CHECK: {{^ ...// some long comment text and a brace, eh {} }}
+
+struct A { int x; };
+void h(struct A *a) {
+ // CHECK-DOT: member
+ // CHECK-DOT: reference
+ // CHECK-DOT: type
+ (void)a
+ .
+ x;
+}
diff --git a/test/Misc/tabstop.c b/test/Misc/tabstop.c
index 66685c62d15a..49c4d7bebbba 100644
--- a/test/Misc/tabstop.c
+++ b/test/Misc/tabstop.c
@@ -39,12 +39,9 @@ void f(void)
// CHECK-3: {{^ }}if (0 & 1 == 1)
// CHECK-3: {{^ }} ( )
-// CHECK-3: {{^ }} ( )
// CHECK-4: {{^ }}if (0 & 1 == 1)
// CHECK-4: {{^ }} ( )
-// CHECK-4: {{^ }} ( )
// CHECK-5: {{^ }}if (0 & 1 == 1)
// CHECK-5: {{^ }} ( )
-// CHECK-5: {{^ }} ( )
diff --git a/test/Misc/verify.c b/test/Misc/verify.c
new file mode 100644
index 000000000000..85b034e95724
--- /dev/null
+++ b/test/Misc/verify.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct s; // expected-note 7 {{forward declaration of 'struct s'}}
+
+// standard string matching
+struct s s1; // expected-error {{tentative definition has type 'struct s' that is never completed}}
+struct s s2; // expected-error {{tentative definition has type}}
+
+// regex matching
+struct s r1; // expected-error-re {{tentative definition has type 'struct s' that is never completed}}
+struct s r2; // expected-error-re {{tentative definition has type '.*[[:space:]]*.*' that is never completed}}
+struct s r3; // expected-error-re {{tentative definition has type '(.*)[[:space:]]*(.*)' that is never completed}}
+struct s r4; // expected-error-re {{^tentative}}
+struct s r5; // expected-error-re {{completed$}}
diff --git a/test/PCH/exprs.c b/test/PCH/exprs.c
index 2b588a229e76..038a18ba5b26 100644
--- a/test/PCH/exprs.c
+++ b/test/PCH/exprs.c
@@ -5,6 +5,7 @@
// RUN: %clang_cc1 -emit-pch -fblocks -o %t %S/exprs.h
// RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s
+__SIZE_TYPE__ size_type_value;
int integer;
long long_integer;
double floating;
@@ -35,6 +36,9 @@ char_literal *int_ptr3 = &integer;
// UnaryOperator
negate_enum *int_ptr4 = &integer;
+// OffsetOfExpr
+offsetof_type *offsetof_ptr = &size_type_value;
+
// SizeOfAlignOfExpr
typeof(sizeof(float)) size_t_value;
typeof_sizeof *size_t_ptr = &size_t_value;
diff --git a/test/PCH/exprs.h b/test/PCH/exprs.h
index 7012422aad33..5af8c7c1a900 100644
--- a/test/PCH/exprs.h
+++ b/test/PCH/exprs.h
@@ -25,6 +25,19 @@ typedef typeof('a') char_literal;
// UnaryOperator
typedef typeof(-Enumerator) negate_enum;
+// OffsetOfExpr
+struct X {
+ int member;
+};
+struct Y {
+ struct X array[5];
+};
+struct Z {
+ struct Y y;
+};
+typedef typeof(__builtin_offsetof(struct Z, y.array[1 + 2].member))
+ offsetof_type;
+
// SizeOfAlignOfExpr
typedef typeof(sizeof(int)) typeof_sizeof;
typedef typeof(sizeof(Enumerator)) typeof_sizeof2;
diff --git a/test/PCH/functions.c b/test/PCH/functions.c
index eb8579ab2ef4..23becb60e8ed 100644
--- a/test/PCH/functions.c
+++ b/test/PCH/functions.c
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s
int f0(int x0, int y0, ...) { return x0 + y0; }
-
+// expected-note{{passing argument to parameter here}}
float *test_f1(int val, double x, double y) {
if (val > 5)
return f1(x, y);
@@ -15,7 +15,7 @@ float *test_f1(int val, double x, double y) {
}
void test_g0(int *x, float * y) {
- g0(y); // expected-warning{{incompatible pointer types passing 'float *', expected 'int *'}}
+ g0(y); // expected-warning{{incompatible pointer types passing 'float *' to parameter of type 'int *'}}
g0(x);
}
diff --git a/test/PCH/functions.h b/test/PCH/functions.h
index 39724300816a..f57400fc846b 100644
--- a/test/PCH/functions.h
+++ b/test/PCH/functions.h
@@ -1,6 +1,9 @@
/* For use with the functions.c test */
-int f0(int x, int y, ...);
+
+
+
+int f0(int x, int y, ...);
float *f1(float x, float y);
void g0(int *);
diff --git a/test/PCH/objc_stmts.h b/test/PCH/objc_stmts.h
new file mode 100644
index 000000000000..5f705dfcdbb7
--- /dev/null
+++ b/test/PCH/objc_stmts.h
@@ -0,0 +1,22 @@
+/* For use with the methods.m test */
+
+@interface A
+@end
+
+@interface B
+@end
+
+@interface TestPCH
+- (void)instMethod;
+@end
+
+@implementation TestPCH
+- (void)instMethod {
+ @try {
+ } @catch(A *a) {
+ } @catch(B *b) {
+ } @catch(...) {
+ } @finally {
+ }
+}
+@end
diff --git a/test/PCH/objc_stmts.m b/test/PCH/objc_stmts.m
new file mode 100644
index 000000000000..ed7466a53d9e
--- /dev/null
+++ b/test/PCH/objc_stmts.m
@@ -0,0 +1,12 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/objc_stmts.h -emit-llvm -o - %s
+// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-dump -o - %s 2>&1 | FileCheck %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_stmts.h
+// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s
+// RUN: %clang_cc1 -include-pch %t -ast-dump -o - %s 2>&1 | FileCheck %s
+
+// CHECK: catch parm = "A *a"
+// CHECK: catch parm = "B *b"
+// CHECK: catch all
diff --git a/test/PCH/pr4489.c b/test/PCH/pr4489.c
index 1d8be2d76cc5..033e55b853c8 100644
--- a/test/PCH/pr4489.c
+++ b/test/PCH/pr4489.c
@@ -1,6 +1,13 @@
// RUN: %clang -x c-header -o %t.pch %s
// RUN: echo > %t.empty.c
// RUN: %clang -include %t -x c %t.empty.c -emit-llvm -S -o -
+
+// FIXME: This test is forcibly disabled, it is flaky on the clang-i686-xp-msvc9
+// buildbot.
+//
+// RUN: false
+// XFAIL: *
+
// PR 4489: Crash with PCH
// PR 4492: Crash with PCH (round two)
// PR 4509: Crash with PCH (round three)
diff --git a/test/PCH/types.c b/test/PCH/types.c
index 1ebc01be6a14..c21b33a4ee51 100644
--- a/test/PCH/types.c
+++ b/test/PCH/types.c
@@ -66,7 +66,7 @@ int_ptr_ptr ipp = &int_value_ptr;
// TYPE_TYPEOF_EXPR
typeof_17 *t17 = &int_value;
struct S { int x, y; };
-typeof_17 t17_2 = (struct S){1, 2}; // expected-error{{incompatible type initializing}}
+typeof_17 t17_2 = (struct S){1, 2}; // expected-error{{initializing 'typeof_17' (aka 'int') with an expression of incompatible type 'struct S'}}
// TYPE_TYPEOF
int_ptr_ptr2 ipp2 = &int_value_ptr;
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
index c2a32cfa390e..ed144573fcd2 100644
--- a/test/Parser/altivec.c
+++ b/test/Parser/altivec.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -faltivec -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -faltivec -fsyntax-only -verify %s
__vector char vv_c;
__vector signed char vv_sc;
@@ -40,6 +40,8 @@ vector int f__r();
void f_a(vector int a);
void f_a2(int b, vector int a);
+vector int v = (vector int)(-1);
+
// 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}}
@@ -81,8 +83,8 @@ void f() {
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'}}
+ gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int'}}
+ av = gv8; // expected-error {{assigning to '__vector unsigned int' from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
v = gccv;
__vector unsigned int tv = gccv;
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index ca606f5391ae..b2873638cdba 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -52,3 +52,7 @@ int foo42(void) {
void __attribute__((noreturn)) d0(void), __attribute__((noreturn)) d1(void);
void d2(void) __attribute__((noreturn)), d3(void) __attribute__((noreturn));
+
+
+// PR6287
+void __attribute__((returns_twice)) returns_twice_test();
diff --git a/test/Parser/builtin_types_compatible.c b/test/Parser/builtin_types_compatible.c
index 325615c7ee91..ac81e7b08dc9 100644
--- a/test/Parser/builtin_types_compatible.c
+++ b/test/Parser/builtin_types_compatible.c
@@ -35,7 +35,7 @@ static void test()
struct xx { int a; } x, y;
c = __builtin_choose_expr(a+3-7, b, x); // expected-error{{'__builtin_choose_expr' requires a constant expression}}
- c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible type assigning 'struct xx', expected 'int'}}
+ c = __builtin_choose_expr(0, b, x); // expected-error{{assigning to 'int' from incompatible type 'struct xx'}}
c = __builtin_choose_expr(5+3-7, b, x);
y = __builtin_choose_expr(4+3-7, b, x);
diff --git a/test/Parser/check-syntax-1.m b/test/Parser/check-syntax-1.m
index 085ff4cf67a1..db37793c560f 100644
--- a/test/Parser/check-syntax-1.m
+++ b/test/Parser/check-syntax-1.m
@@ -11,9 +11,7 @@ typedef float CGFloat;
// rdar: // 7822196
@interface A
-(void) x; // expected-error {{method type specifier must start with '-' or '+'}} \
- // expected-warning {{type specifier missing, defaults to 'int' [-Wimplicit-int]}} \
- // expected-error {{cannot declare variable inside @interface or @protocol}}
+(void) x; // expected-error {{method type specifier must start with '-' or '+'}}
(int)im; // expected-error {{method type specifier must start with '-' or '+'}} \
- ok;
@end
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index 3610c0e04930..66d4f3263b9a 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/cxx-altivec.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -faltivec -fsyntax-only -verify %s
-
+// RUN: %clang_cc1 -triple=powerpc-apple-darwin8 -faltivec -fsyntax-only -verify %s
// This is the same as the C version:
__vector char vv_c;
@@ -42,6 +41,8 @@ vector int f__r();
void f_a(vector int a);
void f_a2(int b, vector int a);
+vector int v = (vector int)(-1);
+
// 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}}
@@ -81,8 +82,8 @@ void f() {
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'}}
+ gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int'}}
+ av = gv8; // expected-error {{assigning to '__vector unsigned int' from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
v = gccv;
__vector unsigned int tv = gccv;
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index c8b4716aa356..98d962ad0998 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -5,8 +5,6 @@ char *const_cast_test(const char *var)
return const_cast<char*>(var);
}
-#if 0
-// FIXME: Uncomment when C++ is supported more.
struct A {
virtual ~A() {}
};
@@ -18,7 +16,6 @@ struct B *dynamic_cast_test(struct A *a)
{
return dynamic_cast<struct B*>(a);
}
-#endif
char *reinterpret_cast_test()
{
@@ -34,3 +31,9 @@ char postfix_expr_test()
{
return reinterpret_cast<char*>(0xdeadbeef)[0];
}
+
+// This was being incorrectly tentatively parsed.
+namespace test1 {
+ template <class T> class A {};
+ void foo() { A<int>(*(A<int>*)0); }
+}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 576e57d0716a..4abbbc5b9b58 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -8,7 +8,7 @@ protected:
struct S {};
enum {};
- int; // expected-error {{declaration does not declare anything}}
+ int; // expected-warning {{declaration does not declare anything}}
int : 1, : 2;
public:
diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp
index 2fe30cd3e428..59350b566367 100644
--- a/test/Parser/cxx-friend.cpp
+++ b/test/Parser/cxx-friend.cpp
@@ -21,9 +21,9 @@ class B {
// 'A' here should refer to the declaration above.
friend class A;
- friend C; // expected-error {{must specify 'class' to befriend}}
- friend U; // expected-error {{must specify 'union' to befriend}}
- friend int; // expected-error {{friends can only be classes or functions}}
+ friend C; // expected-warning {{must specify 'class' to befriend}}
+ friend U; // expected-warning {{must specify 'union' to befriend}}
+ friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
friend void myfunc();
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 3f8f1ec9d0be..3a97efac19ed 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -6,7 +6,7 @@ template x; // expected-error {{C++ requires a type specifier for al
// expected-error {{does not refer}}
export template x; // expected-error {{expected '<' after 'template'}}
export template<class T> class x0; // expected-warning {{exported templates are unsupported}}
-template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
+template < ; // expected-error {{parse error}} expected-warning {{declaration does not declare anything}}
template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
// expected-error{{extraneous}}
template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}} \
diff --git a/test/Parser/declarators.c b/test/Parser/declarators.c
index 91803c1c5d79..31712af26c74 100644
--- a/test/Parser/declarators.c
+++ b/test/Parser/declarators.c
@@ -53,7 +53,7 @@ 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
// allows us to diagnose other bad things done with y, such as this.
- return &b.y; // expected-warning {{incompatible pointer types returning 'int *', expected 'float *'}}
+ return &b.y; // expected-warning {{incompatible pointer types returning 'int *' from a function with result type 'float *'}}
}
struct xyz test8() { return a; } // a should be be marked invalid, no diag.
diff --git a/test/Parser/implicit-casts.c b/test/Parser/implicit-casts.c
index 900b4ece8bab..a2b31f929fb3 100644
--- a/test/Parser/implicit-casts.c
+++ b/test/Parser/implicit-casts.c
@@ -14,7 +14,7 @@ void test2() {
}
int test3() {
int a[2];
- a[0] = test3; // expected-warning{{incompatible pointer to integer conversion assigning 'int ()', expected 'int'}}
+ a[0] = test3; // expected-warning{{incompatible pointer to integer conversion assigning to 'int' from 'int ()'}}
return 0;
}
short x; void test4(char c) { x += c; }
diff --git a/test/Parser/objc-init.m b/test/Parser/objc-init.m
index 0c23aebc878c..32ba948f472d 100644
--- a/test/Parser/objc-init.m
+++ b/test/Parser/objc-init.m
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic
+// RUN: %clang_cc1 -fsyntax-only -verify -x objective-c++ %s
// rdar://5707001
@interface NSNumber;
@@ -14,7 +15,7 @@ void test1() {
id objects[] = {[NSNumber METH]};
}
-void test2(NSNumber x) { // expected-error {{Objective-C interface type 'NSNumber' cannot be passed by value}}
+void test2(NSNumber x) { // expected-error {{Objective-C interface type 'NSNumber' cannot be passed by value; did you forget * in 'NSNumber'}}
id objects[] = {[x METH]};
}
diff --git a/test/Parser/objc-quirks.m b/test/Parser/objc-quirks.m
index 62984a458f36..b6671d1cf947 100644
--- a/test/Parser/objc-quirks.m
+++ b/test/Parser/objc-quirks.m
@@ -8,3 +8,21 @@ int @"s" = 5; // expected-error {{prefix attribute must be}}
@interface A
}; // expected-error {{missing @end}} expected-error {{expected external declaration}}
+
+
+
+// PR6811
+// 'super' isn't an expression, it is a magic context-sensitive keyword.
+@interface A2 {
+ id isa;
+}
+- (void)a;
+@end
+
+@interface B2 : A2 @end
+@implementation B2
+- (void)a
+{
+ [(super) a]; // expected-error {{use of undeclared identifier 'super'}}
+}
+@end
diff --git a/test/Preprocessor/expr_usual_conversions.c b/test/Preprocessor/expr_usual_conversions.c
index b1bddd34546c..5ca2cb867b2d 100644
--- a/test/Preprocessor/expr_usual_conversions.c
+++ b/test/Preprocessor/expr_usual_conversions.c
@@ -1,8 +1,9 @@
-// RUN: %clang_cc1 %s -E 2>&1 | grep warning | wc -l | grep 2
+// RUN: %clang_cc1 %s -E -verify
#define INTMAX_MIN (-9223372036854775807LL -1)
-#if (-42 + 0U) / -2
+#if (-42 + 0U) /* expected-warning {{left side of operator converted from negative value to unsigned: -42 to 18446744073709551574}} */ \
+ / -2 /* expected-warning {{right side of operator converted from negative value to unsigned: -2 to 18446744073709551614}} */
foo
#endif
diff --git a/test/Preprocessor/if_warning.c b/test/Preprocessor/if_warning.c
index 98653a8feef6..345ac95eb4ba 100644
--- a/test/Preprocessor/if_warning.c
+++ b/test/Preprocessor/if_warning.c
@@ -19,3 +19,9 @@ extern int x;
#else 1 // Should not warn due to C99 6.10p4
#endif
#endif
+
+
+// PR6852
+#if 'somesillylongthing' // expected-warning {{character constant too long for its type}} \
+ // expected-warning {{multi-character character constant}}
+#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index cccee762e264..b9850983a2a1 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -11,7 +11,6 @@
//
// RUN: %clang_cc1 -x c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
//
-// CXX0X:#define _GNU_SOURCE 1
// CXX0X:#define __DEPRECATED 1
// CXX0X:#define __GNUG__
// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1
@@ -22,7 +21,6 @@
//
// RUN: %clang_cc1 -x c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s
//
-// CXX98:#define _GNU_SOURCE 1
// CXX98:#define __DEPRECATED 1
// CXX98:#define __GNUG__
// CXX98:#define __GXX_WEAK__ 1
@@ -50,6 +48,10 @@
// COMMON:#define __STDC__ 1
// COMMON:#define __VERSION__
// COMMON:#define __clang__ 1
+// COMMON:#define __clang_major__ 2
+// COMMON:#define __clang_minor__ 0
+// COMMON:#define __clang_patchlevel__ 0
+// COMMON:#define __clang_version__
// COMMON:#define __llvm__ 1
//
//
@@ -58,7 +60,6 @@
//
// RUN: %clang_cc1 -x c++ -std=gnu++98 -E -dM < /dev/null | FileCheck -check-prefix GXX98 %s
//
-// GXX98:#define _GNU_SOURCE 1
// GXX98:#define __DEPRECATED 1
// GXX98:#define __GNUG__
// GXX98:#define __GXX_WEAK__ 1
@@ -1028,3 +1029,6 @@
// X86_64:#define __x86_64 1
// X86_64:#define __x86_64__ 1
//
+// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -E -dM < /dev/null | FileCheck -check-prefix GNUSOURCE %s
+// GNUSOURCE:#define _GNU_SOURCE 1
+//
diff --git a/test/Preprocessor/line-directive-output.c b/test/Preprocessor/line-directive-output.c
new file mode 100644
index 000000000000..290703a50e3b
--- /dev/null
+++ b/test/Preprocessor/line-directive-output.c
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -E %s 2>&1 | FileCheck %s -strict-whitespace
+// PR6101
+int a;
+// CHECK: # 1 "{{.*}}line-directive-output.c"
+// CHECK: int a;
+
+// CHECK-NEXT: # 50 "{{.*}}line-directive-output.c"
+// CHECK-NEXT: int b;
+#line 50
+int b;
+
+// CHECK: # 13 "{{.*}}line-directive-output.c"
+// CHECK-NEXT: int c;
+# 13
+int c;
+
+
+// CHECK-NEXT: # 1 "A.c"
+#line 1 "A.c"
+// CHECK-NEXT: # 2 "A.c"
+#line 2
+
+// CHECK-NEXT: # 1 "B.c"
+#line 1 "B.c"
+
+// CHECK-NEXT: # 1000 "A.c"
+#line 1000 "A.c"
+
+int y;
+
+
+
+
+
+
+
+// CHECK: # 1010 "A.c"
+int z;
+
+extern int x;
+
+# 3 "temp2.h" 1
+extern int y;
+
+# 7 "A.c" 2
+extern int z;
+
+
+
+
+
+
+
+
+
+
+
+
+
+// CHECK: # 25 "A.c"
+
+
+// CHECK: # 50 "C.c" 1
+# 50 "C.c" 1
+
+
+// CHECK-NEXT: # 2000 "A.c" 2
+# 2000 "A.c" 2
+# 42 "A.c"
+# 44 "A.c"
+# 49 "A.c"
diff --git a/test/Preprocessor/non_fragile_feature.m b/test/Preprocessor/non_fragile_feature.m
index 552209d4955e..1f67ed3f09bd 100644
--- a/test/Preprocessor/non_fragile_feature.m
+++ b/test/Preprocessor/non_fragile_feature.m
@@ -6,3 +6,7 @@
#if !__has_feature(objc_nonfragile_abi)
#error Non-fragile ABI used for compilation but feature macro not set.
#endif
+
+#if !__has_feature(objc_weak_class)
+#error objc_weak_class should be enabled with nonfragile abi
+#endif
diff --git a/test/Preprocessor/output_paste_avoid.c b/test/Preprocessor/output_paste_avoid.c
index 8c6173a78d1d..8e4f3a4bf4d9 100644
--- a/test/Preprocessor/output_paste_avoid.c
+++ b/test/Preprocessor/output_paste_avoid.c
@@ -4,8 +4,11 @@
#define y(a) ..a
A: y(.)
// This should print as ".. ." to avoid turning into ...
-// CHECK: A: . . .
+// CHECK: A: .. .
+#define X 0 .. 1
+B: X
+// CHECK: B: 0 .. 1
#define DOT .
C: ..DOT
diff --git a/test/Rewriter/dllimport-typedef.c b/test/Rewriter/dllimport-typedef.c
index 28d2e297fa67..b86fa4a1c737 100644
--- a/test/Rewriter/dllimport-typedef.c
+++ b/test/Rewriter/dllimport-typedef.c
@@ -10,8 +10,8 @@ typedef __declspec(dllimport) int CB(void);
void bar() { return 1; }
// CHECK-NEG: warning: void function 'bar' should not return a value
-// CHECK-NEG: 1 diagnostic generated
+// CHECK-NEG: 1 warning generated
// CHECK-POS: warning: 'dllimport' attribute only applies to variable and function type
// CHECK-POS: warning: void function 'bar' should not return a value
-// CHECK-POS: 2 diagnostics generated
+// CHECK-POS: 2 warnings generated
diff --git a/test/Rewriter/missing-dllimport.c b/test/Rewriter/missing-dllimport.c
index d2356bd95670..c060379db0fd 100644
--- a/test/Rewriter/missing-dllimport.c
+++ b/test/Rewriter/missing-dllimport.c
@@ -12,8 +12,8 @@ inline int __cdecl foo() { return 0; }
void bar() { return 1; }
// CHECK-NEG: warning: void function 'bar' should not return a value
-// CHECK-NEG: 1 diagnostic generated
+// CHECK-NEG: 1 warning generated
// CHECK-POS: warning: 'foo' redeclared without dllimport attribute: previous dllimport ignored
// CHECK-POS: warning: void function 'bar' should not return a value
-// CHECK-POS: 2 diagnostics generated
+// CHECK-POS: 2 warnings generated
diff --git a/test/Rewriter/rewrite-super-message.mm b/test/Rewriter/rewrite-super-message.mm
index 036aa1bb3186..be0a963c55d4 100644
--- a/test/Rewriter/rewrite-super-message.mm
+++ b/test/Rewriter/rewrite-super-message.mm
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp
-// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -DKEEP_ATTRIBUTES -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp
// radar 7738453
void *sel_registerName(const char *);
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index badd2383abc2..6258114578db 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -37,6 +37,6 @@ struct _st {
__attribute__((address_space(256))) void * * const base = 0;
void * get_0(void) {
return base[0]; // expected-error {{illegal implicit cast between two pointers with different address spaces}} \
- expected-warning {{returning 'void __attribute__((address_space(256))) *' discards qualifiers, expected 'void *'}}
+ expected-warning {{returning 'void __attribute__((address_space(256))) *' from a function with result type 'void *' discards qualifiers}}
}
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
index f22c1fc4db8a..57abc9304d5b 100644
--- a/test/Sema/altivec-init.c
+++ b/test/Sema/altivec-init.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -faltivec -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -triple=powerpc-apple-darwin8 -faltivec -verify -pedantic -fsyntax-only
typedef int v4 __attribute((vector_size(16)));
typedef short v8 __attribute((vector_size(16)));
@@ -6,7 +6,7 @@ typedef short v8 __attribute((vector_size(16)));
v8 foo(void) {
v8 a;
v4 b;
- a = (v8){4, 2}; // expected-error {{too few elements in vector initialization (expected 8 elements, have 2)}}
+ a = (v8){4, 2};
b = (v4)(5, 6, 7, 8, 9); // expected-warning {{excess elements in vector initializer}}
b = (v4)(5, 6, 8, 8.0f);
return (v8){0, 1, 2, 3, 1, 2, 3, 4};
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index 78995a993a4f..d9e08397f2d3 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -50,12 +50,12 @@ struct Redecl {
void zz(); // expected-error{{duplicate member 'zz'}}
};
-union { // expected-error{{declaration does not declare anything}}
+union { // expected-warning{{declaration does not declare anything}}
int int_val;
float float_val;
};
-static union { // expected-error{{declaration does not declare anything}}
+static union { // expected-warning{{declaration does not declare anything}}
int int_val2;
float float_val2;
};
@@ -66,7 +66,7 @@ void f() {
}
void g() {
- union { // expected-error{{declaration does not declare anything}}
+ union { // expected-warning{{declaration does not declare anything}}
int i;
float f2;
};
@@ -78,7 +78,7 @@ void g() {
struct s0 { union { int f0; }; };
// <rdar://problem/6481130>
-typedef struct { }; // expected-error{{declaration does not declare anything}}
+typedef struct { }; // expected-warning{{declaration does not declare anything}}
// PR3675
struct s1 {
@@ -89,7 +89,7 @@ struct s1 {
};
// PR3680
-struct {}; // expected-error{{declaration does not declare anything}}
+struct {}; // expected-warning{{declaration does not declare anything}}
struct s2 {
union {
@@ -101,4 +101,4 @@ struct s2 {
typedef struct {
int x;
} a_struct;
-int tmp = (a_struct) { .x = 0 }; // expected-error {{incompatible type initializing 'a_struct', expected 'int'}}
+int tmp = (a_struct) { .x = 0 }; // expected-error {{initializing 'int' with an expression of incompatible type 'a_struct'}}
diff --git a/test/Sema/arm-layout.c b/test/Sema/arm-layout.c
index 1e239d275a82..424868510428 100644
--- a/test/Sema/arm-layout.c
+++ b/test/Sema/arm-layout.c
@@ -1,20 +1,53 @@
// 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__
+#define check(name, cond) int _##name##_check[(cond) ? 1 : -1]
struct s0 { char field0; double field1; };
-int g0[sizeof(struct s0) == 16 ? 1 : -1];
+#ifdef __ARM_EABI__
+check(s0_size, sizeof(struct s0) == 16);
+#else
+check(s0_size, sizeof(struct s0) == 12);
+#endif
struct s1 { char field0; long double field1; };
-int g1[sizeof(struct s1) == 16 ? 1 : -1];
-
+#ifdef __ARM_EABI__
+check(s1_size, sizeof(struct s1) == 16);
#else
+check(s1_size, sizeof(struct s1) == 12);
+#endif
-struct s0 { char field0; double field1; };
-int g0[sizeof(struct s0) == 12 ? 1 : -1];
+struct s2 {
+ short field0;
+ int field1 : 24;
+ char field2;
+};
+#ifdef __ARM_EABI__
+check(s2_size, sizeof(struct s2) == 8);
+check(s2_offset_0, __builtin_offsetof(struct s2, field0) == 0);
+check(s2_offset_1, __builtin_offsetof(struct s2, field2) == 7);
+#else
+check(s2_size, sizeof(struct s2) == 6);
+check(s2_offset_0, __builtin_offsetof(struct s2, field0) == 0);
+check(s2_offset_1, __builtin_offsetof(struct s2, field2) == 5);
+#endif
-struct s1 { char field0; long double field1; };
-int g1[sizeof(struct s1) == 12 ? 1 : -1];
+struct s3 {
+ short field0;
+ int field1 : 24 __attribute__((aligned(4)));
+ char field2;
+};
+check(s3_size, sizeof(struct s3) == 8);
+check(s3_offset_0, __builtin_offsetof(struct s3, field0) == 0);
+check(s3_offset_1, __builtin_offsetof(struct s3, field2) == 7);
+struct s4 {
+ int field0 : 4
+};
+#ifdef __ARM_EABI__
+check(s4_size, sizeof(struct s4) == 4);
+check(s4_align, __alignof(struct s4) == 4);
+#else
+check(s4_size, sizeof(struct s4) == 1);
+check(s4_align, __alignof(struct s4) == 1);
#endif
diff --git a/test/Sema/array-constraint.c b/test/Sema/array-constraint.c
index 66f15c3a3ccc..9fcac25abe96 100644
--- a/test/Sema/array-constraint.c
+++ b/test/Sema/array-constraint.c
@@ -43,10 +43,10 @@ void check_size() {
static int I;
typedef int TA[I]; // expected-error {{variable length array declaration not allowed at file scope}}
-void strFunc(char *);
+void strFunc(char *); // expected-note{{passing argument to parameter here}}
const char staticAry[] = "test";
void checkStaticAry() {
- strFunc(staticAry); // expected-warning{{passing 'char const [5]' discards qualifiers, expected 'char *'}}
+ strFunc(staticAry); // expected-warning{{passing 'char const [5]' to parameter of type 'char *' discards qualifiers}}
}
diff --git a/test/Sema/array-init.c b/test/Sema/array-init.c
index 45d318385299..f93b0878fd3f 100644
--- a/test/Sema/array-init.c
+++ b/test/Sema/array-init.c
@@ -9,7 +9,7 @@ int ary2[] = { x, y, z }; // expected-error{{initializer element is not a compil
extern int fileScopeExtern[3] = { 1, 3, 5 }; // expected-warning{{'extern' variable has an initializer}}
-static long ary3[] = { 1, "abc", 3, 4 }; // expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'long'}}
+static long ary3[] = { 1, "abc", 3, 4 }; // expected-warning{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [4]'}}
void func() {
int x = 1;
@@ -44,11 +44,11 @@ void func() {
int a,b,c;
} z = { 1 };
- struct threeElements *p = 7; // expected-warning{{incompatible integer to pointer conversion initializing 'int', expected 'struct threeElements *'}}
+ struct threeElements *p = 7; // expected-warning{{incompatible integer to pointer conversion initializing 'struct threeElements *' with an expression of type 'int'}}
extern int blockScopeExtern[3] = { 1, 3, 5 }; // expected-error{{'extern' variable cannot have an initializer}}
- static long x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'long'}}
+ static long x2[3] = { 1.0, "abc" , 5.8 }; // expected-warning{{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [4]'}}
}
void test() {
@@ -155,10 +155,10 @@ void charArrays() {
char c[] = { "Hello" };
int l[sizeof(c) == 6 ? 1 : -1];
- int i[] = { "Hello "}; // expected-warning{{incompatible pointer to integer conversion initializing 'char [7]', expected 'int'}}
+ int i[] = { "Hello "}; // expected-warning{{incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [7]'}}
char c2[] = { "Hello", "Good bye" }; //expected-warning{{excess elements in char array initializer}}
- int i2[1] = { "Hello" }; //expected-warning{{incompatible pointer to integer conversion initializing 'char [6]', expected 'int'}}
+ int i2[1] = { "Hello" }; //expected-warning{{incompatible pointer to integer conversion initializing 'int' with an expression of type 'char [6]'}}
char c3[5] = { "Hello" };
char c4[4] = { "Hello" }; //expected-warning{{initializer-string for char array is too long}}
@@ -191,12 +191,12 @@ void autoStructTest() {
struct s1 {char a; char b;} t1;
struct s2 {struct s1 c;} t2 = { t1 };
// The following is a less than great diagnostic (though it's on par with EDG).
-struct s1 t3[] = {t1, t1, "abc", 0}; //expected-warning{{incompatible pointer to integer conversion initializing 'char [4]', expected 'char'}}
+struct s1 t3[] = {t1, t1, "abc", 0}; //expected-warning{{incompatible pointer to integer conversion initializing 'char' with an expression of type 'char [4]'}}
int t4[sizeof t3 == 6 ? 1 : -1];
}
struct foo { int z; } w;
int bar (void) {
- struct foo z = { w }; //expected-error{{incompatible type initializing 'struct foo', expected 'int'}}
+ struct foo z = { w }; //expected-error{{initializing 'int' with an expression of incompatible type 'struct foo'}}
return z.z;
}
struct s3 {void (*a)(void);} t5 = {autoStructTest};
diff --git a/test/Sema/attr-format.c b/test/Sema/attr-format.c
index 0fadf98f978f..a223e08f5a48 100644
--- a/test/Sema/attr-format.c
+++ b/test/Sema/attr-format.c
@@ -45,7 +45,7 @@ void e2(char *str, int c, ...) __attribute__((format(printf0, 2,3))); // expecte
// FreeBSD usage
#define __printf0like(fmt,va) __attribute__((__format__(__printf0__,fmt,va)))
void null(int i, const char *a, ...) __printf0like(2,0); // no-error
-void null(int i, const char *a, ...) {
+void null(int i, const char *a, ...) { // expected-note{{passing argument to parameter 'a' here}}
if (a)
(void)0/* vprintf(...) would go here */;
}
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index b17f9fd12920..5333a2c13fc2 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -40,3 +40,5 @@ f5 (unsigned long size)
__attribute__((noreturn)) void f(__attribute__((noreturn)) void (*x)(void)) {
x();
}
+
+typedef void (*Fun)(void) __attribute__ ((noreturn(2))); // expected-error {{attribute requires 0 argument(s)}}
diff --git a/test/Sema/attr-section.c b/test/Sema/attr-section.c
index 614f294d237e..a9325254080b 100644
--- a/test/Sema/attr-section.c
+++ b/test/Sema/attr-section.c
@@ -12,4 +12,4 @@ int y __attribute__((section(
void test() {
__attribute__((section("NEAR,x"))) int n1; // expected-error {{'section' attribute is not valid on local variables}}
__attribute__((section("NEAR,x"))) static int n2; // ok.
-} \ No newline at end of file
+}
diff --git a/test/Sema/bitfield.c b/test/Sema/bitfield.c
index 6f129daceba5..5bb194b1f3a9 100644
--- a/test/Sema/bitfield.c
+++ b/test/Sema/bitfield.c
@@ -5,7 +5,7 @@ struct a {
int a : -1; // expected-error{{bit-field 'a' has negative width}}
// rdar://6081627
- int b : 33; // expected-error{{size of bit-field 'b' exceeds size of its type (32 bits)}}
+ int b : 33; // expected-error{{size of bit-field 'b' (33 bits) exceeds size of its type (32 bits)}}
int c : (1 + 0.25); // expected-error{{expression is not an integer constant expression}}
int d : (int)(1 + 0.25);
@@ -21,7 +21,7 @@ struct a {
int g : (_Bool)1;
// PR4017
- char : 10; // expected-error {{size of anonymous bit-field exceeds size of its type (8 bits)}}
+ char : 10; // expected-error {{size of anonymous bit-field (10 bits) exceeds size of its type (8 bits)}}
unsigned : -2; // expected-error {{anonymous bit-field has negative width (-2)}}
float : 12; // expected-error {{anonymous bit-field has non-integral type 'float'}}
};
diff --git a/test/Sema/block-call.c b/test/Sema/block-call.c
index 0aba75e14a9a..318bc6b2a3b1 100644
--- a/test/Sema/block-call.c
+++ b/test/Sema/block-call.c
@@ -13,7 +13,7 @@ int main() {
int (^IFP) () = PFR; // OK
- const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
+ const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int const (^)()' with an expression of type 'int (^)()'}}
const int (^CICC) () = CIC;
@@ -21,7 +21,7 @@ int main() {
int * const (^IPCC1) () = IPCC;
- int * (^IPCC2) () = IPCC; // expected-error {{incompatible block pointer types initializing 'int *const (^)()', expected 'int *(^)()'}}
+ int * (^IPCC2) () = IPCC; // expected-error {{incompatible block pointer types initializing 'int *(^)()' with an expression of type 'int *const (^)()'}}
int (^IPCC3) (const int) = PFR;
@@ -29,14 +29,14 @@ int main() {
int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
- int (^IPCC6) (int, char (^CArg) (float)) = IPCC4; // expected-error {{incompatible block pointer types initializing 'int (^)(int, char (^)(double))', expected 'int (^)(int, char (^)(float))'}}
+ int (^IPCC6) (int, char (^CArg) (float)) = IPCC4; // expected-error {{incompatible block pointer types initializing 'int (^)(int, char (^)(float))' with an expression of type 'int (^)(int, char (^)(double))'}}
IPCC2 = 0;
- IPCC2 = 1; // expected-error {{invalid conversion assigning integer 'int', expected block pointer 'int *(^)()'}}
+ IPCC2 = 1; // expected-error {{invalid block pointer conversion assigning to 'int *(^)()' from 'int'}}
int (^x)() = 0;
- int (^y)() = 3; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+ int (^y)() = 3; // expected-error {{invalid block pointer conversion initializing 'int (^)()' with an expression of type 'int'}}
int a = 1;
- int (^z)() = a+4; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
+ int (^z)() = a+4; // expected-error {{invalid block pointer conversion initializing 'int (^)()' with an expression of type 'int'}}
}
int blah() {
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index ca71ab12b268..92be5b189848 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -139,12 +139,12 @@ void test14() {
enum { LESS };
-void foo(long (^comp)()) {
+void foo(long (^comp)()) { // expected-note{{passing argument to parameter 'comp' here}}
}
void (^test15f)(void);
void test15() {
- foo(^{ return LESS; }); // expected-error {{incompatible block pointer types passing 'int (^)(void)', expected 'long (^)()'}}
+ foo(^{ return LESS; }); // expected-error {{incompatible block pointer types passing 'int (^)(void)' to parameter of type 'long (^)()'}}
}
__block int test16i; // expected-error {{__block attribute not allowed, only allowed on local variables}}
@@ -202,8 +202,8 @@ L0:
// radr://7438948
void test20() {
int n = 7;
- int vla[n]; // expected-note {{declared at}}
- int (*vm)[n] = 0; // expected-note {{declared at}}
+ int vla[n]; // expected-note {{declared here}}
+ int (*vm)[n] = 0; // expected-note {{declared here}}
vla[1] = 4341;
^{
(void)vla[1]; // expected-error {{cannot refer to declaration with a variably modified type inside block}}
@@ -213,8 +213,8 @@ void test20() {
// radr://7438948
void test21() {
- int a[7]; // expected-note {{declared at}}
- __block int b[10]; // expected-note {{declared at}}
+ int a[7]; // expected-note {{declared here}}
+ __block int b[10]; // expected-note {{declared here}}
a[1] = 1;
^{
(void)a[1]; // expected-error {{cannot refer to declaration with an array type inside block}}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 2385106630d7..10b3b8480cc9 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -4,7 +4,7 @@ typedef void (^CL)(void);
CL foo() {
short y;
- short (^add1)(void) = ^{ return y+1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(void)', expected 'short (^)(void)'}}
+ short (^add1)(void) = ^{ return y+1; }; // expected-error {{incompatible block pointer types initializing 'short (^)(void)' with an expression of type 'int (^)(void)'}}
CL X = ^{
if (2)
@@ -26,7 +26,7 @@ CL foo() {
return (char*)0;
};
- double (^A)(void) = ^ { // expected-error {{incompatible block pointer types initializing 'float (^)(void)', expected 'double (^)(void)'}}
+ double (^A)(void) = ^ { // expected-error {{incompatible block pointer types initializing 'double (^)(void)' with an expression of type 'float (^)(void)'}}
if (1)
return (float)1.0;
else
@@ -38,10 +38,10 @@ CL foo() {
if (3)
return "";
else
- return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int', expected 'char *'}}
+ return 2; // expected-warning {{incompatible integer to pointer conversion returning 'int' from a function with result type 'char *'}}
};
- return ^{ return 1; }; // expected-error {{incompatible block pointer types returning 'int (^)(void)', expected 'CL'}}
+ return ^{ return 1; }; // expected-error {{incompatible block pointer types returning 'int (^)(void)' from a function with result type 'CL' (aka 'void (^)(void)')}}
}
typedef int (^CL2)(void);
@@ -78,8 +78,8 @@ static int funk(char *s) {
}
void next();
void foo4() {
- int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(char *)', expected 'int (^)(char const *)'}}
- int (*yy)(const char *s) = funk; // expected-warning {{incompatible pointer types initializing 'int (char *)', expected 'int (*)(char const *)'}}
+ int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(char const *)' with an expression of type 'int (^)(char *)'}}
+ int (*yy)(const char *s) = funk; // expected-warning {{incompatible pointer types initializing 'int (*)(char const *)' with an expression of type 'int (char *)'}}
int (^nested)(char *s) = ^(char *str) { void (^nest)(void) = ^(void) { printf("%s\n", str); }; next(); return 1; }; // expected-warning{{implicitly declaring C library function 'printf' with type 'int (char const *, ...)'}} \
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
@@ -109,7 +109,7 @@ void foo6() {
void foo7()
{
- 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 (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int const (^)(void)' with an expression of type 'int (^)(void)'}}
const int (^CC) (void) = ^const int{ const int i = 1; return i; }; // OK
int i;
diff --git a/test/Sema/builtin-prefetch.c b/test/Sema/builtin-prefetch.c
index 4f09da6c28cf..c5fa792a5663 100644
--- a/test/Sema/builtin-prefetch.c
+++ b/test/Sema/builtin-prefetch.c
@@ -6,8 +6,8 @@ void foo() {
__builtin_prefetch(&a, 1);
__builtin_prefetch(&a, 1, 2);
__builtin_prefetch(&a, 1, 9, 3); // expected-error{{too many arguments to function}}
- __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to __builtin_prefetch must be of integer type}}
- __builtin_prefetch(&a, a, 2); // expected-error{{argument to __builtin_prefetch must be a constant integer}}
+ __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to '__builtin_prefetch' must be a constant integer}}
+ __builtin_prefetch(&a, a, 2); // expected-error{{argument to '__builtin_prefetch' must be a constant integer}}
__builtin_prefetch(&a, 2); // expected-error{{argument should be a value from 0 to 1}}
__builtin_prefetch(&a, 0, 4); // expected-error{{argument should be a value from 0 to 3}}
__builtin_prefetch(&a, -1, 4); // expected-error{{argument should be a value from 0 to 1}}
diff --git a/test/Sema/builtin-stackaddress.c b/test/Sema/builtin-stackaddress.c
index 1feb57ea5267..5f63bb114624 100644
--- a/test/Sema/builtin-stackaddress.c
+++ b/test/Sema/builtin-stackaddress.c
@@ -4,7 +4,7 @@ return __builtin_return_address(0);
}
void b(unsigned x) {
-return __builtin_return_address(x); // expected-error{{the level argument for a stack address builtin must be constant}}
+return __builtin_return_address(x); // expected-error{{argument to '__builtin_return_address' must be a constant integer}}
}
void* c(unsigned x) {
@@ -12,5 +12,5 @@ return __builtin_frame_address(0);
}
void d(unsigned x) {
-return __builtin_frame_address(x); // expected-error{{the level argument for a stack address builtin must be constant}}
+return __builtin_frame_address(x); // expected-error{{argument to '__builtin_frame_address' must be a constant integer}}
}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index 7b2f2afbd9ca..6fa563b31137 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -60,7 +60,7 @@ void test11(int X) {
break;
}
- __builtin_eh_return_data_regno(X); // expected-error {{not an integer constant expression}}
+ __builtin_eh_return_data_regno(X); // expected-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}}
}
// PR5062
diff --git a/test/Sema/cast-to-union.c b/test/Sema/cast-to-union.c
index 6856c17c721a..6f275e8b505f 100644
--- a/test/Sema/cast-to-union.c
+++ b/test/Sema/cast-to-union.c
@@ -10,7 +10,7 @@ void test(int x) {
union u w = (union u)2; // expected-warning {{C99 forbids casts to union type}}
union u ww = (union u)1.0; // expected-error{{cast to union type from type 'double' not present in union}}
-union u x = 7; // expected-error{{incompatible type initializing 'int', expected 'union u'}}
+union u x = 7; // expected-error{{initializing 'union u' with an expression of incompatible type 'int'}}
int i;
union u zz = (union u)i; // expected-error{{initializer element is not a compile-time constant}} expected-warning {{C99 forbids casts to union type}}
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 7c8c36f0c145..631b69420293 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -282,3 +282,8 @@ int test5(unsigned int x) {
&& (x >= 0) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
&& (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}}
}
+
+int test6(unsigned i, unsigned power) {
+ unsigned x = (i < (1 << power) ? i : 0);
+ return x != 3 ? 1 << power : i;
+}
diff --git a/test/Sema/compound-literal.c b/test/Sema/compound-literal.c
index 0c8ddd42d0c8..08c30b3c876d 100644
--- a/test/Sema/compound-literal.c
+++ b/test/Sema/compound-literal.c
@@ -9,7 +9,7 @@ static int *p = (int []){2,4};
static int x = (int){1};
static int *p2 = (int []){2,x}; // -expected-error {{initializer element is not a compile-time constant}}
-static long *p3 = (long []){2,"x"}; // -expected-warning {{incompatible pointer to integer conversion initializing 'char [2]', expected 'long'}}
+static long *p3 = (long []){2,"x"}; // -expected-warning {{incompatible pointer to integer conversion initializing 'long' with an expression of type 'char [2]'}}
typedef struct { } cache_t; // -expected-warning{{use of empty struct extension}}
static cache_t clo_I1_cache = ((cache_t) { } ); // -expected-warning{{use of GNU empty initializer extension}}
diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c
index 5f01374be366..5e2c1a46248a 100644
--- a/test/Sema/conditional-expr.c
+++ b/test/Sema/conditional-expr.c
@@ -13,11 +13,11 @@ void foo() {
dp = vp;
vp = dp;
- ip = dp; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}}
- dp = ip; // expected-warning {{incompatible pointer types assigning 'int *', expected 'double *'}}
+ ip = dp; // expected-warning {{incompatible pointer types assigning to 'int *' from 'double *'}}
+ dp = ip; // expected-warning {{incompatible pointer types assigning to 'double *' from 'int *'}}
dp = 0 ? (double *)0 : (void *)0;
vp = 0 ? (double *)0 : (void *)0;
- ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning 'double *', expected 'int *'}}
+ ip = 0 ? (double *)0 : (void *)0; // expected-warning {{incompatible pointer types assigning to 'int *' from 'double *'}}
const int *cip;
vp = (0 ? vp : cip); // expected-warning {{discards qualifiers}}
@@ -66,5 +66,5 @@ extern int f1(void);
int f0(int a) {
// GCC considers this a warning.
- return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *', expected 'int'}}
+ return a ? f1() : nil; // expected-warning {{pointer/integer type mismatch in conditional expression ('int' and 'void *')}} expected-warning {{incompatible pointer to integer conversion returning 'void *' from a function with result type 'int'}}
}
diff --git a/test/Sema/conditional.c b/test/Sema/conditional.c
index c3dbe1321b6b..3d7bccaf9758 100644
--- a/test/Sema/conditional.c
+++ b/test/Sema/conditional.c
@@ -6,9 +6,9 @@ void _efree(void *ptr);
void free(void *ptr);
int _php_stream_free1() {
- return (1 ? free(0) : _efree(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
+ return (1 ? free(0) : _efree(0)); // expected-error {{returning 'void' from a function with incompatible result type 'int'}}
}
int _php_stream_free2() {
- return (1 ? _efree(0) : free(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
+ return (1 ? _efree(0) : free(0)); // expected-error {{returning 'void' from a function with incompatible result type 'int'}}
}
diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c
index 815e6dd9ca50..f6fed3c92d0d 100644
--- a/test/Sema/decl-invalid.c
+++ b/test/Sema/decl-invalid.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic
-typedef union <anonymous> __mbstate_t; // expected-error {{declaration of anonymous union must be a definition}} expected-error {{declaration does not declare anything}}
+typedef union <anonymous> __mbstate_t; // expected-error {{declaration of anonymous union must be a definition}} expected-warning {{declaration does not declare anything}}
// PR2017
@@ -13,12 +13,12 @@ int a() {
expected-error{{expected identifier or '('}}
}
-int; // expected-error {{declaration does not declare anything}}
-typedef int; // expected-error {{declaration does not declare anything}}
-const int; // expected-error {{declaration does not declare anything}}
-struct; // expected-error {{declaration of anonymous struct must be a definition}} // expected-error {{declaration does not declare anything}}
+int; // expected-warning {{declaration does not declare anything}}
+typedef int; // expected-warning {{declaration does not declare anything}}
+const int; // expected-warning {{declaration does not declare anything}}
+struct; // expected-error {{declaration of anonymous struct must be a definition}} // expected-warning {{declaration does not declare anything}}
typedef int I;
-I; // expected-error {{declaration does not declare anything}}
+I; // expected-warning {{declaration does not declare anything}}
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 1c87a0e21c5d..7354028cba39 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -10,7 +10,7 @@ int typedef validTypeDecl() { } // expected-error {{function definition declared
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}}
+ // expected-warning {{declaration does not declare anything}}
int gv2;
static void buggy(int *x) { }
diff --git a/test/Sema/enum.c b/test/Sema/enum.c
index 6177edff91c4..ba4e56b907a7 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -91,8 +91,7 @@ static enum e1 badfunc(struct s1 *q) {
typedef enum {
an_enumerator = 20
} 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 *'}}
+char * s = (an_enum) an_enumerator; // expected-warning {{incompatible integer to pointer conversion initializing 'char *' with an expression of type 'an_enum'}}
// PR4515
enum PR4515 {PR4515a=1u,PR4515b=(PR4515a-2)/2};
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 9acc63fa41a5..dbb6e80aa6d5 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -84,7 +84,7 @@ void test11(struct mystruct P, float F) {
// PR3753
int test12(const char *X) {
- return X == "foo"; // expected-warning {{comparison against a string literal is unspecified}}
+ return X == "foo"; // expected-warning {{comparison against a string literal is unspecified (use strncmp instead)}}
}
int test12b(const char *X) {
@@ -128,3 +128,9 @@ void test17(int x) {
x = sizeof(x/0); // no warning.
}
+// PR6501
+void test18_a(int a);
+void test18(int b) {
+ test18_a(b, b); // expected-error {{too many arguments to function call, expected 1, have 2}}
+ test18_a(); // expected-error {{too few arguments to function call, expected 1, have 0}}
+}
diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c
index cbda021cd282..d2976238c0e5 100644
--- a/test/Sema/ext_vector_casts.c
+++ b/test/Sema/ext_vector_casts.c
@@ -25,7 +25,7 @@ static void test() {
ivec4 = (int4)vec4_3;
i = (int)ivec4; // expected-error {{invalid conversion between vector type 'int4' and integer type 'int' of different size}}
- i = ivec4; // expected-error {{incompatible type assigning 'int4', expected 'int'}}
+ i = ivec4; // expected-error {{assigning to 'int' from incompatible type 'int4'}}
ivec4 = (int4)ptr; // expected-error {{invalid conversion between vector type 'int4' and scalar type 'int *'}}
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index dcc4c35d01ec..bdc2bb0c9abe 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -4,7 +4,7 @@
typedef __typeof(sizeof(int)) size_t;
typedef struct _FILE FILE;
int fprintf(FILE *, const char *restrict, ...);
-int printf(const char *restrict, ...);
+int printf(const char *restrict, ...); // expected-note{{passing argument to parameter here}}
int snprintf(char *restrict, size_t, const char *restrict, ...);
int sprintf(char *restrict, const char *restrict, ...);
int vasprintf(char **, const char *, va_list);
@@ -12,7 +12,7 @@ int asprintf(char **, const char *, ...);
int vfprintf(FILE *, const char *restrict, va_list);
int vprintf(const char *restrict, va_list);
int vsnprintf(char *, size_t, const char *, va_list);
-int vsprintf(char *restrict, const char *restrict, va_list);
+int vsprintf(char *restrict, const char *restrict, va_list); // expected-note{{passing argument to parameter here}}
char * global_fmt;
diff --git a/test/Sema/function-ptr.c b/test/Sema/function-ptr.c
index c1ff8e1d7b1f..ff852725baef 100644
--- a/test/Sema/function-ptr.c
+++ b/test/Sema/function-ptr.c
@@ -3,9 +3,9 @@ typedef int unary_int_func(int arg);
unary_int_func *func;
unary_int_func *set_func(void *p) {
- func = p; // expected-warning {{converts between void* and function pointer}}
- p = func; // expected-warning {{converts between void* and function pointer}}
+ func = p; // expected-warning {{converts between void pointer and function pointer}}
+ p = func; // expected-warning {{converts between void pointer and function pointer}}
- return p; // expected-warning {{converts between void* and function pointer}}
+ return p; // expected-warning {{converts between void pointer and function pointer}}
}
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 1302b34b107a..b8a64af96bcf 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -123,7 +123,7 @@ a x;
a2 x2;
void test_x() {
x(5);
- x2(5); // expected-warning{{incompatible integer to pointer conversion passing 'int', expected 'int *'}}
+ x2(5); // expected-warning{{incompatible integer to pointer conversion passing 'int' to parameter of type 'int *'}}
}
enum e0 {};
diff --git a/test/Sema/incompatible-sign.c b/test/Sema/incompatible-sign.c
index a1592efc4c47..6249feb6b1e7 100644
--- a/test/Sema/incompatible-sign.c
+++ b/test/Sema/incompatible-sign.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
-int a(int* x);
-int b(unsigned* y) { return a(y); } // expected-warning {{pointer types point to integer types with different sign}}
+int a(int* x); // expected-note{{passing argument to parameter 'x' here}}
+int b(unsigned* y) { return a(y); } // expected-warning {{passing 'unsigned int *' to parameter of type 'int *' converts between pointers to integer types with different sign}}
diff --git a/test/Sema/invalid-init-diag.c b/test/Sema/invalid-init-diag.c
index dec7d6c18f8a..3e4870e0cab1 100644
--- a/test/Sema/invalid-init-diag.c
+++ b/test/Sema/invalid-init-diag.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
int a;
-struct {int x;} x = a; // expected-error {{incompatible type initializing 'int', expected 'struct <anonymous}}
+struct {int x;} x = a; // expected-error {{with an expression of incompatible type 'int'}}
diff --git a/test/Sema/offsetof.c b/test/Sema/offsetof.c
index 49d4eb43e423..5026193943ff 100644
--- a/test/Sema/offsetof.c
+++ b/test/Sema/offsetof.c
@@ -53,4 +53,15 @@ int x[__builtin_offsetof(union x, x)];
struct incomplete; // expected-note 2 {{forward declaration of 'struct incomplete'}}
int test1[__builtin_offsetof(struct incomplete, foo)]; // expected-error {{offsetof of incomplete type 'struct incomplete'}}
-int test1[__builtin_offsetof(struct incomplete[10], [4].foo)]; // expected-error {{array has incomplete element type 'struct incomplete'}}
+int test2[__builtin_offsetof(struct incomplete[10], [4].foo)]; // expected-error {{array has incomplete element type 'struct incomplete'}}
+
+// Bitfields
+struct has_bitfields {
+ int i : 7;
+ int j : 12; // expected-note{{bit-field is declared here}}
+};
+
+int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cannot compute offset of bit-field 'j'}}
+
+typedef struct Array { int array[1]; } Array;
+int test4 = __builtin_offsetof(Array, array);
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index 69c91cb15f47..e53f0eb99bc1 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -5,17 +5,21 @@
void if_assign(void) {
int i;
if (i = 4) {} // expected-warning {{assignment as a condition}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
if ((i = 4)) {}
}
void bitwise_rel(unsigned i) {
(void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}} \
- // expected-note{{place parentheses around the & expression to evaluate it first}}
+ // expected-note{{place parentheses around the & expression to evaluate it first}} \
+ // expected-note{{place parentheses around the == expression to silence this warning}}
(void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}} \
- // expected-note{{place parentheses around the & expression to evaluate it first}}
+ // expected-note{{place parentheses around the & expression to evaluate it first}} \
+ // expected-note{{place parentheses around the == expression to silence this warning}}
(void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}} \
- // expected-note{{place parentheses around the & expression to evaluate it first}}
+ // expected-note{{place parentheses around the & expression to evaluate it first}} \
+ // expected-note{{place parentheses around the < expression to silence this warning}}
(void)((i & 0x2) == 0);
(void)(i & (0x2 == 0));
// Eager logical op
diff --git a/test/Sema/pointer-conversion.c b/test/Sema/pointer-conversion.c
index 7191bf7c63f4..2d755ae42f3d 100644
--- a/test/Sema/pointer-conversion.c
+++ b/test/Sema/pointer-conversion.c
@@ -1,10 +1,10 @@
//RUN: %clang_cc1 -fsyntax-only -verify %s
char * c;
-char const ** c2 = &c; // expected-warning {{initializing, 'char const **' and 'char **' have different qualifiers in nested pointer types}}
+char const ** c2 = &c; // expected-warning {{discards qualifiers in nested pointer types}}
typedef char dchar;
-dchar *** c3 = &c2; // expected-warning {{initializing, 'dchar ***' and 'char const ***' have different qualifiers in nested pointer types}}
+dchar *** c3 = &c2; // expected-warning {{discards qualifiers in nested pointer types}}
volatile char * c4;
-char ** c5 = &c4; // expected-warning {{initializing, 'char **' and 'char volatile **' have different qualifiers in nested pointer types}}
+char ** c5 = &c4; // expected-warning {{discards qualifiers in nested pointer types}}
diff --git a/test/Sema/predef.c b/test/Sema/predef.c
index 9c1994699da7..08a4a2bf83e9 100644
--- a/test/Sema/predef.c
+++ b/test/Sema/predef.c
@@ -6,7 +6,7 @@ void abcdefghi12(void) {
}
char *X = __func__; // expected-warning {{predefined identifier is only valid}} \
- expected-warning {{initializing 'char const [1]' discards qualifiers, expected 'char *'}}
+ expected-warning {{initializing 'char *' with an expression of type 'char const [1]' discards qualifiers}}
void a() {
__func__[0] = 'a'; // expected-error {{variable is not assignable}}
diff --git a/test/Sema/predefined-function.c b/test/Sema/predefined-function.c
index 665d0fa1a8b7..1c40b6e8c2c0 100644
--- a/test/Sema/predefined-function.c
+++ b/test/Sema/predefined-function.c
@@ -4,13 +4,14 @@ char *funk(int format);
enum Test {A=-1};
char *funk(enum Test x);
-int eli(float b); // expected-note {{previous declaration is here}}
+int eli(float b); // expected-note {{previous declaration is here}} \
+// expected-note{{passing argument to parameter 'b' here}}
int b(int c) {return 1;}
int foo();
int foo() {
int eli(int (int)); // expected-error {{conflicting types for 'eli'}}
- eli(b); // expected-error{{incompatible type passing}}
+ eli(b); // expected-error{{passing 'int (int)' to parameter of incompatible type 'float'}}
return 0;
}
diff --git a/test/Sema/return.c b/test/Sema/return.c
index fab6a82aa704..0d46d981bed2 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -225,7 +225,7 @@ void test33() {
// Test that 'static inline' functions are only analyzed for CFG-based warnings
// when they are used.
-static inline int si_has_missing_return() {} // no-warning
+static inline int si_has_missing_return() {} // expected-warning{{control reaches end of non-void function}}
static inline int si_has_missing_return_2() {}; // expected-warning{{control reaches end of non-void function}}
static inline int si_forward();
static inline int si_has_missing_return_3(int x) {
diff --git a/test/Sema/statements.c b/test/Sema/statements.c
index 6da2daa01ac2..e3c41f3e1aaf 100644
--- a/test/Sema/statements.c
+++ b/test/Sema/statements.c
@@ -13,7 +13,7 @@ int test(int _x) {
// PR2374
int test2() { return ({L:5;}); }
-int test3() { return ({ {5;} }); } // expected-error {{incompatible type returning 'void', expected 'int'}}\
+int test3() { return ({ {5;} }); } // expected-error {{returning 'void' from a function with incompatible result type 'int'}}\
// expected-warning {{expression result unused}}
int test4() { return ({ ({5;}); }); }
int test5() { return ({L1: L2: L3: 5;}); }
@@ -41,3 +41,13 @@ void test11(int bit) {
{
}
}
+
+// rdar://3271964
+enum Numbers { kOne, kTwo, kThree, kFour};
+int test12(enum Numbers num) {
+ switch (num == kOne) {// expected-warning {{switch condition has boolean value}}
+ default:
+ case kThree:
+ break;
+ }
+} \ No newline at end of file
diff --git a/test/Sema/struct-compat.c b/test/Sema/struct-compat.c
index 2e112e17dade..65bef9f60555 100644
--- a/test/Sema/struct-compat.c
+++ b/test/Sema/struct-compat.c
@@ -13,5 +13,5 @@ struct x {int a;} *c = b; // expected-warning {{incompatible pointer types}}
struct x {int a;} r;
int b() {
-struct x {char x;} s = r; // expected-error {{incompatible type initializing}}
+struct x {char x;} s = r; // expected-error {{initializing 'struct x' with an expression of incompatible type 'struct x'}}
}
diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c
index 03f6a53d059a..cdfc8506d1b5 100644
--- a/test/Sema/transparent-union.c
+++ b/test/Sema/transparent-union.c
@@ -4,7 +4,7 @@ typedef union {
float *fp;
} TU __attribute__((transparent_union));
-void f(TU);
+void f(TU); // expected-note{{passing argument to parameter here}}
void g(int *ip, float *fp, char *cp) {
f(ip);
diff --git a/test/Sema/typedef-retain.c b/test/Sema/typedef-retain.c
index 0ef15fdec6cd..5b963c48b2cc 100644
--- a/test/Sema/typedef-retain.c
+++ b/test/Sema/typedef-retain.c
@@ -5,11 +5,11 @@ typedef int int4 __attribute__((vector_size(16)));
typedef int4* int4p;
void test1(float4 a, int4 *result, int i) {
- result[i] = a; // expected-error {{assigning 'float4', expected 'int4'}}
+ result[i] = a; // expected-error {{assigning to 'int4' from incompatible type 'float4'}}
}
void test2(float4 a, int4p result, int i) {
- result[i] = a; // expected-error {{assigning 'float4', expected 'int4'}}
+ result[i] = a; // expected-error {{assigning to 'int4' from incompatible type 'float4'}}
}
// PR2039
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index 4c6c47b34517..4ae0d4b46504 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -104,3 +104,9 @@ void t8() {
}
void t9() __attribute__((warn_unused_result)); // expected-warning {{attribute 'warn_unused_result' cannot be applied to functions without return value}}
+
+// rdar://7410924
+void *some_function(void);
+void t10() {
+ (void*) some_function(); //expected-warning {{expression result unused; should this cast be to 'void'?}}
+}
diff --git a/test/Sema/vector-assign.c b/test/Sema/vector-assign.c
index d074a958fa0f..05fc3b13db0c 100644
--- a/test/Sema/vector-assign.c
+++ b/test/Sema/vector-assign.c
@@ -12,30 +12,30 @@ void test1() {
v2f v4;
v4ss v5;
- v1 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v2s'}}
- v1 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2s'}}
- v1 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v2s'}}
- v1 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2s'}}
+ v1 = v2; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v2u'}}
+ v1 = v3; // expected-error {{assigning to 'v2s' from incompatible type 'v1s'}}
+ v1 = v4; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v2f'}}
+ v1 = v5; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v4ss'}}
- v2 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v2u'}}
- v2 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2u'}}
- v2 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v2u'}}
- v2 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2u'}}
+ v2 = v1; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v2s'}}
+ v2 = v3; // expected-error {{assigning to 'v2u' from incompatible type 'v1s'}}
+ v2 = v4; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v2f'}}
+ v2 = v5; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v4ss'}}
- v3 = v1; // expected-error {{incompatible type assigning 'v2s', expected 'v1s'}}
- v3 = v2; // expected-error {{incompatible type assigning 'v2u', expected 'v1s'}}
- v3 = v4; // expected-error {{incompatible type assigning 'v2f', expected 'v1s'}}
- v3 = v5; // expected-error {{incompatible type assigning 'v4ss', expected 'v1s'}}
+ v3 = v1; // expected-error {{assigning to 'v1s' from incompatible type 'v2s'}}
+ v3 = v2; // expected-error {{assigning to 'v1s' from incompatible type 'v2u'}}
+ v3 = v4; // expected-error {{assigning to 'v1s' from incompatible type 'v2f'}}
+ v3 = v5; // expected-error {{assigning to 'v1s' from incompatible type 'v4ss'}}
- v4 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v2f'}}
- v4 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v2f'}}
- v4 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v2f'}}
- v4 = v5; // expected-warning {{incompatible vector types assigning 'v4ss', expected 'v2f'}}
+ v4 = v1; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v2s'}}
+ v4 = v2; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v2u'}}
+ v4 = v3; // expected-error {{assigning to 'v2f' from incompatible type 'v1s'}}
+ v4 = v5; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v4ss'}}
- v5 = v1; // expected-warning {{incompatible vector types assigning 'v2s', expected 'v4ss'}}
- v5 = v2; // expected-warning {{incompatible vector types assigning 'v2u', expected 'v4ss'}}
- v5 = v3; // expected-error {{incompatible type assigning 'v1s', expected 'v4ss'}}
- v5 = v4; // expected-warning {{incompatible vector types assigning 'v2f', expected 'v4ss'}}
+ v5 = v1; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2s'}}
+ v5 = v2; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2u'}}
+ v5 = v3; // expected-error {{assigning to 'v4ss' from incompatible type 'v1s'}}
+ v5 = v4; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2f'}}
}
// PR2263
@@ -47,7 +47,7 @@ float test2(__attribute__((vector_size(16))) float a, int b) {
typedef long long __attribute__((__vector_size__(2 * sizeof(long long))))
longlongvec;
-void test3a(longlongvec *);
+void test3a(longlongvec *); // expected-note{{passing argument to parameter here}}
void test3(const unsigned *src) {
- test3a(src); // expected-warning {{incompatible pointer types passing 'unsigned int const *', expected 'longlongvec *'}}
+ test3a(src); // expected-warning {{incompatible pointer types passing 'unsigned int const *' to parameter of type 'longlongvec *'}}
}
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index aab0ab4775ab..a717e8611019 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -30,9 +30,9 @@ type 't1' and integer type 'short' of different size}}
}
-void f2(t2 X);
+void f2(t2 X); // expected-note{{passing argument to parameter 'X' here}}
void f3(t3 Y) {
- f2(Y); // expected-warning {{incompatible vector types passing 't3', expected 't2'}}
+ f2(Y); // expected-warning {{incompatible vector types passing 't3' to parameter of type 't2'}}
}
diff --git a/test/Sema/warn-missing-braces.c b/test/Sema/warn-missing-braces.c
index 07eb61aac003..ebfe9848306d 100644
--- a/test/Sema/warn-missing-braces.c
+++ b/test/Sema/warn-missing-braces.c
@@ -1,3 +1,3 @@
// RUN: %clang_cc1 -fsyntax-only -Wmissing-braces -verify %s
-int a[2][2] = { 0, 1, 2, 3 }; // expected-warning{{suggest braces}} expected-warning{{suggest braces}} \ No newline at end of file
+int a[2][2] = { 0, 1, 2, 3 }; // expected-warning{{suggest braces}} expected-warning{{suggest braces}}
diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c
index b52f676ac58a..d5e676b11603 100644
--- a/test/Sema/warn-unused-function.c
+++ b/test/Sema/warn-unused-function.c
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
void foo() {}
static void f2() {}
@@ -28,3 +30,8 @@ static void f7(void) {}
__attribute__((unused)) static void bar(void);
void bar(void) { }
+__attribute__((constructor)) static void bar2(void);
+void bar2(void) { }
+
+__attribute__((destructor)) static void bar3(void);
+void bar3(void) { }
diff --git a/test/Sema/warn-unused-parameters.c b/test/Sema/warn-unused-parameters.c
index c6458cf9712b..e47ddd5e00d5 100644
--- a/test/Sema/warn-unused-parameters.c
+++ b/test/Sema/warn-unused-parameters.c
@@ -1,13 +1,22 @@
-// RUN: %clang -fblocks -fsyntax-only -Wunused-parameter %s -Xclang -verify
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Wunused-parameter %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Wunused %s 2>&1 | FileCheck -check-prefix=CHECK-unused %s
int f0(int x,
- int y, // expected-warning{{unused}}
+ int y,
int z __attribute__((unused))) {
return x;
}
void f1() {
(void)^(int x,
- int y, // expected-warning{{unused}}
+ int y,
int z __attribute__((unused))) { return x; };
}
+
+// Used when testing '-Wunused' to see that we only emit one diagnostic, and no
+// warnings for the above cases.
+static void achor() {};
+
+// CHECK: 5:12: warning: unused parameter 'y'
+// CHECK: 12:15: warning: unused parameter 'y'
+// CHECK-unused: 1 warning generated \ No newline at end of file
diff --git a/test/Sema/warn-unused-value.c b/test/Sema/warn-unused-value.c
index 2e0fa54effbf..16b787f77441 100644
--- a/test/Sema/warn-unused-value.c
+++ b/test/Sema/warn-unused-value.c
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
int i = 0;
int j = 0;
@@ -51,3 +53,16 @@ void pr4806() {
*pi; // expected-warning {{expression result unused}}
*pj;
}
+
+// Don't warn about unused '||', '&&' expressions that contain assignments.
+int test_logical_foo1();
+int test_logical_foo2();
+int test_logical_foo3();
+int test_logical_bar() {
+ int x = 0;
+ (x = test_logical_foo1()) || // no-warning
+ (x = test_logical_foo2()) || // no-warning
+ (x = test_logical_foo3()); // no-warning
+ return x;
+}
+
diff --git a/test/Sema/warn-write-strings.c b/test/Sema/warn-write-strings.c
index 938f0be7721f..04af00ca2d83 100644
--- a/test/Sema/warn-write-strings.c
+++ b/test/Sema/warn-write-strings.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
// PR4804
-char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}}
+char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'char const [4]' discards qualifiers}}
diff --git a/test/Sema/x86-builtin-palignr.c b/test/Sema/x86-builtin-palignr.c
new file mode 100644
index 000000000000..eedf99bdfb6f
--- /dev/null
+++ b/test/Sema/x86-builtin-palignr.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -target-feature +ssse3 -verify %s
+// Temporarily xfail this on windows.
+// XFAIL: win32
+
+#include <tmmintrin.h>
+
+__m64 foo(__m64 a, __m64 b, int c)
+{
+ return _mm_alignr_pi8(a, b, c); // expected-error {{argument to '__builtin_ia32_palignr' must be a constant integer}}
+}
diff --git a/test/SemaCXX/abstract.cpp b/test/SemaCXX/abstract.cpp
index 0ae6c446f3da..3e61cc386eb8 100644
--- a/test/SemaCXX/abstract.cpp
+++ b/test/SemaCXX/abstract.cpp
@@ -42,11 +42,11 @@ void f() {
t3(C()); // expected-error {{allocation of an object of abstract type 'C'}}
}
-C e1[2]; // expected-error {{variable type 'C' is an abstract class}}
-C (*e2)[2]; // expected-error {{variable type 'C' is an abstract class}}
-C (**e3)[2]; // expected-error {{variable type 'C' is an abstract class}}
+C e1[2]; // expected-error {{array of abstract class type 'C'}}
+C (*e2)[2]; // expected-error {{array of abstract class type 'C'}}
+C (**e3)[2]; // expected-error {{array of abstract class type 'C'}}
-void t4(C c[2]); // expected-error {{parameter type 'C' is an abstract class}}
+void t4(C c[2]); // expected-error {{array of abstract class type 'C'}}
void t5(void (*)(C)); // expected-error {{parameter type 'C' is an abstract class}}
@@ -168,4 +168,3 @@ namespace PureImplicit {
struct D : C {};
D y;
}
-
diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp
index 25fd9e52aa25..85516902163e 100644
--- a/test/SemaCXX/access-base-class.cpp
+++ b/test/SemaCXX/access-base-class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
namespace T1 {
class A { };
diff --git a/test/SemaCXX/access-control-check.cpp b/test/SemaCXX/access-control-check.cpp
index 1db6704909df..4540e99d8a33 100644
--- a/test/SemaCXX/access-control-check.cpp
+++ b/test/SemaCXX/access-control-check.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
class M {
int iM;
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
index 3b06119393d0..f8b00df17314 100644
--- a/test/SemaCXX/addr-of-overloaded-function.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -54,3 +54,35 @@ struct B
void d(void *);
static void d(A *);
};
+
+struct C {
+ C &getC() {
+ return makeAC; // expected-error{{address of overloaded function 'makeAC' cannot be converted to type 'C'}}
+ }
+
+ C &makeAC();
+ const C &makeAC() const;
+
+ static void f(); // expected-note{{candidate function}}
+ static void f(int); // expected-note{{candidate function}}
+
+ void g() {
+ int (&fp)() = f; // expected-error{{address of overloaded function 'f' does not match required type 'int ()'}}
+ }
+};
+
+// PR6886
+namespace test0 {
+ void myFunction(void (*)(void *));
+
+ class Foo {
+ void foo();
+
+ static void bar(void*);
+ static void bar();
+ };
+
+ void Foo::foo() {
+ myFunction(bar);
+ }
+}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 708a8f256a3d..4c34447940ff 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -60,10 +60,23 @@ struct C {
void f() {
A as1[1] = { };
- A as2[1] = { 1 }; // expected-error {{copying array element of type 'A' invokes deleted copy constructor}}
+ A as2[1] = { 1 }; // expected-error {{copying array element of type 'A' invokes deleted constructor}}
B b1 = { };
- B b2 = { 1 }; // expected-error {{copying member subobject of type 'A' invokes deleted copy constructor}}
+ B b2 = { 1 }; // expected-error {{copying member subobject of type 'A' invokes deleted constructor}}
C c1 = { 1 };
}
+
+class Agg {
+public:
+ int i, j;
+};
+
+class AggAgg {
+public:
+ Agg agg1;
+ Agg agg2;
+};
+
+AggAgg aggagg = { 1, 2, 3, 4 };
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 0590db28d832..5c34e016e57d 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -110,7 +110,7 @@ struct BadMembers {
};
// <rdar://problem/6481130>
-typedef union { }; // expected-error{{declaration does not declare anything}}
+typedef union { }; // expected-warning{{declaration does not declare anything}}
// <rdar://problem/7562438>
typedef struct objc_module *Foo ;
diff --git a/test/SemaCXX/bitfield-layout.cpp b/test/SemaCXX/bitfield-layout.cpp
new file mode 100644
index 000000000000..adecf55a8774
--- /dev/null
+++ b/test/SemaCXX/bitfield-layout.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=x86_64-apple-darwin10
+
+#define CHECK_SIZE(name, size) extern int name##1[sizeof(name) == size ? 1 : -1];
+#define CHECK_ALIGN(name, size) extern int name##2[__alignof(name) == size ? 1 : -1];
+
+// Simple tests.
+struct Test1 {
+ char c : 9; // expected-warning {{size of bit-field 'c' (9 bits) exceeds the size of its type; value will be truncated to 8 bits}}
+};
+CHECK_SIZE(Test1, 2);
+CHECK_ALIGN(Test1, 1);
+
+struct Test2 {
+ char c : 16; // expected-warning {{size of bit-field 'c' (16 bits) exceeds the size of its type; value will be truncated to 8 bits}}
+};
+CHECK_SIZE(Test2, 2);
+CHECK_ALIGN(Test2, 2);
+
+struct Test3 {
+ char c : 32; // expected-warning {{size of bit-field 'c' (32 bits) exceeds the size of its type; value will be truncated to 8 bits}}
+};
+CHECK_SIZE(Test3, 4);
+CHECK_ALIGN(Test3, 4);
+
+struct Test4 {
+ char c : 64; // expected-warning {{size of bit-field 'c' (64 bits) exceeds the size of its type; value will be truncated to 8 bits}}
+};
+CHECK_SIZE(Test4, 8);
+CHECK_ALIGN(Test4, 8);
+
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index 7095d92d6852..ca9f04541635 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -51,3 +51,26 @@ namespace Test3 {
t(2) { } // expected-error {{multiple initializations given for non-static member 't'}}
};
}
+
+namespace test4 {
+ class A {
+ union {
+ struct {
+ int a;
+ int b;
+ };
+
+ int c;
+
+ union {
+ int d;
+ int e;
+ };
+ };
+
+ A(char _) : a(0), b(0) {}
+ A(short _) : a(0), c(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+ A(int _) : d(0), e(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+ A(long _) : a(0), d(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+ };
+}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 508ca4d7652a..7eea67ad4455 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -103,7 +103,7 @@ void ogfn()
// PR3020: This used to crash due to double ownership of C4.
struct C4;
- C4; // expected-error {{declaration does not declare anything}}
+ C4; // expected-warning {{declaration does not declare anything}}
}
struct C4 {
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 49bcd99fb695..a812a5920d65 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -faccess-control -std=c++0x -Wsign-compare %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -Wsign-compare %s
// C++ rules for ?: are a lot stricter than C rules, and have to take into
// account more conversion options.
@@ -7,8 +7,7 @@
struct ToBool { explicit operator bool(); };
struct B;
-struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} \
- // expected-note 2 {{candidate is the implicit copy constructor}}
+struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
struct I { operator int(); };
struct J { operator I(); };
@@ -224,7 +223,7 @@ namespace PR6757 {
struct Foo3 {
Foo3();
- Foo3(Foo3&);
+ Foo3(Foo3&); // expected-note{{would lose const qualifier}}
};
struct Bar {
@@ -236,7 +235,6 @@ namespace PR6757 {
void f() {
(void)(true ? Bar() : Foo1()); // okay
(void)(true ? Bar() : Foo2()); // okay
- // FIXME: Diagnostic below could be improved
- (void)(true ? Bar() : Foo3()); // expected-error{{incompatible operand types ('PR6757::Bar' and 'PR6757::Foo3')}}
+ (void)(true ? Bar() : Foo3()); // expected-error{{no viable constructor copying temporary}}
}
}
diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp
index 0d4d38743300..a17dd58dab03 100644
--- a/test/SemaCXX/constant-expression.cpp
+++ b/test/SemaCXX/constant-expression.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
-
// C++ [expr.const]p1:
// In several places, C++ requires expressions that evaluate to an integral
// or enumeration constant: as array bounds, as case expressions, as
@@ -79,5 +78,10 @@ template <int itval, Enum etval> struct C {
};
template struct C<1, eval>;
-//template struct C<cval, ceval>;
-//template struct C<Struct::sval, Struct::seval>;
+template struct C<cval, ceval>;
+template struct C<Struct::sval, Struct::seval>;
+
+enum {
+ a = sizeof(int) == 8,
+ b = a? 8 : 4
+};
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index 96dfa8ba5269..8e9e133d94cb 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -Wreorder -fsyntax-only -verify %s
class A {
int m;
+public:
A() : A::m(17) { } // expected-error {{member initializer 'm' does not name a non-static data member or base class}}
A(int);
};
@@ -72,8 +73,9 @@ class U {
union { int a; char* p; };
union { int b; double d; };
- U() : a(1), p(0), d(1.0) {} // expected-error {{multiple initializations given for non-static member 'p'}} \
- // expected-note {{previous initialization is here}}
+ U() : a(1), // expected-note {{previous initialization is here}}
+ p(0), // expected-error {{initializing multiple members of anonymous union}}
+ d(1.0) {}
};
struct V {};
@@ -86,12 +88,11 @@ struct Derived : Base, Base1, virtual V {
struct Current : Derived {
int Derived;
- Current() : Derived(1), ::Derived(), // expected-warning {{member 'Derived' will be initialized after}} \
- // expected-note {{base '::Derived'}} \
- // expected-warning {{base class '::Derived' will be initialized after}}
+ Current() : Derived(1), ::Derived(), // expected-warning {{field 'Derived' will be initialized after base '::Derived'}} \
+ // expected-warning {{base class '::Derived' will be initialized after base 'Derived::V'}}
::Derived::Base(), // expected-error {{type '::Derived::Base' is not a direct or virtual base of 'Current'}}
Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}}
- Derived::V(), // expected-note {{base 'Derived::V'}}
+ Derived::V(),
::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
INT::NonExisting() {} // expected-error {{expected a class or namespace}} \
// expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
@@ -125,7 +126,7 @@ struct Q {
// A silly class used to demonstrate field-is-uninitialized in constructors with
// multiple params.
-class TwoInOne { TwoInOne(TwoInOne a, TwoInOne b) {} };
+class TwoInOne { public: TwoInOne(TwoInOne a, TwoInOne b) {} };
class InitializeUsingSelfTest {
bool A;
char* B;
@@ -170,3 +171,36 @@ struct X0 : NDC<int> {
NDC<int> ndc;
};
+
+namespace Test0 {
+
+struct A { A(); };
+
+struct B {
+ B() { }
+ const A a;
+};
+
+}
+
+namespace Test1 {
+ struct A {
+ enum Kind { Foo } Kind;
+ A() : Kind(Foo) {}
+ };
+}
+
+namespace Test2 {
+
+struct A {
+ A(const A&);
+};
+
+struct B : virtual A { };
+struct C : A, B { };
+
+C f(C c) {
+ return c;
+}
+
+}
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index bca75c0b2fb5..3e96d02495fe 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -56,7 +56,7 @@ public:
// This used to crash Clang.
struct Flip;
-struct Flop { // expected-note{{candidate is the implicit copy constructor}}
+struct Flop {
Flop();
Flop(const Flip&); // expected-note{{candidate constructor}}
};
@@ -129,5 +129,89 @@ private:
};
A1 f() {
- return "Hello"; // expected-error{{invokes deleted copy constructor}}
+ return "Hello"; // expected-error{{invokes deleted constructor}}
+}
+
+namespace source_locations {
+ template<typename T>
+ struct sneaky_int {
+ typedef int type;
+ };
+
+ template<typename T, typename U>
+ struct A { };
+
+ template<typename T>
+ struct A<T, T> : A<T, int> { };
+
+ struct E {
+ template<typename T>
+ operator A<T, typename sneaky_int<T>::type>&() const; // expected-note{{candidate function}}
+ };
+
+ void f() {
+ A<float, float> &af = E(); // expected-error{{no viable conversion}}
+ A<float, int> &af2 = E();
+ const A<float, int> &caf2 = E();
+ }
+
+ // Check
+ template<typename T>
+ struct E2 {
+ operator T
+ * // expected-error{{pointer to a reference}}
+ () const;
+ };
+
+ E2<int&> e2i; // expected-note{{in instantiation}}
+}
+
+namespace crazy_declarators {
+ struct A {
+ (&operator bool())(); // expected-error {{must use a typedef to declare a conversion to 'bool (&)()'}}
+
+ // FIXME: This diagnostic is misleading (the correct spelling
+ // would be 'operator int*'), but it's a corner case of a
+ // rarely-used syntax extension.
+ *operator int(); // expected-error {{must use a typedef to declare a conversion to 'int *'}}
+ };
+}
+
+namespace smart_ptr {
+ class Y {
+ class YRef { };
+
+ Y(Y&);
+
+ public:
+ Y();
+ Y(YRef);
+
+ operator YRef(); // expected-note{{candidate function}}
+ };
+
+ struct X { // expected-note{{candidate constructor (the implicit copy constructor) not}}
+ explicit X(Y);
+ };
+
+ Y make_Y();
+
+ X f() {
+ X x = make_Y(); // expected-error{{no viable conversion from 'smart_ptr::Y' to 'smart_ptr::X'}}
+ X x2(make_Y());
+ return X(Y());
+ }
+}
+
+struct Any {
+ Any(...);
+};
+
+struct Other {
+ Other(const Other &);
+ Other();
+};
+
+void test_any() {
+ Any any = Other(); // expected-error{{cannot pass object of non-POD type 'Other' through variadic constructor; call will abort at runtime}}
}
diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp
index 8cdb1be48763..bfe1501df867 100644
--- a/test/SemaCXX/copy-assignment.cpp
+++ b/test/SemaCXX/copy-assignment.cpp
@@ -94,6 +94,6 @@ void test() {
int i;
i = convertibleToInt;
- i = a; // expected-error{{incompatible type assigning 'A', expected 'int'}}
+ i = a; // expected-error{{assigning to 'int' from incompatible type 'A'}}
}
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
index e5b1fd766bbd..0c4aa964cb66 100644
--- a/test/SemaCXX/copy-initialization.cpp
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -1,18 +1,21 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class X {
public:
- explicit X(const X&);
- X(int*); // expected-note 2{{candidate constructor}}
- explicit X(float*);
+ explicit X(const X&); // expected-note {{candidate constructor}}
+ X(int*); // expected-note 3{{candidate constructor}}
+ explicit X(float*); // expected-note {{candidate constructor}}
};
class Y : public X { };
void f(Y y, int *ip, float *fp) {
X x1 = y; // expected-error{{no matching constructor for initialization of 'X'}}
- X x2 = 0;
- X x3 = ip;
+ X x2 = 0; // expected-error{{no viable constructor copying variable}}
+ X x3 = ip; // expected-error{{no viable constructor copying variable}}
X x4 = fp; // expected-error{{no viable conversion}}
+ X x2a(0); // expected-error{{call to constructor of 'X' is ambiguous}}
+ X x3a(ip);
+ X x4a(fp);
}
struct foo {
@@ -25,19 +28,17 @@ void test(const foo *P) { P->bar(); } // expected-error{{cannot initialize objec
namespace PR6757 {
struct Foo {
Foo();
- Foo(Foo&);
+ Foo(Foo&); // expected-note{{candidate constructor not viable}}
};
struct Bar {
operator const Foo&() const;
};
- void f(Foo); // expected-note{{candidate function not viable: no known conversion from 'PR6757::Bar' to 'PR6757::Foo' for 1st argument}}
+ void f(Foo);
- // FIXME: This isn't really the right reason for the failure. We
- // should fail after overload resolution.
void g(Foo foo) {
- f(Bar()); // expected-error{{no matching function for call to 'f'}}
+ f(Bar()); // expected-error{{no viable constructor copying parameter of type 'PR6757::Foo const'}}
f(foo);
}
}
diff --git a/test/SemaCXX/cstyle-cast.cpp b/test/SemaCXX/cstyle-cast.cpp
index 6a28f4c2c875..ccb25f00c24e 100644
--- a/test/SemaCXX/cstyle-cast.cpp
+++ b/test/SemaCXX/cstyle-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -faccess-control %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A {};
diff --git a/test/SemaCXX/default-assignment-operator.cpp b/test/SemaCXX/default-assignment-operator.cpp
index baae03cf1347..a04de37fcb6a 100644
--- a/test/SemaCXX/default-assignment-operator.cpp
+++ b/test/SemaCXX/default-assignment-operator.cpp
@@ -1,13 +1,17 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}}
- int &ref; // expected-note {{declared at}}
+class Base { // expected-error {{cannot define the implicit default assignment operator for 'Base', because non-static reference member 'ref' can't use default assignment operator}} \
+ // expected-warning{{class 'Base' does not declare any constructor to initialize its non-modifiable members}} \
+ // expected-note {{synthesized method is first required here}}
+ int &ref; // expected-note {{declared here}} \
+ // expected-note{{reference member 'ref' will never be initialized}}
};
-class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}}
+class X : Base { // // expected-error {{cannot define the implicit default assignment operator for 'X', because non-static const member 'cint' can't use default assignment operator}} \
+ // expected-note {{synthesized method is first required here}}
public:
X();
- const int cint; // expected-note {{declared at}}
+ const int cint; // expected-note {{declared here}}
};
struct Y : X {
@@ -25,7 +29,7 @@ Z z2;
// Test1
void f(X x, const X cx) {
- x = cx; // expected-note 2 {{synthesized method is first required here}}
+ x = cx;
x = cx;
z1 = z2;
}
@@ -70,9 +74,11 @@ void i() {
// Test5
-class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}}
+class E1 { // expected-error{{cannot define the implicit default assignment operator for 'E1', because non-static const member 'a' can't use default assignment operator}} \
+ // expected-note {{synthesized method is first required here}}
+
public:
- const int a; // expected-note{{declared at}}
+ const int a; // expected-note{{declared here}}
E1() : a(0) {}
};
@@ -80,6 +86,6 @@ public:
E1 e1, e2;
void j() {
- e1 = e2; // expected-note{{synthesized method is first required here}}
+ e1 = e2;
}
diff --git a/test/SemaCXX/default-constructor-initializers.cpp b/test/SemaCXX/default-constructor-initializers.cpp
index b40b133a5541..757332df0b05 100644
--- a/test/SemaCXX/default-constructor-initializers.cpp
+++ b/test/SemaCXX/default-constructor-initializers.cpp
@@ -16,7 +16,7 @@ X3 x3; // expected-note {{first required here}}
struct X4 { // expected-error {{must explicitly initialize the member 'x2'}} \
// expected-error {{must explicitly initialize the reference member 'rx2'}}
X2 x2; // expected-note {{member is declared here}}
- X2 & rx2; // expected-note {{declared at}}
+ X2 & rx2; // expected-note {{declared here}}
};
X4 x4; // expected-note {{first required here}}
@@ -46,8 +46,8 @@ Y4 y4;
struct Z1 { // expected-error {{must explicitly initialize the reference member 'z'}} \
// expected-error {{must explicitly initialize the const member 'c1'}}
- int& z; // expected-note {{declared at}}
- const int c1; // expected-note {{declared at}}
+ int& z; // expected-note {{declared here}}
+ const int c1; // expected-note {{declared here}}
volatile int v1;
};
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index 790208aa1d05..e9d8a2f767bc 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -14,7 +14,8 @@ void h(int i, int j = 2, int k = 3,
int n);// expected-error {{missing default argument on parameter 'n'}}
struct S { } s;
-void i(int = s) { } // expected-error {{no viable conversion}}
+void i(int = s) { } // expected-error {{no viable conversion}} \
+// expected-note{{passing argument to parameter here}}
struct X {
X(int);
@@ -26,6 +27,8 @@ struct Y { // expected-note 2{{candidate}}
explicit Y(int);
};
-void k(Y y = 17); // expected-error{{no viable conversion}}
+void k(Y y = 17); // expected-error{{no viable conversion}} \
+// expected-note{{passing argument to parameter 'y' here}}
-void kk(Y = 17); // expected-error{{no viable conversion}}
+void kk(Y = 17); // expected-error{{no viable conversion}} \
+// expected-note{{passing argument to parameter here}}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index a0999c0c4c62..d9f1edf3b2a1 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -102,7 +102,8 @@ void test_Z(const Z& z) {
struct ZZ {
static ZZ g(int = 17);
- void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}}
+ void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}} \
+ // expected-note{{passing argument to parameter 'z' here}}
ZZ(ZZ&, int = 17); // expected-note{{candidate constructor}}
};
diff --git a/test/SemaCXX/derived-to-base-ambig.cpp b/test/SemaCXX/derived-to-base-ambig.cpp
index 9216e5b03798..129ec79182fe 100644
--- a/test/SemaCXX/derived-to-base-ambig.cpp
+++ b/test/SemaCXX/derived-to-base-ambig.cpp
@@ -6,7 +6,7 @@ class D : public B, public C { };
void f(D* d) {
A* a;
- a = d; // expected-error{{ambiguous conversion from derived class 'D' to base class 'A':}} expected-error{{incompatible type assigning 'D *', expected 'A *'}}
+ a = d; // expected-error{{ambiguous conversion from derived class 'D' to base class 'A':}} expected-error{{assigning to 'A *' from incompatible type 'D *'}}
}
class Object2 { };
@@ -20,7 +20,7 @@ class F2 : public E2, public A2 { };
void g(E2* e2, F2* f2) {
Object2* o2;
o2 = e2;
- o2 = f2; // expected-error{{ambiguous conversion from derived class 'F2' to base class 'Object2':}} expected-error{{incompatible type assigning 'F2 *', expected 'Object2 *'}}
+ o2 = f2; // expected-error{{ambiguous conversion from derived class 'F2' to base class 'Object2':}} expected-error{{assigning to 'Object2 *' from incompatible type 'F2 *'}}
}
// Test that ambiguous/inaccessibility checking does not trigger too
diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp
index d30642b5c3ec..54cd6cacc0d4 100644
--- a/test/SemaCXX/direct-initializer.cpp
+++ b/test/SemaCXX/direct-initializer.cpp
@@ -10,7 +10,7 @@ void f() {
}
class Y {
- explicit Y(float);
+public: explicit Y(float);
};
class X { // expected-note{{candidate constructor (the implicit copy constructor)}}
diff --git a/test/SemaCXX/elaborated-type-specifier.cpp b/test/SemaCXX/elaborated-type-specifier.cpp
index 3cd3a1bc2241..2d0b571e0273 100644
--- a/test/SemaCXX/elaborated-type-specifier.cpp
+++ b/test/SemaCXX/elaborated-type-specifier.cpp
@@ -22,7 +22,7 @@ namespace NS {
void test_elab2(struct S4 *s4);
};
- void X::test_elab2(S4 *s4) { }
+ void X::test_elab2(S4 *s4) { } // expected-note{{passing argument to parameter 's4' here}}
}
void test_X_elab(NS::X x) {
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index 2ed4bfe88562..18349d10ef71 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -97,3 +97,26 @@ BadReturn::BadReturn(int) try {
}
}
}
+
+// Cannot throw an abstract type.
+class foo {
+public:
+ foo() {}
+ void bar () {
+ throw *this; // expected-error{{cannot throw an object of abstract type 'foo'}}
+ }
+ virtual void test () = 0; // expected-note{{pure virtual function 'test'}}
+};
+
+namespace PR6831 {
+ namespace NA { struct S; }
+ namespace NB { struct S; }
+
+ void f() {
+ using namespace NA;
+ using namespace NB;
+ try {
+ } catch (int S) {
+ }
+ }
+}
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
index 4e0486c79ac2..3b088645a65b 100644
--- a/test/SemaCXX/functional-cast.cpp
+++ b/test/SemaCXX/functional-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -faccess-control %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
// ------------ not interpreted as C-style cast ------------
diff --git a/test/SemaCXX/illegal-member-initialization.cpp b/test/SemaCXX/illegal-member-initialization.cpp
index 3fb0b93fc4f6..87069efaacc7 100644
--- a/test/SemaCXX/illegal-member-initialization.cpp
+++ b/test/SemaCXX/illegal-member-initialization.cpp
@@ -14,9 +14,9 @@ struct X {
// expected-error {{constructor for 'X' must explicitly initialize the const member 'cvalue'}} \
// expected-error {{constructor for 'X' must explicitly initialize the reference member 'b'}} \
// expected-error {{constructor for 'X' must explicitly initialize the const member 'cb'}}
- int &value; // expected-note{{declared at}}
- const int cvalue; // expected-note{{declared at}}
- B& b; // expected-note{{declared at}}
+ int &value; // expected-note{{declared here}}
+ const int cvalue; // expected-note{{declared here}}
+ B& b; // expected-note{{declared here}}
const B cb; // expected-note{{declared here}}
};
diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp
index 40a61e47fd3c..79cc3679f498 100644
--- a/test/SemaCXX/implicit-member-functions.cpp
+++ b/test/SemaCXX/implicit-member-functions.cpp
@@ -1,14 +1,41 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-struct A { }; // expected-note {{previous implicit declaration is here}}
+struct A { };
A::A() { } // expected-error {{definition of implicitly declared constructor}}
-struct B { }; // expected-note {{previous implicit declaration is here}}
+struct B { };
B::B(const B&) { } // expected-error {{definition of implicitly declared copy constructor}}
-struct C { }; // expected-note {{previous implicit declaration is here}}
+struct C { };
C& C::operator=(const C&) { return *this; } // expected-error {{definition of implicitly declared copy assignment operator}}
-struct D { }; // expected-note {{previous implicit declaration is here}}
+struct D { };
D::~D() { } // expected-error {{definition of implicitly declared destructor}}
+// Make sure that the special member functions are introduced for
+// name-lookup purposes and overload with user-declared
+// constructors and assignment operators.
+namespace PR6570 {
+ class A { };
+
+ class B {
+ public:
+ B() {}
+
+ B(const A& a) {
+ operator = (CONST);
+ operator = (a);
+ }
+
+ B& operator = (const A& a) {
+ return *this;
+ }
+
+ void f(const A &a) {
+ B b(a);
+ };
+
+ static const B CONST;
+ };
+
+}
diff --git a/test/SemaCXX/inc-decrement-qualifiers.cpp b/test/SemaCXX/inc-decrement-qualifiers.cpp
new file mode 100644
index 000000000000..ba837a9c06db
--- /dev/null
+++ b/test/SemaCXX/inc-decrement-qualifiers.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+volatile int i;
+
+const int &inc = i++;
+const int &dec = i--;
+
+const int &incfail = ++i; // expected-error {{drops qualifiers}}
+const int &decfail = --i; // expected-error {{drops qualifiers}}
diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index 7a4bebca864e..2e9203219536 100644
--- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -1,5 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only %s
+// This is a test for an egregious hack in Clang that works around
+// issues with GCC's evolution. libstdc++ 4.2.x uses __is_pod as an
+// identifier (to declare a struct template like the one below), while
+// GCC 4.3 and newer make __is_pod a keyword. Clang treats __is_pod as
+// a keyword *unless* it is introduced following the struct keyword.
+
template<typename T>
struct __is_pod {
};
diff --git a/test/SemaCXX/libstdcxx_map_base_hack.cpp b/test/SemaCXX/libstdcxx_map_base_hack.cpp
new file mode 100644
index 000000000000..a556281fc0f8
--- /dev/null
+++ b/test/SemaCXX/libstdcxx_map_base_hack.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+
+// libstdc++ 4.2.x contains a bug where a friend struct template
+// declaration for std::tr1::__detail::_Map base has different
+// template arguments than the real declaration. Clang has an
+// egregious hack to work around this problem, since we can't modify
+// all of the world's libstdc++'s.
+
+namespace std { namespace tr1 { namespace __detail {
+ template<typename _Key, typename _Value, typename _Ex, bool __unique,
+ typename _Hashtable>
+ struct _Map_base { };
+
+} } }
+
+namespace std { namespace tr1 {
+ template<typename T>
+ struct X1 {
+ template<typename _Key2, typename _Pair, typename _Hashtable>
+ friend struct __detail::_Map_base;
+ };
+
+} }
+
+std::tr1::X1<int> x1i;
diff --git a/test/SemaCXX/local-classes.cpp b/test/SemaCXX/local-classes.cpp
index 6799e58e954e..500b2197ef35 100644
--- a/test/SemaCXX/local-classes.cpp
+++ b/test/SemaCXX/local-classes.cpp
@@ -30,3 +30,12 @@ namespace PR6383 {
compare_and_set2 (false, gross);
}
}
+
+namespace Templates {
+ template<int Value>
+ void f() {
+ struct Inner {
+ static int getValue() { return Value; }
+ };
+ }
+}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 13ff64d8cffc..54a95936bed1 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -2,7 +2,7 @@
class X{
public:
- enum E {Enumerator};
+ enum E {Enumerator}; // expected-note 2{{declared here}}
int f();
static int mem;
static float g();
@@ -11,8 +11,8 @@ public:
void test(X* xp, X x) {
int i1 = x.f();
int i2 = xp->f();
- x.E; // expected-error{{cannot refer to type member 'E' with '.'}}
- xp->E; // expected-error{{cannot refer to type member 'E' with '->'}}
+ x.E; // expected-error{{cannot refer to type member 'E' in 'X' with '.'}}
+ xp->E; // expected-error{{cannot refer to type member 'E' in 'X' with '->'}}
int i3 = x.Enumerator;
int i4 = xp->Enumerator;
x.mem = 1;
@@ -56,3 +56,19 @@ namespace test3 {
}
};
}
+
+namespace test4 {
+ class X {
+ protected:
+ template<typename T> void f(T);
+ };
+
+ class Y : public X {
+ public:
+ using X::f;
+ };
+
+ void test_f(Y y) {
+ y.f(17);
+ }
+}
diff --git a/test/SemaCXX/member-location.cpp b/test/SemaCXX/member-location.cpp
index c3099d25e0e1..6f7e1f577519 100644
--- a/test/SemaCXX/member-location.cpp
+++ b/test/SemaCXX/member-location.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR4103: Make sure we have a location for the error
-class A { float a(int *); int b(); };
+class A {
+ float a(int *); // expected-note{{passing argument to parameter here}}
+ int b();
+};
int A::b() { return a(a((int*)0)); } // expected-error {{cannot initialize a parameter of type 'int *' with an rvalue of type 'float'}}
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 92ae92d710ce..be25cbdb7ed0 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -38,7 +38,7 @@ void f() {
int G::*pdig = pdi1; // expected-error {{conversion from pointer to member of class 'A' to pointer to member of class 'G' via virtual base 'D' is not allowed}}
// Conversion to member of base.
- pdi1 = pdid; // expected-error {{incompatible type assigning 'int D::*', expected 'int A::*'}}
+ pdi1 = pdid; // expected-error {{assigning to 'int A::*' from incompatible type 'int D::*'}}
// Comparisons
int (A::*pf2)(int, int);
@@ -88,7 +88,7 @@ void g() {
void (HasMembers::*pmd)() = &HasMembers::d;
}
-struct Incomplete;
+struct Incomplete; // expected-note {{forward declaration}}
void h() {
HasMembers hm, *phm = &hm;
@@ -123,7 +123,7 @@ void h() {
Incomplete *inc;
int Incomplete::*pii = 0;
- (void)(inc->*pii); // okay
+ (void)(inc->*pii); // expected-error {{pointer into incomplete}}
}
struct OverloadsPtrMem
@@ -147,3 +147,13 @@ namespace pr5985 {
}
};
}
+
+namespace pr6783 {
+ struct Base {};
+ struct X; // expected-note {{forward declaration}}
+
+ int test1(int Base::* p2m, X* object)
+ {
+ return object->*p2m; // expected-error {{left hand operand to ->*}}
+ }
+}
diff --git a/test/SemaCXX/missing-header.cpp b/test/SemaCXX/missing-header.cpp
new file mode 100644
index 000000000000..f43657990058
--- /dev/null
+++ b/test/SemaCXX/missing-header.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#include "not exist" // expected-error{{'not exist' file not found}}
+
+class AnalysisContext {};
+static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {}
+ bool NoReturnEdge = false;
+}
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index 3ea1ccfd9f70..1c3da3c656a6 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -91,3 +91,13 @@ namespace A = N;
A::X nx;
+namespace PR7014 {
+ namespace X
+ {
+ namespace Y {}
+ }
+
+ using namespace X;
+
+ namespace Y = X::Y;
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 9a611c38ad6d..59a8e8c45dc7 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -13,9 +13,9 @@ namespace A {
}
A:: ; // expected-error {{expected unqualified-id}}
-// FIXME: redundant errors
-::A::ax::undef ex3; // expected-error {{no member named}} expected-error {{unknown type name}}
-A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{unknown type name}}
+// FIXME: there is a member 'ax'; it's just not a class.
+::A::ax::undef ex3; // expected-error {{no member named 'ax'}}
+A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}}
int A::C::Ag1() { return 0; }
@@ -165,8 +165,7 @@ void ::global_func2(int) { } // expected-error{{definition or redeclaration of '
void N::f() { } // okay
struct Y; // expected-note{{forward declaration of 'Y'}}
-Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}} \
- // expected-error{{no type named 'foo' in}}
+Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}}
X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \
// expected-error{{C++ requires a type specifier for all declarations}} \
@@ -195,7 +194,7 @@ somens::a a3 = a2; // expected-error {{no viable conversion}}
// typedefs and using declarations.
namespace test1 {
namespace ns {
- class Counter { static int count; };
+ class Counter { public: static int count; };
typedef Counter counter;
}
using ns::counter;
@@ -224,9 +223,8 @@ namespace test2 {
// PR6259, invalid case
namespace test3 {
- // FIXME: this should really only trigger once
- class A; // expected-note 2 {{forward declaration}}
+ class A; // expected-note {{forward declaration}}
void foo(const char *path) {
- A::execute(path); // expected-error 2 {{incomplete type 'test3::A' named in nested name specifier}}
+ A::execute(path); // expected-error {{incomplete type 'test3::A' named in nested name specifier}}
}
}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index ae77e704f501..763ed2c7b4d6 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -34,7 +34,6 @@ void good_news()
S *ps = new S(1, 2, 3.4);
ps = new (pf) (S)(1, 2, 3.4);
S *(*paps)[2] = new S*[*pi][2];
- ps = new (S[3])(1, 2, 3.4);
typedef int ia4[4];
ia4 *pai = new (int[3][4]);
pi = ::new int;
@@ -182,6 +181,7 @@ void f(X8 *x8) {
}
class X9 {
+public:
static void operator delete(void*, int); // expected-note {{'operator delete' declared here}}
static void operator delete(void*, float); // expected-note {{'operator delete' declared here}}
};
@@ -216,6 +216,7 @@ static void* f(void* g)
}
class X14 {
+public:
static void operator delete(void*, const size_t);
};
@@ -229,3 +230,23 @@ namespace PR5918 { // Look for template operator new overloads.
(void)new(0) S;
}
}
+
+namespace Test1 {
+
+void f() {
+ (void)new int[10](1, 2); // expected-error {{array 'new' cannot have initialization arguments}}
+}
+
+template<typename T>
+void g(unsigned i) {
+ (void)new T[1](i); // expected-error {{array 'new' cannot have initialization arguments}}
+}
+
+template<typename T>
+void h(unsigned i) {
+ (void)new T(i); // expected-error {{array 'new' cannot have initialization arguments}}
+}
+template void h<unsigned>(unsigned);
+template void h<unsigned[10]>(unsigned); // expected-note {{in instantiation of function template specialization 'Test1::h<unsigned int [10]>' requested here}}
+
+}
diff --git a/test/SemaCXX/no-exceptions.cpp b/test/SemaCXX/no-exceptions.cpp
new file mode 100644
index 000000000000..019e25c97842
--- /dev/null
+++ b/test/SemaCXX/no-exceptions.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// Various tests for -fno-exceptions
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace test0 {
+ // rdar://problem/7878149
+ class Foo {
+ public:
+ void* operator new(size_t x);
+ private:
+ void operator delete(void *x);
+ };
+
+ void test() {
+ // Under -fexceptions, this does access control for the associated
+ // 'operator delete'.
+ (void) new Foo();
+ }
+}
diff --git a/test/SemaCXX/offsetof.cpp b/test/SemaCXX/offsetof.cpp
index 3283270847fd..47c3f22a0ed3 100644
--- a/test/SemaCXX/offsetof.cpp
+++ b/test/SemaCXX/offsetof.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -Winvalid-offsetof
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s -Winvalid-offsetof
struct NonPOD {
virtual void f();
@@ -18,3 +18,38 @@ struct Derived : Base { int y; };
int o = __builtin_offsetof(Derived, x); // expected-warning{{offset of on non-POD type}}
const int o2 = sizeof(__builtin_offsetof(Derived, x));
+
+struct HasArray {
+ int array[17];
+};
+
+// Constant and non-constant offsetof expressions
+void test_ice(int i) {
+ int array0[__builtin_offsetof(HasArray, array[5])];
+ int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}}
+}
+
+// Bitfields
+struct has_bitfields {
+ int i : 7;
+ int j : 12; // expected-note{{bit-field is declared here}}
+};
+
+int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cannot compute offset of bit-field 'j'}}
+
+// offsetof referring to members of a base class.
+struct Base1 {
+ int x;
+};
+
+struct Base2 {
+ int y;
+};
+
+struct Derived2 : public Base1, public Base2 {
+ int z;
+};
+
+int derived1[__builtin_offsetof(Derived2, x) == 0? 1 : -1];
+int derived2[__builtin_offsetof(Derived2, y) == 4? 1 : -1];
+int derived3[__builtin_offsetof(Derived2, z) == 8? 1 : -1];
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index c286028c29af..79c74cec4947 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -247,14 +247,14 @@ struct Z : X, Y { };
int& cvqual_subsume(X&); // expected-note{{candidate function}}
float& cvqual_subsume(const Y&); // expected-note{{candidate function}}
-int& cvqual_subsume2(const X&);
-float& cvqual_subsume2(const volatile Y&);
+int& cvqual_subsume2(const X&); // expected-note{{candidate function}}
+float& cvqual_subsume2(const volatile Y&); // expected-note{{candidate function}}
Z get_Z();
void cvqual_subsume_test(Z z) {
cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
- int& x = cvqual_subsume2(get_Z()); // okay: only binds to the first one
+ int& x = cvqual_subsume2(get_Z()); // expected-error{{call to 'cvqual_subsume2' is ambiguous; candidates are:}}
}
// Test overloading with cv-qualification differences in reference
@@ -406,3 +406,27 @@ namespace PR6483 {
f1(x1); // expected-error{{no matching function for call}}
}
}
+
+namespace PR6078 {
+ struct A {
+ A(short); // expected-note{{candidate constructor}}
+ A(long); // expected-note{{candidate constructor}}
+ };
+ struct S {
+ typedef void ft(A);
+ operator ft*();
+ };
+
+ void f() {
+ S()(0); // expected-error{{conversion from 'int' to 'PR6078::A' is ambiguous}}
+ }
+}
+
+namespace PR6177 {
+ struct String { String(char const*); };
+
+ void f(bool const volatile&); // expected-note{{passing argument to parameter here}}
+ void f(String);
+
+ void g() { f(""); } // expected-error{{volatile lvalue reference to type 'bool const volatile' cannot bind to a value of unrelated type 'char const [1]'}}
+}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 89f181469fdf..3d737f4d3050 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -88,6 +88,7 @@ enum pr5244_bar
class pr5244_baz
{
+public:
pr5244_bar quux;
};
@@ -258,7 +259,7 @@ bool x(BB y, BB z) { return y != z; }
struct AX {
- AX& operator ->(); // expected-note {{declared at}}
+ AX& operator ->(); // expected-note {{declared here}}
int b;
};
@@ -268,14 +269,14 @@ void m() {
}
struct CircA {
- struct CircB& operator->(); // expected-note {{declared at}}
+ struct CircB& operator->(); // expected-note {{declared here}}
int val;
};
struct CircB {
- struct CircC& operator->(); // expected-note {{declared at}}
+ struct CircC& operator->(); // expected-note {{declared here}}
};
struct CircC {
- struct CircA& operator->(); // expected-note {{declared at}}
+ struct CircA& operator->(); // expected-note {{declared here}}
};
void circ() {
@@ -355,3 +356,24 @@ namespace pr5900 {
x(); // expected-error {{does not provide a call operator}}
}
}
+
+// Operator lookup through using declarations.
+namespace N {
+ struct X2 { };
+}
+
+namespace N2 {
+ namespace M {
+ namespace Inner {
+ template<typename T>
+ N::X2 &operator<<(N::X2&, const T&);
+ }
+ using Inner::operator<<;
+ }
+}
+
+void test_lookup_through_using() {
+ using namespace N2::M;
+ N::X2 x;
+ x << 17;
+}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index 4846e72e5926..e5c730677561 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -48,7 +48,7 @@ namespace C
a.A::sub::x();
a.A::B::base::x();
- a.bad::x(); // expected-error{{type 'bad' is not a direct or virtual base of ''A::sub''}}
+ a.bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}}
a->foo();
a->member::foo();
@@ -69,7 +69,7 @@ namespace C
a->A::sub::x();
a->A::B::base::x();
- a->bad::x(); // expected-error{{type 'bad' is not a direct or virtual base of ''A::sub''}}
+ a->bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}}
(*a)->foo();
(*a)->member::foo();
@@ -107,7 +107,7 @@ namespace C
a.A::B::base::x();
a->A::member::foo();
- a.bad::x(); // expected-error{{direct or virtual}}
+ a.bad::x(); // expected-error{{'bad::x' is not a member of class 'A::sub'}}
}
void test_fun5() {
diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp
index abde62efceae..dfb059aa36ad 100644
--- a/test/SemaCXX/qualified-id-lookup.cpp
+++ b/test/SemaCXX/qualified-id-lookup.cpp
@@ -124,3 +124,25 @@ namespace test1 {
template class ClassChecker<int>;
}
+
+namespace PR6830 {
+ namespace foo {
+
+ class X {
+ public:
+ X() {}
+ };
+
+ } // namespace foo
+
+ class Z {
+ public:
+ explicit Z(const foo::X& x) {}
+
+ void Work() {}
+ };
+
+ void Test() {
+ Z(foo::X()).Work();
+ }
+}
diff --git a/test/SemaCXX/ref-init-ambiguous.cpp b/test/SemaCXX/ref-init-ambiguous.cpp
index 8844162052d9..a8e95a39539d 100644
--- a/test/SemaCXX/ref-init-ambiguous.cpp
+++ b/test/SemaCXX/ref-init-ambiguous.cpp
@@ -17,7 +17,7 @@ void test(C c) {
const E2 &e2 = c; // expected-error {{reference initialization of type 'E2 const &' with initializer of type 'C' is ambiguous}}
}
-void foo(const E2 &);
+void foo(const E2 &);// expected-note{{passing argument to parameter here}}
const E2 & re(C c) {
foo(c); // expected-error {{reference initialization of type 'E2 const &' with initializer of type 'C' is ambiguous}}
diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp
index f1f4ab9f9541..e40ea01a9b99 100644
--- a/test/SemaCXX/references.cpp
+++ b/test/SemaCXX/references.cpp
@@ -66,8 +66,8 @@ int& test6(int& x) {
int& not_initialized_error; // expected-error{{declaration of reference variable 'not_initialized_error' requires an initializer}}
extern int& not_initialized_okay;
-class Test6 {
- int& okay;
+class Test6 { // expected-warning{{class 'Test6' does not declare any constructor to initialize its non-modifiable members}}
+ int& okay; // expected-note{{reference member 'okay' will never be initialized}}
};
struct C : B, A { };
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
index a5dd7e214dc2..48f641aa997b 100644
--- a/test/SemaCXX/static-cast.cpp
+++ b/test/SemaCXX/static-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -faccess-control %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A {};
struct B : public A {}; // Single public base.
struct C1 : public virtual B {}; // Single virtual base.
diff --git a/test/SemaCXX/storage-class.cpp b/test/SemaCXX/storage-class.cpp
new file mode 100644
index 000000000000..a2e206323a07
--- /dev/null
+++ b/test/SemaCXX/storage-class.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+extern const int PR6495a = 42;
+extern int PR6495b = 42; // expected-warning{{'extern' variable has an initializer}}
+extern const int PR6495c[] = {42,43,44};
diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp
index c382539e05f1..49e1f3aa79e5 100644
--- a/test/SemaCXX/typedef-redecl.cpp
+++ b/test/SemaCXX/typedef-redecl.cpp
@@ -13,7 +13,7 @@ struct X {
struct Y; // expected-note{{previous definition is here}}
typedef int Y; // expected-error{{typedef redefinition with different types ('int' vs 'Y')}}
-typedef int Y2; // expected-note{{previous definition is here}}
+typedef int Y2; // expected-note{{declared here}}
struct Y2; // expected-error{{definition of type 'Y2' conflicts with typedef of the same name}}
void f(); // expected-note{{previous definition is here}}
@@ -37,3 +37,14 @@ namespace test1 {
using namespace a;
foo x;
}
+
+namespace PR6923 {
+ struct A;
+
+ extern "C" {
+ struct A;
+ typedef struct A A;
+ }
+
+ struct A;
+}
diff --git a/test/SemaCXX/typeid-ref.cpp b/test/SemaCXX/typeid-ref.cpp
new file mode 100644
index 000000000000..da0016970bee
--- /dev/null
+++ b/test/SemaCXX/typeid-ref.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+namespace std {
+ class type_info;
+}
+
+struct X { };
+
+void f() {
+ // CHECK: @_ZTS1X = weak_odr constant
+ // CHECK: @_ZTI1X = weak_odr constant
+ (void)typeid(X&);
+}
diff --git a/test/SemaCXX/typeid.cpp b/test/SemaCXX/typeid.cpp
index 0e78ff46a65c..8db7db507464 100644
--- a/test/SemaCXX/typeid.cpp
+++ b/test/SemaCXX/typeid.cpp
@@ -5,7 +5,6 @@ void f()
(void)typeid(int); // expected-error {{error: you need to include <typeinfo> before using the 'typeid' operator}}
}
-// FIXME: This should really include <typeinfo>, but we don't have that yet.
namespace std {
class type_info;
}
diff --git a/test/SemaCXX/unused-functions.cpp b/test/SemaCXX/unused-functions.cpp
new file mode 100644
index 000000000000..cefa9e118a48
--- /dev/null
+++ b/test/SemaCXX/unused-functions.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s
+
+static int foo(int x) { return x; }
+
+template<typename T>
+T get_from_foo(T y) { return foo(y); }
+
+int g(int z) { return get_from_foo(z); }
diff --git a/test/SemaCXX/user-defined-conversions.cpp b/test/SemaCXX/user-defined-conversions.cpp
index 4367f4b8a353..5de7f44be92c 100644
--- a/test/SemaCXX/user-defined-conversions.cpp
+++ b/test/SemaCXX/user-defined-conversions.cpp
@@ -67,3 +67,18 @@ void test_conversion(ConvertibleToBase ctb, ConvertibleToDerived ctd,
Base b4(ctd);
Base b5 = ctfd;
}
+
+struct X1 {
+ X1(X1&); // expected-note{{candidate constructor not viable: no known conversion from 'X1' to 'X1 &' for 1st argument}}
+};
+
+struct X2 {
+ operator X1();
+};
+
+int &f(X1);
+float &f(...);
+
+void g(X2 b) {
+ int &ir = f(b); // expected-error{{no viable constructor copying parameter of type 'X1'}}
+}
diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp
index 16a7a1d0c9b9..10520fb8bba4 100644
--- a/test/SemaCXX/value-initialization.cpp
+++ b/test/SemaCXX/value-initialization.cpp
@@ -1,7 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
-struct A { // expected-error {{implicit default constructor for 'A' must explicitly initialize the const member 'i'}}
- const int i; // expected-note {{declared at}}
+struct A { // expected-error {{implicit default constructor for 'A' must explicitly initialize the const member 'i'}} \
+ // expected-warning{{struct 'A' does not declare any constructor to initialize its non-modifiable members}}
+ const int i; // expected-note {{declared here}} \
+ // expected-note{{const member 'i' will never be initialized}}
virtual void f() { }
};
diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp
index 688713582657..e07531f64365 100644
--- a/test/SemaCXX/virtual-override.cpp
+++ b/test/SemaCXX/virtual-override.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s -std=c++0x
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
namespace T1 {
class A {
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
index ce16a68a77ef..e5a3425804b8 100644
--- a/test/SemaCXX/warn-assignment-condition.cpp
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -12,33 +12,42 @@ void test() {
// With scalars.
if (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
if ((x = 7)) {}
do {
} while (x = 7); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
do {
} while ((x = 7));
while (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
+
while ((x = 7)) {}
for (; x = 7; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
for (; (x = 7); ) {}
if (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
if ((p = p)) {}
do {
} while (p = p); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
do {
} while ((p = p));
while (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
while ((p = p)) {}
for (; p = p; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
for (; (p = p); ) {}
// Initializing variables (shouldn't warn).
@@ -49,33 +58,41 @@ void test() {
// With temporaries.
if (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
if ((x = (b+b).foo())) {}
do {
} while (x = (b+b).foo()); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
do {
} while ((x = (b+b).foo()));
while (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
while ((x = (b+b).foo())) {}
for (; x = (b+b).foo(); ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
for (; (x = (b+b).foo()); ) {}
// With a user-defined operator.
if (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
if ((a = b + b)) {}
do {
} while (a = b + b); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
do {
} while ((a = b + b));
while (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
while ((a = b + b)) {}
for (; a = b + b; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
- // expected-note{{use '==' to turn this assignment into an equality comparison}}
+ // expected-note{{use '==' to turn this assignment into an equality comparison}} \
+ // expected-note{{place parentheses around the assignment to silence this warning}}
for (; (a = b + b); ) {}
}
diff --git a/test/SemaCXX/warn-missing-noreturn.cpp b/test/SemaCXX/warn-missing-noreturn.cpp
index 32d020f15f3d..8016c3da5cc5 100644
--- a/test/SemaCXX/warn-missing-noreturn.cpp
+++ b/test/SemaCXX/warn-missing-noreturn.cpp
@@ -22,3 +22,17 @@ struct B {
};
template void B::g<int>(int); // expected-note {{in instantiation of function template specialization 'B::g<int>' requested here}}
+
+// We don't want a warning here.
+struct X {
+ virtual void g() { f(); }
+};
+
+namespace test1 {
+ bool condition();
+
+ // We don't want a warning here.
+ void foo() {
+ while (condition()) {}
+ }
+}
diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
index f4191565dfdb..3ff01af3627c 100644
--- a/test/SemaCXX/warn-reorder-ctor-initialization.cpp
+++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -6,12 +6,13 @@ struct BB1 {};
class complex : public BB, BB1 {
public:
- complex() : s2(1), // expected-warning {{member 's2' will be initialized after}}
- s1(1) , // expected-note {{field s1}}
- s3(3), // expected-warning {{member 's3' will be initialized after}}
- BB1(), // expected-note {{base 'BB1'}} \
- // expected-warning {{base class 'BB1' will be initialized after}}
- BB() {} // expected-note {{base 'BB'}}
+ complex()
+ : s2(1), // expected-warning {{field 's2' will be initialized after field 's1'}}
+ s1(1),
+ s3(3), // expected-warning {{field 's3' will be initialized after base 'BB1'}}
+ BB1(), // expected-warning {{base class 'BB1' will be initialized after base 'BB'}}
+ BB()
+ {}
int s1;
int s2;
int s3;
@@ -44,14 +45,12 @@ struct C : public A, public B, private virtual V {
struct D : public A, public B {
- D() : A(), V() { } // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ D() : A(), V() { } // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
struct E : public A, public B, private virtual V {
- E() : A(), V() { } // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ E() : A(), V() { } // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
@@ -64,13 +63,11 @@ struct B1 {
};
struct F : public A1, public B1, private virtual V {
- F() : A1(), V() { } // expected-warning {{base class 'A1' will be initialized after}} \
- // expected-note {{base 'V'}}
+ F() : A1(), V() { } // expected-warning {{base class 'A1' will be initialized after base 'V'}}
};
struct X : public virtual A, virtual V, public virtual B {
- X(): A(), V(), B() {} // expected-warning {{base class 'A' will be initialized after}} \
- // expected-note {{base 'V'}}
+ X(): A(), V(), B() {} // expected-warning {{base class 'A' will be initialized after base 'V'}}
};
class Anon {
@@ -80,8 +77,8 @@ class Anon {
class Anon2 {
int c; union {int a,b;}; int d;
Anon2() : c(2),
- d(10), // expected-warning {{member 'd' will be initialized after}}
- b(1) {} // expected-note {{field b}}
+ d(10), // expected-warning {{field 'd' will be initialized after field 'b'}}
+ b(1) {}
};
class Anon3 {
union {int a,b;};
@@ -95,7 +92,31 @@ struct S2: virtual S1 { };
struct S3 { };
struct S4: virtual S3, S2 {
- S4() : S2(), // expected-warning {{base class 'T1::S2' will be initialized after}}
- S3() { }; // expected-note {{base 'T1::S3'}}
+ S4() : S2(), // expected-warning {{base class 'T1::S2' will be initialized after base 'T1::S3'}}
+ S3() { };
};
}
+
+namespace test2 {
+ struct Foo { Foo(); };
+ class A {
+ template <class T> A(T *t) :
+ y(), // expected-warning {{field 'y' will be initialized after field 'x'}}
+ x()
+ {}
+ Foo x;
+ Foo y;
+ };
+}
+
+// PR6575: this should not crash
+namespace test3 {
+ struct MyClass {
+ MyClass() : m_int(0) {}
+ union {
+ struct {
+ int m_int;
+ };
+ };
+ };
+}
diff --git a/test/SemaCXX/warn-unused-parameters.cpp b/test/SemaCXX/warn-unused-parameters.cpp
new file mode 100644
index 000000000000..75d8dcc549c9
--- /dev/null
+++ b/test/SemaCXX/warn-unused-parameters.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-parameter -verify %s
+template<typename T>
+struct X {
+ T f0(T x);
+ T f1(T x);
+ T f2(T);
+ template<typename U> U f3(U x);
+ template<typename U> U f4(U x);
+ template<typename U> U f5(U);
+};
+
+template<typename T> T X<T>::f0(T x) { return x; }
+template<typename T> T X<T>::f1(T) { return T(); }
+template<typename T> T X<T>::f2(T x) { return T(); } // expected-warning{{unused parameter 'x'}}
+template<typename T> template<typename U> U X<T>::f3(U x) { return x; }
+template<typename T> template<typename U> U X<T>::f4(U) { return U(); }
+template<typename T> template<typename U> U X<T>::f5(U x) { return U(); } // expected-warning{{unused parameter 'x'}}
+
+void test_X(X<int> &x, int i) {
+ x.f0(i);
+ x.f1(i);
+ x.f2(i);
+ x.f3(i);
+ x.f4(i);
+ x.f5(i);
+}
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index 3b5349a5ce1b..5ef7e7002f65 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -51,3 +51,11 @@ void test_dependent_init(T *p) {
X0<int> i(p);
(void)i;
}
+
+namespace PR6948 {
+ template<typename T> class X;
+
+ void f() {
+ X<char> str (read_from_file()); // expected-error{{use of undeclared identifier 'read_from_file'}}
+ }
+}
diff --git a/test/SemaCXX/warn-weak-vtables.cpp b/test/SemaCXX/warn-weak-vtables.cpp
index 1ea88a548e71..39333c108ae8 100644
--- a/test/SemaCXX/warn-weak-vtables.cpp
+++ b/test/SemaCXX/warn-weak-vtables.cpp
@@ -18,4 +18,4 @@ void f() {
struct A {
virtual void f() { }
};
-} \ No newline at end of file
+}
diff --git a/test/SemaObjC/argument-checking.m b/test/SemaObjC/argument-checking.m
index 3806a4c96530..9019a0fb24e4 100644
--- a/test/SemaObjC/argument-checking.m
+++ b/test/SemaObjC/argument-checking.m
@@ -2,24 +2,25 @@
struct S { int a; };
-extern int charStarFunc(char *);
-extern int charFunc(char);
+extern int charStarFunc(char *); // expected-note{{passing argument to parameter here}}
+extern int charFunc(char); // expected-note{{passing argument to parameter here}}
@interface Test
+alloc;
--(int)charStarMeth:(char *)s;
--structMeth:(struct S)s;
--structMeth:(struct S)s :(struct S)s2;
+-(int)charStarMeth:(char *)s; // expected-note{{passing argument to parameter 's' here}}
+-structMeth:(struct S)s; // expected-note{{passing argument to parameter 's' here}}
+-structMeth:(struct S)s
+ :(struct S)s2; // expected-note{{passing argument to parameter 's2' here}}
@end
void test() {
id obj = [Test alloc];
struct S sInst;
- charStarFunc(1); // expected-warning {{incompatible integer to pointer conversion passing 'int', expected 'char *'}}
- charFunc("abc"); // expected-warning {{incompatible pointer to integer conversion passing 'char [4]', expected 'char'}}
+ charStarFunc(1); // expected-warning {{incompatible integer to pointer conversion passing 'int' to parameter of type 'char *'}}
+ charFunc("abc"); // expected-warning {{incompatible pointer to integer conversion passing 'char [4]' to parameter of type 'char'}}
[obj charStarMeth:1]; // expected-warning {{incompatible integer to pointer conversion sending 'int'}}
- [obj structMeth:1]; // expected-error {{incompatible type sending 'int'}}
- [obj structMeth:sInst :1]; // expected-error {{incompatible type sending 'int'}}
+ [obj structMeth:1]; // expected-error {{sending 'int'}}
+ [obj structMeth:sInst :1]; // expected-error {{sending 'int'}}
}
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m
index b40f9b093585..402a658f3e35 100644
--- a/test/SemaObjC/block-type-safety.m
+++ b/test/SemaObjC/block-type-safety.m
@@ -4,7 +4,7 @@
@interface Super @end
@interface Sub : Super @end
-void f2(void(^f)(Super *)) {
+void f2(void(^f)(Super *)) { // expected-note{{passing argument to parameter 'f' here}}
Super *o;
f(o);
}
@@ -18,7 +18,7 @@ void r0(Super* (^f)()) {
Super *o = f();
}
-void r1(Sub* (^f)()) {
+void r1(Sub* (^f)()) { // expected-note{{passing argument to parameter 'f' here}}
Sub *o = f();
}
@@ -29,14 +29,14 @@ void r2 (id<NSObject> (^f) (void)) {
}
void test1() {
- f2(^(Sub *o) { }); // expected-error {{incompatible block pointer types passing 'void (^)(Sub *)', expected 'void (^)(Super *)'}}
+ f2(^(Sub *o) { }); // expected-error {{incompatible block pointer types passing}}
f3(^(Super *o) { }); // OK, block taking Super* may be called with a Sub*
r0(^Super* () { return 0; }); // OK
r0(^Sub* () { return 0; }); // OK, variable of type Super* gets return value of type Sub*
r0(^id () { return 0; });
- r1(^Super* () { return 0; }); // expected-error {{incompatible block pointer types passing 'Super *(^)(void)', expected 'Sub *(^)()'}}
+ r1(^Super* () { return 0; }); // expected-error {{incompatible block pointer types passing}}
r1(^Sub* () { return 0; }); // OK
r1(^id () { return 0; });
@@ -94,3 +94,13 @@ void test2(void)
}
@end
+@protocol P, P2;
+void f4(void (^f)(id<P> x)) { // expected-note{{passing argument to parameter 'f' here}}
+ NSArray<P2> *b;
+ f(b); // expected-warning {{passing 'NSArray<P2> *' to parameter of incompatible type 'id<P>'}}
+}
+
+void test3() {
+ f4(^(NSArray<P2>* a) { }); // expected-error {{incompatible block pointer types passing 'void (^)(NSArray<P2> *)' to parameter of type 'void (^)(id<P>)'}}
+}
+
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index ddac7d1759ec..15aa5811cc53 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -21,9 +21,9 @@ void foo4(id (^objectCreationBlock)(int)) {
return bar4(objectCreationBlock);
}
-void bar5(id(^)(void));
+void bar5(id(^)(void)); // expected-note{{passing argument to parameter here}}
void foo5(id (^objectCreationBlock)(int)) {
- return bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(int)', expected 'id (^)(void)'}}
+ return bar5(objectCreationBlock); // expected-error {{incompatible block pointer types passing 'id (^)(int)' to parameter of type 'id (^)(void)'}}
}
void bar6(id(^)(int));
@@ -39,10 +39,10 @@ void foo7(id (^x)(int)) {
@end
void foo8() {
- void *P = ^(itf x) {}; // expected-error {{Objective-C interface type 'itf' cannot be passed by value}}
- P = ^itf(int x) {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
- P = ^itf() {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
- P = ^itf{}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value}}
+ void *P = ^(itf x) {}; // expected-error {{Objective-C interface type 'itf' cannot be passed by value; did you forget * in 'itf'}}
+ P = ^itf(int x) {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
+ P = ^itf() {}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
+ P = ^itf{}; // expected-error {{Objective-C interface type 'itf' cannot be returned by value; did you forget * in 'itf'}}
}
diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m
index 9be853b81f8a..043314d4e182 100644
--- a/test/SemaObjC/call-super-2.m
+++ b/test/SemaObjC/call-super-2.m
@@ -69,7 +69,7 @@ id objc_getClass(const char *s);
- (int) instance_func1
{
int i = (size_t)[self instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id'))}}
- return i + (size_t)[super instance_func0]; // expected-warning {{method '-instance_func0' not found (return type defaults to 'id')}}
+ return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0')}}
}
- (int) instance_func2
{
diff --git a/test/SemaObjC/catch-stmt.m b/test/SemaObjC/catch-stmt.m
index 80c986ff5447..ef1da377094c 100644
--- a/test/SemaObjC/catch-stmt.m
+++ b/test/SemaObjC/catch-stmt.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -verify %s
-
+@interface A @end
@protocol P;
void f() {
@@ -8,6 +8,6 @@ void f() {
} @catch (int) { // expected-error{{@catch parameter is not a pointer to an interface type}}
} @catch (int *b) { // expected-error{{@catch parameter is not a pointer to an interface type}}
} @catch (id <P> c) { // expected-error{{illegal qualifiers on @catch parameter}}
- }
+ } @catch(A* a) { }
}
diff --git a/test/SemaObjC/class-bitfield.m b/test/SemaObjC/class-bitfield.m
index d1525622429e..c0393c2287c1 100644
--- a/test/SemaObjC/class-bitfield.m
+++ b/test/SemaObjC/class-bitfield.m
@@ -5,7 +5,7 @@
int a : -1; // expected-error{{bit-field 'a' has negative width}}
// rdar://6081627
- int b : 33; // expected-error{{size of bit-field 'b' exceeds size of its type (32 bits)}}
+ int b : 33; // expected-error{{size of bit-field 'b' (33 bits) exceeds size of its type (32 bits)}}
int c : (1 + 0.25); // expected-error{{expression is not an integer constant expression}}
int d : (int)(1 + 0.25);
diff --git a/test/SemaObjC/class-method-lookup.m b/test/SemaObjC/class-method-lookup.m
index f1269f2f4610..f26d692328a2 100644
--- a/test/SemaObjC/class-method-lookup.m
+++ b/test/SemaObjC/class-method-lookup.m
@@ -40,7 +40,7 @@
id foo(void) {
Object *obj;
id obj2 = obj;
- [obj setWindow:nil]; // expected-warning {{Object may not respond to 'setWindow:'}}
+ [obj setWindow:nil]; // expected-warning {{'Object' may not respond to 'setWindow:'}}
return obj;
}
diff --git a/test/SemaObjC/class-method-self.m b/test/SemaObjC/class-method-self.m
index 6f7d1fd93f4f..ba70644ebae8 100644
--- a/test/SemaObjC/class-method-self.m
+++ b/test/SemaObjC/class-method-self.m
@@ -3,7 +3,7 @@
typedef struct objc_class *Class;
@interface XX
-- (void)addObserver:(XX*)o;
+- (void)addObserver:(XX*)o; // expected-note 2{{passing argument to parameter 'o' here}}
@end
@@ -18,9 +18,9 @@ typedef struct objc_class *Class;
static XX *obj;
+ (void)classMethod {
- [obj addObserver:self]; // expected-warning {{incompatible pointer types sending 'Class', expected 'XX *'}}
+ [obj addObserver:self]; // expected-warning {{incompatible pointer types sending 'Class' to parameter of type 'XX *'}}
Class whatever;
- [obj addObserver:whatever]; // expected-warning {{incompatible pointer types sending 'Class', expected 'XX *'}}
+ [obj addObserver:whatever]; // expected-warning {{incompatible pointer types sending 'Class' to parameter of type 'XX *'}}
}
@end
diff --git a/test/SemaObjC/compatible-protocol-qualified-types.m b/test/SemaObjC/compatible-protocol-qualified-types.m
index 0df905c9ca15..0342622a11e1 100644
--- a/test/SemaObjC/compatible-protocol-qualified-types.m
+++ b/test/SemaObjC/compatible-protocol-qualified-types.m
@@ -44,7 +44,7 @@ extern NSString * const XCActiveSelectionLevel;
@interface NSTextStorage : NSObject
-- (void)setDelegate:(id <NSTextStorageDelegate>)delegate;
+- (void)setDelegate:(id <NSTextStorageDelegate>)delegate; // expected-note{{passing argument to parameter 'delegate' here}}
- (id <NSTextStorageDelegate>)delegate;
@end
@@ -69,7 +69,7 @@ extern NSString * const XCActiveSelectionLevel;
- (NSTextStorage *)contents {
- [_contents setDelegate:self]; // expected-warning {{incompatible type sending 'SKTText *', expected 'id<NSTextStorageDelegate>'}}
+ [_contents setDelegate:self]; // expected-warning {{sending 'SKTText *' to parameter of incompatible type 'id<NSTextStorageDelegate>'}}
return 0;
}
diff --git a/test/SemaObjC/compound-init.m b/test/SemaObjC/compound-init.m
new file mode 100644
index 000000000000..7b288bb3de2d
--- /dev/null
+++ b/test/SemaObjC/compound-init.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+@interface A
+@end
+
+void f() {
+ (A){ 0 }; // expected-error{{cannot initialize Objective-C class type 'A'}}
+}
diff --git a/test/SemaObjC/comptypes-1.m b/test/SemaObjC/comptypes-1.m
index 5b1891d4af2e..98107eef2157 100644
--- a/test/SemaObjC/comptypes-1.m
+++ b/test/SemaObjC/comptypes-1.m
@@ -34,25 +34,25 @@ int main()
/* Assigning to a 'MyClass *' variable should always generate a
warning, unless done from an 'id'. */
obj_c = obj; /* Ok */
- obj_c = obj_cp; // // expected-warning {{incompatible pointer types assigning 'MyOtherClass *', expected 'MyClass *'}}
- obj_c = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'MyClass *'}}
+ obj_c = obj_cp; // // expected-warning {{incompatible pointer types assigning to 'MyClass *' from 'MyOtherClass *'}}
+ obj_c = obj_C; // expected-warning {{incompatible pointer types assigning to 'MyClass *' from 'Class'}}
/* Assigning to an 'id<MyProtocol>' variable should generate a
warning if done from a 'MyClass *' (which doesn't implement
MyProtocol), but not from an 'id' or from a 'MyOtherClass *'
(which implements MyProtocol). */
obj_p = obj; /* Ok */
- obj_p = obj_c; // expected-warning {{incompatible type assigning 'MyClass *', expected 'id<MyProtocol>'}}
+ obj_p = obj_c; // expected-warning {{ assigning to 'id<MyProtocol>' from incompatible type 'MyClass *'}}
obj_p = obj_cp; /* Ok */
- obj_p = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'id<MyProtocol>'}}
+ obj_p = obj_C; // expected-warning {{incompatible pointer types assigning to 'id<MyProtocol>' from 'Class'}}
/* Assigning to a 'MyOtherClass *' variable should always generate
a warning, unless done from an 'id' or an 'id<MyProtocol>' (since
MyOtherClass implements MyProtocol). */
obj_cp = obj; /* Ok */
- obj_cp = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'MyOtherClass *'}}
+ obj_cp = obj_c; // expected-warning {{incompatible pointer types assigning to 'MyOtherClass *' from 'MyClass *'}}
obj_cp = obj_p; /* Ok */
- obj_cp = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'MyOtherClass *'}}
+ obj_cp = obj_C; // expected-warning {{incompatible pointer types assigning to 'MyOtherClass *' from 'Class'}}
/* Any comparison involving an 'id' must be without warnings. */
if (obj == obj_p) foo() ; /* Ok */ /*Bogus warning here in 2.95.4*/
diff --git a/test/SemaObjC/comptypes-3.m b/test/SemaObjC/comptypes-3.m
index 94171d11d568..6c1ce419b621 100644
--- a/test/SemaObjC/comptypes-3.m
+++ b/test/SemaObjC/comptypes-3.m
@@ -26,21 +26,21 @@ int main()
id<MyProtocolAB> obj_ab = nil;
id<MyProtocolAC> obj_ac = nil;
- obj_a = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolA>'}}
+ obj_a = obj_b; // expected-warning {{assigning to 'id<MyProtocolA>' from incompatible type 'id<MyProtocolB>'}}
obj_a = obj_ab; /* Ok */
obj_a = obj_ac; /* Ok */
- obj_b = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolB>'}}
+ obj_b = obj_a; // expected-warning {{assigning to 'id<MyProtocolB>' from incompatible type 'id<MyProtocolA>'}}
obj_b = obj_ab; /* Ok */
- obj_b = obj_ac; // expected-warning {{incompatible type assigning 'id<MyProtocolAC>', expected 'id<MyProtocolB>'}}
+ obj_b = obj_ac; // expected-warning {{assigning to 'id<MyProtocolB>' from incompatible type 'id<MyProtocolAC>'}}
- obj_ab = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolAB>'}}
- obj_ab = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolAB>'}}
- obj_ab = obj_ac; // expected-warning {{incompatible type assigning 'id<MyProtocolAC>', expected 'id<MyProtocolAB>'}}
+ obj_ab = obj_a; // expected-warning {{assigning to 'id<MyProtocolAB>' from incompatible type 'id<MyProtocolA>'}}
+ obj_ab = obj_b; // expected-warning {{assigning to 'id<MyProtocolAB>' from incompatible type 'id<MyProtocolB>'}}
+ obj_ab = obj_ac; // expected-warning {{assigning to 'id<MyProtocolAB>' from incompatible type 'id<MyProtocolAC>'}}
- obj_ac = obj_a; // expected-warning {{incompatible type assigning 'id<MyProtocolA>', expected 'id<MyProtocolAC>'}}
- obj_ac = obj_b; // expected-warning {{incompatible type assigning 'id<MyProtocolB>', expected 'id<MyProtocolAC>'}}
- obj_ac = obj_ab; // expected-warning {{incompatible type assigning 'id<MyProtocolAB>', expected 'id<MyProtocolAC>'}}
+ obj_ac = obj_a; // expected-warning {{assigning to 'id<MyProtocolAC>' from incompatible type 'id<MyProtocolA>'}}
+ obj_ac = obj_b; // expected-warning {{assigning to 'id<MyProtocolAC>' from incompatible type 'id<MyProtocolB>'}}
+ obj_ac = obj_ab; // expected-warning {{assigning to 'id<MyProtocolAC>' from incompatible type 'id<MyProtocolAB>'}}
if (obj_a == obj_b) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolA>' and 'id<MyProtocolB>')}}
if (obj_b == obj_a) foo (); // expected-warning {{comparison of distinct pointer types ('id<MyProtocolB>' and 'id<MyProtocolA>')}}
diff --git a/test/SemaObjC/comptypes-6.m b/test/SemaObjC/comptypes-6.m
index 2911a390ef84..98cf48879212 100644
--- a/test/SemaObjC/comptypes-6.m
+++ b/test/SemaObjC/comptypes-6.m
@@ -9,7 +9,7 @@ extern Object* foo(void);
static Derived *test(void)
{
- Derived *m = foo(); // expected-warning {{incompatible pointer types initializing 'Object *', expected 'Derived *'}}
+ Derived *m = foo(); // expected-warning {{incompatible pointer types initializing 'Derived *' with an expression of type 'Object *'}}
return m;
}
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index 2519c41c829a..df627e5300ad 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -24,27 +24,27 @@ int main()
/* These should all generate warnings. */
- obj = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'id'}}
- obj = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'id'}}
+ obj = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'id' from 'int'}}
+ obj = j; // expected-warning {{incompatible pointer types assigning to 'id' from 'int *'}}
- obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'id<MyProtocol>'}}
- obj_p = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'id<MyProtocol>'}}
+ obj_p = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'id<MyProtocol>' from 'int'}}
+ obj_p = j; // expected-warning {{ incompatible pointer types assigning to 'id<MyProtocol>' from 'int *'}}
- obj_c = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'MyClass *'}}
- obj_c = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'MyClass *'}}
+ obj_c = i; // expected-warning {{ incompatible integer to pointer conversion assigning to 'MyClass *' from 'int'}}
+ obj_c = j; // expected-warning {{incompatible pointer types assigning to 'MyClass *' from 'int *'}}
- obj_C = i; // expected-warning {{incompatible integer to pointer conversion assigning 'int', expected 'Class'}}
- obj_C = j; // expected-warning {{incompatible pointer types assigning 'int *', expected 'Class'}}
+ obj_C = i; // expected-warning {{incompatible integer to pointer conversion assigning to 'Class' from 'int'}}
+ obj_C = j; // expected-warning {{incompatible pointer types assigning to 'Class' from 'int *'}}
- i = obj; // expected-warning {{incompatible pointer to integer conversion assigning 'id', expected 'int'}}
- i = obj_p; // expected-warning {{incompatible pointer to integer conversion assigning 'id<MyProtocol>', expected 'int'}}
- i = obj_c; // expected-warning {{incompatible pointer to integer conversion assigning 'MyClass *', expected 'int'}}
- i = obj_C; // expected-warning {{incompatible pointer to integer conversion assigning 'Class', expected 'int'}}
+ i = obj; // expected-warning {{incompatible pointer to integer conversion assigning to 'int' from 'id'}}
+ i = obj_p; // expected-warning {{incompatible pointer to integer conversion assigning to 'int' from 'id<MyProtocol>'}}
+ i = obj_c; // expected-warning {{incompatible pointer to integer conversion assigning to 'int' from 'MyClass *'}}
+ i = obj_C; // expected-warning {{incompatible pointer to integer conversion assigning to 'int' from 'Class'}}
- j = obj; // expected-warning {{incompatible pointer types assigning 'id', expected 'int *'}}
- j = obj_p; // expected-warning {{incompatible pointer types assigning 'id<MyProtocol>', expected 'int *'}}
- j = obj_c; // expected-warning {{incompatible pointer types assigning 'MyClass *', expected 'int *'}}
- j = obj_C; // expected-warning {{incompatible pointer types assigning 'Class', expected 'int *'}}
+ j = obj; // expected-warning {{incompatible pointer types assigning to 'int *' from 'id'}}
+ j = obj_p; // expected-warning {{ incompatible pointer types assigning to 'int *' from 'id<MyProtocol>'}}
+ j = obj_c; // expected-warning {{incompatible pointer types assigning to 'int *' from 'MyClass *'}}
+ j = obj_C; // expected-warning {{incompatible pointer types assigning to 'int *' from 'Class'}}
if (obj == i) foo() ; // expected-warning {{comparison between pointer and integer ('id' and 'int')}}
if (i == obj) foo() ; // expected-warning {{comparison between pointer and integer ('int' and 'id')}}
diff --git a/test/SemaObjC/comptypes-legal.m b/test/SemaObjC/comptypes-legal.m
index 8caf18563b07..d83d559ee64c 100644
--- a/test/SemaObjC/comptypes-legal.m
+++ b/test/SemaObjC/comptypes-legal.m
@@ -26,12 +26,12 @@ NSObject *ExternFunc (NSObject *filePath, NSObject *key);
typedef id FuncSignature (NSObject *arg1, Derived *arg2);
@interface Derived: NSObject
-+ (void)registerFunc:(FuncSignature *)function;
++ (void)registerFunc:(FuncSignature *)function; // expected-note{{passing argument to parameter 'function' here}}
@end
void foo(void)
{
// GCC currently allows this (it has some fiarly new support for covariant return types and contravariant argument types).
// Since registerFunc: expects a Derived object as it's second argument, I don't know why this would be legal.
- [Derived registerFunc: ExternFunc]; // expected-warning{{incompatible pointer types sending 'NSObject *(NSObject *, NSObject *)', expected 'FuncSignature *'}}
+ [Derived registerFunc: ExternFunc]; // expected-warning{{incompatible pointer types sending 'NSObject *(NSObject *, NSObject *)' to parameter of type 'FuncSignature *'}}
}
diff --git a/test/SemaObjC/conditional-expr-2.m b/test/SemaObjC/conditional-expr-2.m
index e97b693dfc57..fdf3d1381a87 100644
--- a/test/SemaObjC/conditional-expr-2.m
+++ b/test/SemaObjC/conditional-expr-2.m
@@ -25,5 +25,5 @@ void foo (int i, NSKey *NSKeyValueCoding_NullValue, UpdatesList *nukedUpdatesLis
obj = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
key = i ? NSKeyValueCoding_NullValue : nukedUpdatesList; // expected-warning{{incompatible operand types ('NSKey *' and 'UpdatesList *')}}
key = i ? NSKeyValueCoding_NullValue : keysub;
- keysub = i ? NSKeyValueCoding_NullValue : keysub; // expected-warning{{incompatible pointer types assigning 'NSKey *', expected 'KeySub *'}}
+ keysub = i ? NSKeyValueCoding_NullValue : keysub; // expected-warning{{incompatible pointer types assigning to 'KeySub *' from 'NSKey *'}}
}
diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m
index 312f77a15ff4..3b5f609e4213 100644
--- a/test/SemaObjC/conditional-expr-3.m
+++ b/test/SemaObjC/conditional-expr-3.m
@@ -27,11 +27,11 @@ void f1(id x, A *a) {
}
void f2(id<P1> x) {
- id<P0> l = x; // expected-warning {{incompatible type initializing 'id<P1>', expected 'id<P0>'}}
+ id<P0> l = x; // expected-warning {{initializing 'id<P0>' with an expression of incompatible type 'id<P1>'}}
}
void f3(A *a) {
- id<P1> l = a; // expected-warning {{incompatible type initializing 'A *', expected 'id<P1>'}}
+ id<P1> l = a; // expected-warning {{ initializing 'id<P1>' with an expression of incompatible type 'A *'}}
}
void f4(int cond, id x, A *a) {
diff --git a/test/SemaObjC/conditional-expr-4.m b/test/SemaObjC/conditional-expr-4.m
index 84652e4513df..b3317f58061d 100644
--- a/test/SemaObjC/conditional-expr-4.m
+++ b/test/SemaObjC/conditional-expr-4.m
@@ -26,7 +26,7 @@ A *f1_a(int cond, A *a) {
}
void *f1_const_a(int x, void *p, const A * q) {
- void *r = x ? p : q; // expected-warning{{initializing 'void const *' discards qualifiers, expected 'void *'}}
+ void *r = x ? p : q; // expected-warning{{initializing 'void *' with an expression of type 'void const *' discards qualifiers}}
return r;
}
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index 1436f7ee0e00..74ab59bdb9ed 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -27,7 +27,7 @@
@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
- self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream2 *'}}
+ self = nextOutputStream; // expected-warning {{assigning to 'DTFilterOutputStream2 *' from incompatible type 'id<DTOutputStreams>'}}
return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream2 *')}}
}
@end
@@ -36,7 +36,7 @@
@implementation DTFilterOutputStream3 // expected-warning {{cannot find interface declaration for 'DTFilterOutputStream3'}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream]; // expected-warning {{method '-nextOutputStream' not found (return type defaults to 'id')}}
- self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream3 *'}}
+ self = nextOutputStream; // expected-warning {{assigning to 'DTFilterOutputStream3 *' from incompatible type 'id<DTOutputStreams>'}}
return nextOutputStream ? nextOutputStream : self; // expected-warning {{incompatible operand types ('id<DTOutputStreams>' and 'DTFilterOutputStream3 *')}}
}
@end
diff --git a/test/SemaObjC/continuation-class-err.m b/test/SemaObjC/continuation-class-err.m
index 214c4e5b30b5..252518239f16 100644
--- a/test/SemaObjC/continuation-class-err.m
+++ b/test/SemaObjC/continuation-class-err.m
@@ -12,7 +12,7 @@
@interface ReadOnly ()
@property(readwrite, copy) id object; // expected-warning {{property attribute in continuation class does not match the primary class}}
-@property(readonly) id object1; // expected-error {{property declaration in continuation class of 'ReadOnly' is to change a 'readonly' property to 'readwrite'}}
+@property(readonly) id object1; // expected-error {{illegal declaration of property in continuation class 'ReadOnly': attribute must be}}
@property (readwrite, assign) int indentLevel; // OK. assign the the default in any case.
@end
@@ -31,8 +31,8 @@
@end
@interface Bar ()
-@property (copy) id foo; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}}
-@property (copy) id fee; // expected-error {{property declaration in continuation class of 'Bar' is to change a 'readonly' property to 'readwrite'}}
+@property (copy) id foo; // expected-error {{illegal declaration of property in continuation class 'Bar': attribute must be}}
+@property (copy) id fee; // expected-error {{illegal declaration of property in continuation class 'Bar': attribute must be}}
@end
@implementation Bar
diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m
index 45a3710dcf5b..283ad260a94e 100644
--- a/test/SemaObjC/default-synthesize.m
+++ b/test/SemaObjC/default-synthesize.m
@@ -79,3 +79,27 @@
}
@end
+@protocol TopProtocol
+ @property (readonly) id myString;
+@end
+
+@interface TopClass <TopProtocol>
+{
+ id myString;
+}
+@end
+
+@interface SubClass : TopClass <TopProtocol>
+@end
+
+@implementation SubClass @end
+
+// rdar: // 7920807
+@interface C @end
+@interface C (Category)
+@property int p; // expected-warning {{property 'p' requires method 'p' to be defined }} \
+ // expected-warning {{property 'p' requires method 'setP:' to be defined}}
+@end
+@implementation C (Category) // expected-note 2 {{implementation is here}}
+@end
+
diff --git a/test/SemaObjC/ibaction.m b/test/SemaObjC/ibaction.m
new file mode 100644
index 000000000000..b97e002833c9
--- /dev/null
+++ b/test/SemaObjC/ibaction.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -verify
+
+@interface Foo
+{
+ __attribute__((iboutlet)) id myoutlet;
+}
+- (void) __attribute__((ibaction)) myMessage:(id)msg;
+@end
+
+@implementation Foo
+// Normally attributes should not be attached to method definitions, but
+// we allow 'ibaction' to be attached because it can be expanded from
+// the IBAction macro.
+- (void) __attribute__((ibaction)) myMessage:(id)msg {} // no-warning
+@end
diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m
index 206127a5ccef..27b84dedf8e6 100644
--- a/test/SemaObjC/id.m
+++ b/test/SemaObjC/id.m
@@ -9,8 +9,8 @@ void foo() {
// Test assignment compatibility of Class and id. No warning should be
// produced.
// rdar://6770142 - Class and id<foo> are compatible.
- S = T; // expected-warning {{incompatible pointer types assigning 'Class', expected 'id<Foo>'}}
- T = S; // expected-warning {{incompatible pointer types assigning 'id<Foo>', expected 'Class'}}
+ S = T; // expected-warning {{incompatible pointer types assigning to 'id<Foo>' from 'Class'}}
+ T = S; // expected-warning {{incompatible pointer types assigning to 'Class' from 'id<Foo>'}}
R = T; T = R;
R = S; S = R;
}
diff --git a/test/SemaObjC/incompatible-protocol-qualified-types.m b/test/SemaObjC/incompatible-protocol-qualified-types.m
index 7eb540ad556e..494d23e8b267 100644
--- a/test/SemaObjC/incompatible-protocol-qualified-types.m
+++ b/test/SemaObjC/incompatible-protocol-qualified-types.m
@@ -8,7 +8,7 @@
@interface INTF @end
-INTF <MyProto1> * Func(INTF <MyProto1, MyProto2> *p2)
+INTF <MyProto1> * Func(INTF <MyProto1, MyProto2> *p2) // expected-note{{passing argument to parameter 'p2' here}}
{
return p2;
}
@@ -21,15 +21,15 @@ INTF <MyProto1> * Func1(INTF <MyProto1, MyProto2> *p2)
INTF <MyProto1, MyProto2> * Func2(INTF <MyProto1> *p2)
{
- Func(p2); // expected-warning {{incompatible pointer types passing 'INTF<MyProto1> *', expected 'INTF<MyProto1,MyProto2> *}}
- return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto1> *', expected 'INTF<MyProto1,MyProto2> *}}
+ Func(p2); // expected-warning {{incompatible pointer types passing 'INTF<MyProto1> *' to parameter of type 'INTF<MyProto1,MyProto2> *'}}
+ return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto1> *' from a function with result type 'INTF<MyProto1,MyProto2> *'}}
}
INTF <MyProto1> * Func3(INTF <MyProto2> *p2)
{
- return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto2> *', expected 'INTF<MyProto1> *}}
+ return p2; // expected-warning {{incompatible pointer types returning 'INTF<MyProto2> *' from a function with result type 'INTF<MyProto1> *'}}
}
diff --git a/test/SemaObjC/invalid-code.m b/test/SemaObjC/invalid-code.m
index 2f297cf6e659..7a642fb10784 100644
--- a/test/SemaObjC/invalid-code.m
+++ b/test/SemaObjC/invalid-code.m
@@ -12,3 +12,10 @@ void test1() {
__PRETTY_FUNCTION__; // expected-warning{{expression result unused}}
}
@end
+
+// <rdar://problem/7881045>
+// This previously triggered a crash because a ';' was expected after the @throw statement.
+void foo() {
+ @throw (id)0 // expected-error{{expected ';' after @throw}}
+}
+
diff --git a/test/SemaObjC/invalid-objc-decls-1.m b/test/SemaObjC/invalid-objc-decls-1.m
index 2f3be285df3f..91bd8a8c8698 100644
--- a/test/SemaObjC/invalid-objc-decls-1.m
+++ b/test/SemaObjC/invalid-objc-decls-1.m
@@ -27,8 +27,8 @@ struct whatever {
}
@end
-Super foo( // expected-error{{interface interface type 'Super' cannot be returned by value}}
- Super parm1) { // expected-error{{interface interface type 'Super' cannot be passed by value}}
+Super foo( // expected-error{{interface interface type 'Super' cannot be returned by value; did you forget * in 'Super'}}
+ Super parm1) { // expected-error{{interface interface type 'Super' cannot be passed by value; did you forget * in 'Super'}}
Super p1; // expected-error{{interface type cannot be statically allocated}}
return p1;
}
diff --git a/test/SemaObjC/invalid-receiver.m b/test/SemaObjC/invalid-receiver.m
index 16f0155173d0..1174dd2e1706 100644
--- a/test/SemaObjC/invalid-receiver.m
+++ b/test/SemaObjC/invalid-receiver.m
@@ -5,5 +5,5 @@ typedef struct NotAClass {
} NotAClass;
void foo() {
- [NotAClass nonexistent_method]; // expected-error {{invalid receiver to message expression}}
+ [NotAClass nonexistent_method]; // expected-error {{receiver type 'NotAClass' (aka 'struct NotAClass') is not an Objective-C class}}
}
diff --git a/test/SemaObjC/ivar-in-class-extension-error.m b/test/SemaObjC/ivar-in-class-extension-error.m
index ffc0e8b83902..6e0b577976d6 100644
--- a/test/SemaObjC/ivar-in-class-extension-error.m
+++ b/test/SemaObjC/ivar-in-class-extension-error.m
@@ -3,13 +3,13 @@
@interface A @end
-@interface A () { // expected-error {{ivars may not be placed in class extension}}
- int _p0;
+@interface A () {
+ int _p0; // expected-error {{ivars may not be placed in class extension}}
}
@property int p0;
@end
-@interface A(CAT) { // expected-error {{ivars may not be placed in categories}}
- int _p1;
+@interface A(CAT) {
+ int _p1; // expected-error {{ivars may not be placed in categories}}
}
@end
diff --git a/test/SemaObjC/ivar-in-class-extension.m b/test/SemaObjC/ivar-in-class-extension.m
index e1a649cd4784..4130d8f96252 100644
--- a/test/SemaObjC/ivar-in-class-extension.m
+++ b/test/SemaObjC/ivar-in-class-extension.m
@@ -31,12 +31,12 @@ int fn3(SomeClass *obj) {
@end
@interface SomeClass (Category)
- { // expected-error {{ivars may not be placed in categories}}
- int categoryIvar;
+ {
+ int categoryIvar; // expected-error {{ivars may not be placed in categories}}
}
@end
@interface SomeClass (Category1)
- { // expected-error {{ivars may not be placed in categories}}
+ {
}
@end
diff --git a/test/SemaObjC/ivar-lookup.m b/test/SemaObjC/ivar-lookup.m
index 644b3b638c92..06e47116f73c 100644
--- a/test/SemaObjC/ivar-lookup.m
+++ b/test/SemaObjC/ivar-lookup.m
@@ -16,3 +16,22 @@ extern struct foo x;
}
@end
+
+@interface Ivar
+- (float*)method;
+@end
+
+@interface A {
+ A *Ivar;
+}
+- (int*)method;
+@end
+
+@implementation A
+- (int*)method {
+ int *ip = [Ivar method]; // expected-warning{{warning: incompatible pointer types initializing 'int *' with an expression of type 'float *'}}
+ // Note that there is no warning in Objective-C++
+ return 0;
+}
+@end
+
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index 57b109796257..fed3961ce111 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -87,7 +87,7 @@ struct S { int X; } S;
int test5(int X) {
int a = [X somemsg]; // expected-warning {{receiver type 'int' is not 'id'}} \
expected-warning {{method '-somemsg' not found}} \
- expected-warning {{incompatible pointer to integer conversion initializing 'id', expected 'int'}}
+ expected-warning {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'id'}}
int b = [S somemsg]; // expected-error {{bad receiver type 'struct S'}}
}
diff --git a/test/SemaObjC/method-arg-qualifier-warning.m b/test/SemaObjC/method-arg-qualifier-warning.m
index 397f24135f58..463fb7fd777a 100644
--- a/test/SemaObjC/method-arg-qualifier-warning.m
+++ b/test/SemaObjC/method-arg-qualifier-warning.m
@@ -3,7 +3,7 @@
typedef signed char BOOL;
@interface NSString
-- (BOOL)isEqualToString:(NSString *)aString;
+- (BOOL)isEqualToString:(NSString *)aString; // expected-note 2{{passing argument to parameter 'aString' here}}
@end
static const NSString * Identifier1 = @"Identifier1";
@@ -12,8 +12,8 @@ static NSString * const Identifier3 = @"Identifier3";
int main () {
- [@"Identifier1" isEqualToString:Identifier1]; // expected-warning {{sending 'NSString const *' discards qualifiers, expected 'NSString *'}}
- [@"Identifier2" isEqualToString:Identifier2]; // expected-warning {{sending 'NSString const *' discards qualifiers, expected 'NSString *'}}
+ [@"Identifier1" isEqualToString:Identifier1]; // expected-warning {{sending 'NSString const *' to parameter of type 'NSString *' discards qualifiers}}
+ [@"Identifier2" isEqualToString:Identifier2]; // expected-warning {{sending 'NSString const *' to parameter of type 'NSString *' discards qualifiers}}
[@"Identifier3" isEqualToString:Identifier3];
return 0;
}
diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m
index c1509bf9f6f2..324ed342f918 100644
--- a/test/SemaObjC/method-bad-param.m
+++ b/test/SemaObjC/method-bad-param.m
@@ -7,21 +7,21 @@
@end
@interface bar
--(void) my_method:(foo) my_param; // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
-- (foo)cccccc:(long)ddddd; // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+-(void) my_method:(foo) my_param; // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
+- (foo)cccccc:(long)ddddd; // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
@end
@implementation bar
--(void) my_method:(foo) my_param // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
+-(void) my_method:(foo) my_param // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
{
}
-- (foo)cccccc:(long)ddddd // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+- (foo)cccccc:(long)ddddd // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
{
}
@end
-void somefunc(foo x) {} // expected-error {{Objective-C interface type 'foo' cannot be passed by value}}
-foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot be returned by value}}
+void somefunc(foo x) {} // expected-error {{Objective-C interface type 'foo' cannot be passed by value; did you forget * in 'foo'}}
+foo somefunc2() {} // expected-error {{Objective-C interface type 'foo' cannot be returned by value; did you forget * in 'foo'}}
// rdar://6780761
void f0(foo *a0) {
diff --git a/test/SemaObjC/objc-cstyle-args-in-methods.m b/test/SemaObjC/objc-cstyle-args-in-methods.m
new file mode 100644
index 000000000000..9f752959e95b
--- /dev/null
+++ b/test/SemaObjC/objc-cstyle-args-in-methods.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface Foo
+- (id)test:(id)one, id two;
+- (id)bad:(id)one, id two, double three;
+@end
+
+@implementation Foo
+- (id)test:(id )one, id two {return two; }
+- (id)bad:(id)one, id two, double three { return two; }
+@end
+
+
+int main() {
+ Foo *foo;
+ [foo test:@"One", @"Two"];
+ [foo bad:@"One", @"Two"]; // expected-error {{too few arguments to method call}}
+ [foo bad:@"One", @"Two", 3.14];
+ [foo bad:@"One", @"Two", 3.14, @"Two"]; // expected-error {{too many arguments to method call}}
+}
diff --git a/test/SemaObjC/pedantic-dynamic-test.m b/test/SemaObjC/pedantic-dynamic-test.m
new file mode 100644
index 000000000000..9b14c1d75f39
--- /dev/null
+++ b/test/SemaObjC/pedantic-dynamic-test.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// rdar: // 7860960
+
+@interface I
+{
+ int window;
+}
+@property int window, noWarningNeeded;
+@end
+
+@implementation I
+
+@synthesize window;
+
+@dynamic noWarningNeeded;
+@end
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
index d527a9c9f30b..669f9c0e4bd0 100644
--- a/test/SemaObjC/property-9.m
+++ b/test/SemaObjC/property-9.m
@@ -43,9 +43,9 @@ typedef signed char BOOL;
int _awesome;
}
-@property (readonly) int; // expected-error {{declaration does not declare anything}}
+@property (readonly) int; // expected-warning {{declaration does not declare anything}}
@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \
- expected-error {{declaration does not declare anything}}
+ expected-warning {{declaration does not declare anything}}
@property (readonly) int : 4; // expected-error {{property requires fields to be named}}
diff --git a/test/SemaObjC/property-typecheck-1.m b/test/SemaObjC/property-typecheck-1.m
index fc53b590b8b2..f86e04779991 100644
--- a/test/SemaObjC/property-typecheck-1.m
+++ b/test/SemaObjC/property-typecheck-1.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface A
--(float) x; // expected-note {{declared at}}
+-(float) x; // expected-note {{declared here}}
@property int x; // expected-warning {{type of property 'x' does not match type of accessor 'x'}}
@end
@@ -38,7 +38,7 @@ typedef void (F)(void);
@class SSyncSet_iDisk;
@interface SPeer_iDisk_remote1 : SPeer
-- (SSyncSet_iDisk*) syncSet; // expected-note {{declared at}}
+- (SSyncSet_iDisk*) syncSet; // expected-note {{declared here}}
@end
@interface SPeer_iDisk_local
@@ -76,7 +76,7 @@ typedef void (F)(void);
@property (readonly) NSArray* pieces; // expected-warning {{type of property 'pieces' does not match type of accessor 'pieces'}}
@property (readonly) NSMutableArray* first;
-- (NSMutableArray*) pieces; // expected-note {{declared at}} // expected-note {{declared at}}
+- (NSMutableArray*) pieces; // expected-note {{declared here}} // expected-note {{declared here}}
- (NSArray*) first;
@end
diff --git a/test/SemaObjC/protocol-id-test-3.m b/test/SemaObjC/protocol-id-test-3.m
index 3538b0e05e37..624bab0c223a 100644
--- a/test/SemaObjC/protocol-id-test-3.m
+++ b/test/SemaObjC/protocol-id-test-3.m
@@ -8,7 +8,7 @@
@interface INTF @end
-id<MyProto1> Func(INTF <MyProto1, MyProto2> *p2)
+id<MyProto1> Func(INTF <MyProto1, MyProto2> *p2) // expected-note 2{{passing argument to parameter 'p2' here}}
{
return p2;
}
@@ -29,15 +29,15 @@ id<MyProto1> Func(INTF <MyProto1, MyProto2> *p2)
id<MyProto1, MyProto2> Gunc2(id <MyProto1>p2)
{
- Func(p2); // expected-warning {{incompatible type passing 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
- return p2; // expected-warning {{incompatible type returning 'id<MyProto1>', expected 'id<MyProto1,MyProto2>'}}
+ Func(p2); // expected-warning {{passing 'id<MyProto1>' to parameter of incompatible type 'INTF<MyProto1,MyProto2> *'}}
+ return p2; // expected-warning {{returning 'id<MyProto1>' from a function with incompatible result type 'id<MyProto1,MyProto2>'}}
}
id<MyProto1> Gunc3(id <MyProto2>p2)
{
- return p2; // expected-warning {{incompatible type returning 'id<MyProto2>', expected 'id<MyProto1>'}}
+ return p2; // expected-warning {{returning 'id<MyProto2>' from a function with incompatible result type 'id<MyProto1>'}}
}
@@ -61,13 +61,13 @@ INTF<MyProto1> * Hunc1(id <MyProto1, MyProto2>p2)
INTF<MyProto1, MyProto2> * Hunc2(id <MyProto1>p2)
{
- Func(p2); // expected-warning {{incompatible type passing 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
- return p2; // expected-warning {{incompatible type returning 'id<MyProto1>', expected 'INTF<MyProto1,MyProto2> *'}}
+ Func(p2); // expected-warning {{passing 'id<MyProto1>' to parameter of incompatible type 'INTF<MyProto1,MyProto2> *'}}
+ return p2; // expected-warning {{returning 'id<MyProto1>' from a function with incompatible result type 'INTF<MyProto1,MyProto2> *'}}
}
INTF<MyProto1> * Hunc3(id <MyProto2>p2)
{
- return p2; // expected-warning {{incompatible type returning 'id<MyProto2>', expected 'INTF<MyProto1> *'}}
+ return p2; // expected-warning {{returning 'id<MyProto2>' from a function with incompatible result type 'INTF<MyProto1> *'}}
}
diff --git a/test/SemaObjC/protocol-typecheck.m b/test/SemaObjC/protocol-typecheck.m
index d9cde87d4c2c..4eb1b2641af2 100644
--- a/test/SemaObjC/protocol-typecheck.m
+++ b/test/SemaObjC/protocol-typecheck.m
@@ -9,7 +9,7 @@
@interface XX
- (void)setFlexElement:(NSObject <PWhatever, XCElementP> *)flexer;
-- (void)setFlexElement2:(NSObject <PWhatever, XCElementSpacerP> *)flexer;
+- (void)setFlexElement2:(NSObject <PWhatever, XCElementSpacerP> *)flexer; // expected-note{{passing argument to parameter 'flexer' here}}
@end
@@ -20,6 +20,6 @@ void func() {
[obj setFlexElement:flexer];
// FIXME: GCC provides the following diagnostic (which is much better):
// protocol-typecheck.m:21: warning: class 'NSObject <PWhatever, XCElementP>' does not implement the 'XCElementSpacerP' protocol
- [obj setFlexElement2:flexer2]; // expected-warning{{incompatible pointer types sending 'NSObject<PWhatever,XCElementP> *', expected 'NSObject<PWhatever,XCElementSpacerP> *'}}
+ [obj setFlexElement2:flexer2]; // expected-warning{{incompatible pointer types sending 'NSObject<PWhatever,XCElementP> *' to parameter of type 'NSObject<PWhatever,XCElementSpacerP> *'}}
}
diff --git a/test/SemaObjC/protocol-warn.m b/test/SemaObjC/protocol-warn.m
index d0c51e3ffabe..2d042380582e 100644
--- a/test/SemaObjC/protocol-warn.m
+++ b/test/SemaObjC/protocol-warn.m
@@ -51,5 +51,5 @@ UIWebPDFView *getView()
{
UIWebBrowserView *browserView;
UIWebPDFView *pdfView;
- return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView<NSObject> *', expected 'UIWebPDFView *'}}
+ return pdfView ? pdfView : browserView; // expected-warning {{incompatible pointer types returning 'UIView<NSObject> *' from a function with result type 'UIWebPDFView *'}}
}
diff --git a/test/SemaObjC/stmts.m b/test/SemaObjC/stmts.m
index 20a9f55b2095..d1e2ad3612e0 100644
--- a/test/SemaObjC/stmts.m
+++ b/test/SemaObjC/stmts.m
@@ -2,12 +2,16 @@
struct some_struct;
+@interface NSObject
+@end
+
// Note: NSException is not declared.
void f0(id x) {
@try {
} @catch (NSException *x) { // expected-error {{unknown type name 'NSException'}}
} @catch (struct some_struct x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
} @catch (int x) { // expected-error {{@catch parameter is not a pointer to an interface type}}
+ } @catch (static NSObject *y) { // expected-error {{@catch parameter cannot have storage specifier 'static'}}
} @catch (...) {
}
}
diff --git a/test/SemaObjC/super-class-protocol-conformance.m b/test/SemaObjC/super-class-protocol-conformance.m
new file mode 100644
index 000000000000..ac8bc70a9989
--- /dev/null
+++ b/test/SemaObjC/super-class-protocol-conformance.m
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar: // 7884086
+
+@interface NSObject @end
+
+@protocol TopProtocol
+ @property (readonly) id myString; // expected-warning {{property 'myString' requires method 'myString' to be defined}}
+@end
+
+@protocol SubProtocol <TopProtocol>
+@end
+
+@interface TopClass : NSObject <TopProtocol> {}
+@end
+
+@interface SubClass : TopClass <SubProtocol> {}
+@end
+
+@interface SubClass1 : TopClass {}
+@end
+
+@implementation SubClass1 @end // Test1 - No Warning
+
+@implementation TopClass // expected-note {{implementation is here}}
+@end
+
+@implementation SubClass // Test3 - No Warning
+@end
+
+@interface SubClass2 : TopClass<TopProtocol>
+@end
+
+@implementation SubClass2 @end // Test 4 - No Warning
+
+@interface SubClass3 : TopClass<SubProtocol> @end
+@implementation SubClass3 @end // Test 5 - No Warning
+
+@interface SubClass4 : SubClass3 @end
+@implementation SubClass4 @end // Test 5 - No Warning
+
+@protocol NewProtocol
+ @property (readonly) id myNewString; // expected-warning {{property 'myNewString' requires method 'myNewString' to be defined}}
+@end
+
+@interface SubClass5 : SubClass4 <NewProtocol> @end
+@implementation SubClass5 @end // expected-note {{implementation is here}}
+
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
index a61d72fda5ac..31d8db170254 100644
--- a/test/SemaObjC/super.m
+++ b/test/SemaObjC/super.m
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s
+
+void takevoidptr(void*);
+
@interface Foo
- iMethod;
@@ -6,6 +9,8 @@
@end
@interface A
++ superClassMethod;
+- (void)instanceMethod;
@end
@interface B : A
@@ -16,11 +21,24 @@
@implementation B
- (void)instanceMethod {
- [super iMethod]; // expected-warning{{method '-iMethod' not found (return type defaults to 'id')}}
+ [super iMethod]; // expected-warning{{'A' may not respond to 'iMethod')}}
+
+ // Use of super in a block is ok and does codegen to the right thing.
+ // rdar://7852959
+ takevoidptr(^{
+ [super instanceMethod];
+ });
}
+ classMethod {
[super cMethod]; // expected-warning{{method '+cMethod' not found (return type defaults to 'id')}}
+
+ id X[] = { [ super superClassMethod] };
+ id Y[] = {
+ [ super.superClassMethod iMethod],
+ super.superClassMethod,
+ (id)super.superClassMethod // not a cast of super: rdar://7853261
+ };
return 0;
}
@end
@@ -36,13 +54,34 @@ void f0(int super) {
[super m]; // expected-warning{{receiver type 'int' is not 'id'}} \
expected-warning {{method '-m' not found (return type defaults to 'id')}}
}
-void f1(int puper) {
- [super m]; // expected-error{{use of undeclared identifier 'super'}}
+void f1(id puper) { // expected-note {{'puper' declared here}}
+ [super m]; // expected-error{{use of undeclared identifier 'super'; did you mean 'puper'?}}
}
// radar 7400691
typedef Foo super;
+typedef Foo FooTD;
+
void test() {
+ [FooTD cMethod];
[super cMethod];
}
+
+struct SomeStruct {
+ int X;
+};
+
+int test2() {
+ struct SomeStruct super = { 0 };
+ return super.X;
+}
+
+int test3() {
+ id super = 0;
+ [(B*)super instanceMethod];
+ int *s1 = (int*)super;
+
+ id X[] = { [ super superClassMethod] };
+ return 0;
+}
diff --git a/test/SemaObjC/synthesized-ivar.m b/test/SemaObjC/synthesized-ivar.m
index 465caf24a736..58bcf40a5860 100644
--- a/test/SemaObjC/synthesized-ivar.m
+++ b/test/SemaObjC/synthesized-ivar.m
@@ -11,3 +11,6 @@
return IP;
}
@end
+
+// rdar: // 7823675
+int f0(I *a) { return a->IP; } // expected-error {{instance variable 'IP' is protected}}
diff --git a/test/SemaObjC/transparent-union.m b/test/SemaObjC/transparent-union.m
new file mode 100644
index 000000000000..cb03dfec3563
--- /dev/null
+++ b/test/SemaObjC/transparent-union.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef union {
+ struct xx_object_s *_do;
+ struct xx_continuation_s *_dc;
+ struct xx_queue_s *_dq;
+ struct xx_queue_attr_s *_dqa;
+ struct xx_group_s *_dg;
+ struct xx_source_s *_ds;
+ struct xx_source_attr_s *_dsa;
+ struct xx_semaphore_s *_dsema;
+} xx_object_t __attribute__((transparent_union));
+
+@interface INTF
+- (void) doSomething : (xx_object_t) xxObject;
+- (void)testMeth;
+@end
+
+@implementation INTF
+- (void) doSomething : (xx_object_t) xxObject {}
+- (void)testMeth { struct xx_queue_s *sq; [self doSomething:sq ]; }
+@end
diff --git a/test/SemaObjC/unused.m b/test/SemaObjC/unused.m
index a33a1bc02f9d..1ecf32295eae 100644
--- a/test/SemaObjC/unused.m
+++ b/test/SemaObjC/unused.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -Wunused -fsyntax-only
+// RUN: %clang_cc1 %s -verify -Wunused -Wunused-parameter -fsyntax-only
int printf(const char *, ...);
@@ -21,7 +21,7 @@ int test1(void) {
@end
void test2() {
- @"pointless example call for test purposes".length; // expected-warning {{property access result unused - getters should not have side effects}}
+ @"pointless example call for test purposes".length; // expected-warning {{property access result unused - getters should not be used for side effects}}
}
@interface foo
diff --git a/test/SemaObjC/warn-incompatible-builtin-types.m b/test/SemaObjC/warn-incompatible-builtin-types.m
index 2a5005a39607..79c8cea66545 100644
--- a/test/SemaObjC/warn-incompatible-builtin-types.m
+++ b/test/SemaObjC/warn-incompatible-builtin-types.m
@@ -2,7 +2,7 @@
// rdar 7634850
@interface Foo
-- (void)foo:(Class)class;
+- (void)foo:(Class)class; // expected-note{{passing argument to parameter 'class' here}}
@end
void FUNC() {
@@ -10,8 +10,8 @@ void FUNC() {
SEL s1, s2;
id i, i1;
Foo *f;
- [f foo:f]; // expected-warning {{incompatible pointer types sending 'Foo *', expected 'Class'}}
- c = f; // expected-warning {{incompatible pointer types assigning 'Foo *', expected 'Class'}}
+ [f foo:f]; // expected-warning {{incompatible pointer types sending 'Foo *' to parameter of type 'Class'}}
+ c = f; // expected-warning {{incompatible pointer types assigning to 'Class' from 'Foo *'}}
c = i;
@@ -21,22 +21,22 @@ void FUNC() {
i = i1;
- s1 = i; // expected-warning {{incompatible pointer types assigning 'id', expected 'SEL'}}
- i = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'id'}}
+ s1 = i; // expected-warning {{incompatible pointer types assigning to 'SEL' from 'id'}}
+ i = s1; // expected-warning {{incompatible pointer types assigning to 'id' from 'SEL'}}
s1 = s2;
- s1 = c; // expected-warning {{incompatible pointer types assigning 'Class', expected 'SEL'}}
+ s1 = c; // expected-warning {{incompatible pointer types assigning to 'SEL' from 'Class'}}
- c = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'Class'}}
+ c = s1; // expected-warning {{incompatible pointer types assigning to 'Class' from 'SEL'}}
f = i;
- f = c; // expected-warning {{incompatible pointer types assigning 'Class', expected 'Foo *'}}
+ f = c; // expected-warning {{incompatible pointer types assigning to 'Foo *' from 'Class'}}
- f = s1; // expected-warning {{incompatible pointer types assigning 'SEL', expected 'Foo *'}}
+ f = s1; // expected-warning {{incompatible pointer types assigning to 'Foo *' from 'SEL'}}
i = f;
- s1 = f; // expected-warning {{incompatible pointer types assigning 'Foo *', expected 'SEL'}}
+ s1 = f; // expected-warning {{incompatible pointer types assigning to 'SEL' from 'Foo *'}}
}
diff --git a/test/SemaObjC/warn-selector-selection.m b/test/SemaObjC/warn-selector-selection.m
index 96ed77c14bef..e395f43464ed 100644
--- a/test/SemaObjC/warn-selector-selection.m
+++ b/test/SemaObjC/warn-selector-selection.m
@@ -10,5 +10,5 @@
void foo(void) {
Object *obj;
- [obj setWindow:0]; // expected-warning{{Object may not respond to 'setWindow:'}}
+ [obj setWindow:0]; // expected-warning{{'Object' may not respond to 'setWindow:'}}
}
diff --git a/test/SemaObjC/warn-superclass-method-mismatch.m b/test/SemaObjC/warn-superclass-method-mismatch.m
index a4005ad2b293..52054739d53e 100644
--- a/test/SemaObjC/warn-superclass-method-mismatch.m
+++ b/test/SemaObjC/warn-superclass-method-mismatch.m
@@ -9,7 +9,7 @@
@interface Base : Root
-(void) method: (int*) x; // expected-note {{previous declaration is here}}
-(void) method1: (Base*) x; // expected-note {{previous declaration is here}}
--(void) method2: (Sub*) x;
+-(void) method2: (Sub*) x; // expected-note{{passing argument to parameter 'x' here}}
+ method3: (int)x1 : (Base *)x2 : (float)x3; // expected-note {{previous declaration is here}}
+ mathod4: (id)x1;
- method5: (int) x : (double) d; // expected-note {{previous declaration is here}}
diff --git a/test/SemaObjC/warn-unused-exception-param.m b/test/SemaObjC/warn-unused-exception-param.m
new file mode 100644
index 000000000000..f649f8c81219
--- /dev/null
+++ b/test/SemaObjC/warn-unused-exception-param.m
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-exception-parameter %s
+void f0() {
+ @try {} @catch(id a) {} // expected-warning{{unused exception parameter 'a'}}
+}
diff --git a/test/SemaObjC/warn-write-strings.m b/test/SemaObjC/warn-write-strings.m
index 938f0be7721f..04af00ca2d83 100644
--- a/test/SemaObjC/warn-write-strings.m
+++ b/test/SemaObjC/warn-write-strings.m
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
// PR4804
-char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}}
+char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'char const [4]' discards qualifiers}}
diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm
index 72de17133617..fd0df4e6e225 100644
--- a/test/SemaObjCXX/blocks.mm
+++ b/test/SemaObjCXX/blocks.mm
@@ -3,12 +3,12 @@
void bar(id(^)(void));
void foo(id <NSObject>(^objectCreationBlock)(void)) {
- return bar(objectCreationBlock); // expected-warning{{incompatible pointer types converting 'id (^)()', expected 'id<NSObject> (^)()'}}
+ return bar(objectCreationBlock); // expected-warning{{incompatible pointer types converting 'id<NSObject> (^)()' to type 'id (^)()'}}
}
void bar2(id(*)(void));
void foo2(id <NSObject>(*objectCreationBlock)(void)) {
- return bar2(objectCreationBlock); // expected-warning{{incompatible pointer types converting 'id (*)()', expected 'id<NSObject> (*)()'}}
+ return bar2(objectCreationBlock); // expected-warning{{incompatible pointer types converting 'id<NSObject> (*)()' to type 'id (*)()'}}
}
void bar3(id(*)()); // expected-note{{candidate function}}
diff --git a/test/SemaObjCXX/instantiate-expr.mm b/test/SemaObjCXX/instantiate-expr.mm
new file mode 100644
index 000000000000..08be5f7b9110
--- /dev/null
+++ b/test/SemaObjCXX/instantiate-expr.mm
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface A {
+@public
+ int ivar;
+}
+@property int prop;
+@end
+
+typedef struct objc_object {
+ Class isa;
+} *id;
+
+// Test instantiation of value-dependent ObjCIvarRefExpr,
+// ObjCIsaRefExpr, and ObjCPropertyRefExpr nodes.
+A *get_an_A(unsigned);
+id get_an_id(unsigned);
+
+template<unsigned N, typename T, typename U, typename V>
+void f(U value, V value2) {
+ get_an_A(N)->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
+ get_an_A(N).prop = value2; // expected-error{{assigning to 'int' from incompatible type 'double *'}}
+ T c = get_an_id(N)->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}}
+}
+
+template void f<6, Class>(int, int);
+template void f<7, Class>(int*, int); // expected-note{{in instantiation of}}
+template void f<8, Class>(int, double*); // expected-note{{in instantiation of}}
+template void f<9, int>(int, int); // expected-note{{in instantiation of}}
+
+// Test instantiation of unresolved member reference expressions to an
+// ivar reference.
+template<typename T, typename U, typename V>
+void f2(T ptr, U value, V value2) {
+ ptr->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
+ ptr.prop = value2; // expected-error{{assigning to 'int' from incompatible type 'double *'}}
+}
+
+template void f2(A*, int, int);
+template void f2(A*, int*, int); // expected-note{{instantiation of}}
+template void f2(A*, int, double*); // expected-note{{instantiation of}}
+
+// Test instantiation of unresolved member referfence expressions to
+// an isa.
+template<typename T, typename U>
+void f3(U ptr) {
+ T c = ptr->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}}
+}
+
+template void f3<Class>(id);
+template void f3<int>(id); // expected-note{{instantiation of}}
+
+// Implicit setter/getter
+@interface B
+- (int)foo;
+- (void)setFoo:(int)value;
+@end
+
+template<typename T>
+void f4(B *b, T value) {
+ b.foo = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
+}
+
+template void f4(B*, int);
+template void f4(B*, int*); // expected-note{{in instantiation of function template specialization 'f4<int *>' requested here}}
+
+template<typename T, typename U>
+void f5(T ptr, U value) {
+ ptr.foo = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
+}
+
+template void f5(B*, int);
+template void f5(B*, int*); // expected-note{{in instantiation of function template specialization 'f5<B *, int *>' requested here}}
diff --git a/test/SemaObjCXX/instantiate-message.mm b/test/SemaObjCXX/instantiate-message.mm
new file mode 100644
index 000000000000..46c8ede26a59
--- /dev/null
+++ b/test/SemaObjCXX/instantiate-message.mm
@@ -0,0 +1,50 @@
+// RUN: %clang -cc1 -fsyntax-only -verify %s
+
+// Test template instantiation of Objective-C message sends.
+
+@interface ClassMethods
++ (ClassMethods *)method1:(void*)ptr;
+@end
+
+template<typename T>
+struct identity {
+ typedef T type;
+};
+
+template<typename R, typename T, typename Arg1>
+void test_class_method(Arg1 arg1) {
+ R *result1 = [T method1:arg1];
+ R *result2 = [typename identity<T>::type method1:arg1];
+ R *result3 = [ClassMethods method1:arg1]; // expected-error{{cannot initialize a variable of type 'ClassMethods2 *' with an rvalue of type 'ClassMethods *'}}
+}
+
+template void test_class_method<ClassMethods, ClassMethods>(void*);
+template void test_class_method<ClassMethods, ClassMethods>(int*);
+
+@interface ClassMethods2
++ (ClassMethods2 *)method1:(int*)ptr;
+@end
+
+template void test_class_method<ClassMethods2, ClassMethods2>(int*); // expected-note{{in instantiation of}}
+
+
+@interface InstanceMethods
+- (InstanceMethods *)method1:(void*)ptr;
+@end
+
+template<typename R, typename T, typename Arg1>
+void test_instance_method(Arg1 arg1) {
+ T *receiver = 0;
+ InstanceMethods *im = 0;
+ R *result1 = [receiver method1:arg1];
+ R *result2 = [im method1:arg1]; // expected-error{{cannot initialize a variable of type 'InstanceMethods2 *' with an rvalue of type 'InstanceMethods *'}}
+}
+
+template void test_instance_method<InstanceMethods, InstanceMethods>(void*);
+template void test_instance_method<InstanceMethods, InstanceMethods>(int*);
+
+@interface InstanceMethods2
+- (InstanceMethods2 *)method1:(void*)ptr;
+@end
+
+template void test_instance_method<InstanceMethods2, InstanceMethods2>(int*); // expected-note{{in instantiation of}}
diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm
new file mode 100644
index 000000000000..e92f8e8d4f0c
--- /dev/null
+++ b/test/SemaObjCXX/instantiate-stmt.mm
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface NSException
+@end
+
+// @throw
+template<typename T>
+void throw_test(T value) {
+ @throw value; // expected-error{{@throw requires an Objective-C object type ('int' invalid)}}
+}
+
+template void throw_test(NSException *);
+template void throw_test(int); // expected-note{{in instantiation of}}
+
+// @synchronized
+template<typename T>
+void synchronized_test(T value) {
+ @synchronized (value) { // expected-error{{@synchronized requires an Objective-C object type ('int' invalid)}}
+ value = 0;
+ }
+}
+
+template void synchronized_test(NSException *);
+template void synchronized_test(int); // expected-note{{in instantiation of}}
+
+// fast enumeration
+@interface NSArray
+@end
+
+@interface NSString
+@end
+
+struct vector {};
+
+template<typename T> void eat(T);
+
+template<typename E, typename T>
+void fast_enumeration_test(T collection) {
+ for (E element in collection) { // expected-error{{selector element type 'int' is not a valid object}} \
+ // expected-error{{collection expression type 'vector' is not a valid object}}
+ eat(element);
+ }
+
+ E element;
+ for (element in collection) // expected-error{{selector element type 'int' is not a valid object}} \
+ // expected-error{{collection expression type 'vector' is not a valid object}}
+ eat(element);
+
+ for (NSString *str in collection) // expected-error{{collection expression type 'vector' is not a valid object}}
+ eat(str);
+
+ NSString *str;
+ for (str in collection) // expected-error{{collection expression type 'vector' is not a valid object}}
+ eat(str);
+}
+
+template void fast_enumeration_test<NSString *>(NSArray*);
+template void fast_enumeration_test<int>(NSArray*); // expected-note{{in instantiation of}}
+template void fast_enumeration_test<NSString *>(vector); // expected-note{{in instantiation of}}
+
+// @try/@catch/@finally
+
+template<typename T, typename U>
+void try_catch_finally_test(U value) {
+ @try {
+ value = 1; // expected-error{{assigning to 'int *' from incompatible type 'int'}}
+ }
+ @catch (T obj) { // expected-error{{@catch parameter is not a pointer to an interface type}}
+ id x = obj;
+ } @finally {
+ value = 0;
+ }
+}
+
+template void try_catch_finally_test<NSString *>(int);
+template void try_catch_finally_test<NSString *>(int*); // expected-note{{in instantiation of}}
+template void try_catch_finally_test<NSString>(int); // expected-note{{in instantiation of function template specialization 'try_catch_finally_test<NSString, int>' requested here}}
diff --git a/test/SemaObjCXX/ivar-lookup.mm b/test/SemaObjCXX/ivar-lookup.mm
new file mode 100644
index 000000000000..bb26f48f13d5
--- /dev/null
+++ b/test/SemaObjCXX/ivar-lookup.mm
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+@interface Ivar
+- (float*)method;
+@end
+
+@interface A {
+ A *Ivar;
+}
+- (int*)method;
+@end
+
+@implementation A
+- (int*)method {
+ int *ip = [Ivar method]; // Okay; calls A's method on the instance variable Ivar.
+ // Note that Objective-C calls Ivar's method.
+ return 0;
+}
+@end
diff --git a/test/SemaObjCXX/ivar-reference-type.mm b/test/SemaObjCXX/ivar-reference-type.mm
new file mode 100644
index 000000000000..2b5df453e0e4
--- /dev/null
+++ b/test/SemaObjCXX/ivar-reference-type.mm
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+@interface A {
+ int &r; // expected-error {{instance variables cannot be of reference type}}
+}
+@end
diff --git a/test/SemaObjCXX/linkage-spec.mm b/test/SemaObjCXX/linkage-spec.mm
index b4e809eee161..1454e6a6782c 100644
--- a/test/SemaObjCXX/linkage-spec.mm
+++ b/test/SemaObjCXX/linkage-spec.mm
@@ -2,3 +2,11 @@
extern "C" {
@class Protocol;
}
+
+// <rdar://problem/7827709>
+extern "C" {
+@class I;
+}
+
+@interface I
+@end
diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm
index 93a600aef32e..b75608e2327a 100644
--- a/test/SemaObjCXX/message.mm
+++ b/test/SemaObjCXX/message.mm
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface I1
-- (void)method;
+- (int*)method;
@end
@implementation I1
-- (void)method {
+- (int*)method {
struct x { };
- [x method]; // expected-error{{invalid receiver to message expression}}
+ [x method]; // expected-error{{receiver type 'x' is not an Objective-C class}}
+ return 0;
}
@end
@@ -15,15 +16,79 @@ typedef struct { int x; } ivar;
@interface I2 {
id ivar;
}
-- (void)method;
+- (int*)method;
+ (void)method;
@end
+struct I2_holder {
+ I2_holder();
+
+ I2 *get();
+};
+
+I2 *operator+(I2_holder, int);
+
@implementation I2
-- (void)method {
+- (int*)method {
[ivar method];
+
+ // Test instance messages that start with a simple-type-specifier.
+ [I2_holder().get() method];
+ [I2_holder().get() + 17 method];
+ return 0;
}
+ (void)method {
- [ivar method]; // expected-error{{invalid receiver to message expression}}
+ [ivar method]; // expected-error{{receiver type 'ivar' (aka 'ivar') is not an Objective-C class}}
+}
+@end
+
+// Class message sends
+@interface I3
++ (int*)method;
+@end
+
+@interface I4 : I3
++ (int*)otherMethod;
+@end
+
+template<typename T>
+struct identity {
+ typedef T type;
+};
+
+@implementation I4
++ (int *)otherMethod {
+ // Test class messages that use non-trivial simple-type-specifiers
+ // or typename-specifiers.
+ if (false) {
+ if (true)
+ return [typename identity<I3>::type method];
+
+ return [::I3 method];
+ }
+
+ int* ip1 = {[super method]};
+ int* ip2 = {[::I3 method]};
+ int* ip3 = {[typename identity<I3>::type method]};
+ int* ip4 = {[typename identity<I2_holder>::type().get() method]};
+ int array[5] = {[3] = 2};
+ return [super method];
}
@end
+
+struct String {
+ String(const char *);
+};
+
+struct MutableString : public String { };
+
+// C++-specific parameter types
+@interface I5
+- method:(const String&)str1
+ other:(String&)str2; // expected-note{{passing argument to parameter 'str2' here}}
+@end
+
+void test_I5(I5 *i5, String s) {
+ [i5 method:"hello" other:s];
+ [i5 method:s other:"world"]; // expected-error{{non-const lvalue reference to type 'String' cannot bind to a value of unrelated type 'char const [6]'}}
+}
diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm
index 144bda4390d5..cc3264fcc462 100644
--- a/test/SemaObjCXX/objc-pointer-conv.mm
+++ b/test/SemaObjCXX/objc-pointer-conv.mm
@@ -26,13 +26,13 @@ void RandomFunc(CFMDRef theDict, const void *key, const void *value);
@end
@interface I
-- (void) Meth : (I*) Arg;
+- (void) Meth : (I*) Arg; // expected-note{{passing argument to parameter 'Arg' here}}
@end
void Func (I* arg); // expected-note {{candidate function not viable: no known conversion from 'I const *' to 'I *' for 1st argument}}
void foo(const I *p, I* sel) {
- [sel Meth : p]; // expected-error {{incompatible type sending 'I const *', expected 'I *'}}
+ [sel Meth : p]; // expected-error {{cannot initialize a parameter of type 'I *' with an lvalue of type 'I const *'}}
Func(p); // expected-error {{no matching function for call to 'Func'}}
}
diff --git a/test/SemaObjCXX/overload-1.mm b/test/SemaObjCXX/overload-1.mm
new file mode 100644
index 000000000000..fc17ca2be98d
--- /dev/null
+++ b/test/SemaObjCXX/overload-1.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@protocol Proto1 @end
+
+@protocol Proto2 @end
+
+void f(id<Proto1> *) { } // expected-note {{previous definition is here}}
+
+void f(id<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
+
+void f(Class<Proto1> *) { } // expected-note {{previous definition is here}}
+
+void f(Class<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
+
+@interface I @end
+
+void f(I<Proto1> *) { } // expected-note {{previous definition is here}}
+
+void f(I<Proto1, Proto2> *) { } // expected-error {{conflicting types for 'f'}}
+
+@interface I1 @end
+
+void f1(I<Proto1> *) { }
+
+void f1(I1<Proto1, Proto2> *) { }
diff --git a/test/SemaObjCXX/parameters.mm b/test/SemaObjCXX/parameters.mm
new file mode 100644
index 000000000000..aab1fbda4dd8
--- /dev/null
+++ b/test/SemaObjCXX/parameters.mm
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -verify %s
+
+@interface A
+@end
+
+template<typename T>
+struct X0 {
+ void f(T); // expected-error{{interface type 'A' cannot be passed by value}}
+};
+
+X0<A> x0a; // expected-note{{instantiation}}
+
diff --git a/test/SemaObjCXX/void_to_obj.mm b/test/SemaObjCXX/void_to_obj.mm
index 932827e61425..52510c84f139 100644
--- a/test/SemaObjCXX/void_to_obj.mm
+++ b/test/SemaObjCXX/void_to_obj.mm
@@ -7,5 +7,5 @@ void func() {
XX *obj;
void *vv;
- obj = vv; // expected-error{{incompatible type assigning 'void *', expected 'XX *'}}
+ obj = vv; // expected-error{{assigning to 'XX *' from incompatible type 'void *'}}
}
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index 71aabe97f4e3..1be1bc070a81 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -51,3 +51,8 @@ void f() {
}
template<typename T> class X1 { } var; // expected-error{{declared as a template}}
+
+namespace M {
+}
+
+template<typename T> class M::C3 { }; // expected-error{{out-of-line definition of 'C3' does not match any declaration in namespace 'M'}}
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
index 82c2aa4cc3e7..b6ca72e9e149 100644
--- a/test/SemaTemplate/constructor-template.cpp
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -94,3 +94,18 @@ void default_ctor_inst() {
}
template void default_ctor_inst<int>();
+
+template<typename T>
+struct X5 {
+ X5();
+ X5(const T &);
+};
+
+struct X6 {
+ template<typename T> X6(T);
+};
+
+void test_X5_X6() {
+ X5<X6> tf;
+ X5<X6> tf2(tf);
+}
diff --git a/test/SemaTemplate/default-expr-arguments-2.cpp b/test/SemaTemplate/default-expr-arguments-2.cpp
new file mode 100644
index 000000000000..88cc43d6445e
--- /dev/null
+++ b/test/SemaTemplate/default-expr-arguments-2.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
+
+// This is a wacky test to ensure that we're actually instantiating
+// the default rguments of the constructor when the function type is
+// otherwise non-dependent.
+namespace PR6733 {
+ template <class T>
+ class bar {
+ public: enum { kSomeConst = 128 };
+ bar(int x = kSomeConst) {}
+ };
+
+ // CHECK: void f()
+ void f() {
+ // CHECK: bar<int> tmp =
+ // CHECK: CXXDefaultArgExpr{{.*}}'int'
+ bar<int> tmp;
+ }
+}
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index d2cc45b0352b..7c3525a1fb15 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -7,7 +7,8 @@ C<char>::C(int a0);
struct S { }; // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
-template<typename T> void f1(T a, T b = 10) { } // expected-error{{no viable conversion}}
+template<typename T> void f1(T a, T b = 10) { } // expected-error{{no viable conversion}} \
+// expected-note{{passing argument to parameter 'b' here}}
template<typename T> void f2(T a, T b = T()) { }
@@ -25,8 +26,10 @@ void g() {
}
template<typename T> struct F {
- F(T t = 10); // expected-error{{no viable conversion}}
- void f(T t = 10); // expected-error{{no viable conversion}}
+ F(T t = 10); // expected-error{{no viable conversion}} \
+ // expected-note{{passing argument to parameter 't' here}}
+ void f(T t = 10); // expected-error{{no viable conversion}} \
+ // expected-note{{passing argument to parameter 't' here}}
};
struct FD : F<int> { };
@@ -99,7 +102,8 @@ void test_x2(X2<int> x2i, X2<NotDefaultConstructible> x2n) {
// PR5283
namespace PR5283 {
template<typename T> struct A {
- A(T = 1); // expected-error 3 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'int'}}
+ A(T = 1); // expected-error 3 {{cannot initialize a parameter of type 'int *' with an rvalue of type 'int'}} \
+ // expected-note 3{{passing argument to parameter here}}
};
struct B : A<int*> {
@@ -184,3 +188,21 @@ template<> void f4<int>(int, int);
void f4_test(int i) {
f4(i);
}
+
+// Instantiate for initialization
+namespace InstForInit {
+ template<typename T>
+ struct Ptr {
+ typedef T* type;
+ Ptr(type);
+ };
+
+ template<typename T>
+ struct Holder {
+ Holder(int i, Ptr<T> ptr = 0);
+ };
+
+ void test_holder(int i) {
+ Holder<int> h(i);
+ }
+};
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index a2d3c56501e8..77961069c5a2 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -18,15 +18,18 @@ template<class T> class R : Q<T> {T current;};
namespace test0 {
template <class T> class Base {
+ public:
void instance_foo();
static void static_foo();
class Inner {
+ public:
void instance_foo();
static void static_foo();
};
};
template <class T> class Derived1 : Base<T> {
+ public:
void test0() {
Base<T>::static_foo();
Base<T>::instance_foo();
@@ -49,6 +52,7 @@ namespace test0 {
};
template <class T> class Derived2 : Base<T>::Inner {
+ public:
void test0() {
Base<T>::static_foo();
Base<T>::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 83b1beeea997..fa1b3e0001c4 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -32,3 +32,11 @@ namespace PR6152 {
template struct X<int>;
}
+namespace cvquals {
+ template<typename T>
+ void f(int *ptr) {
+ ptr->~T();
+ }
+
+ template void f<const volatile int>(int *);
+}
diff --git a/test/SemaTemplate/elaborated-type-specifier.cpp b/test/SemaTemplate/elaborated-type-specifier.cpp
new file mode 100644
index 000000000000..b34660acbea0
--- /dev/null
+++ b/test/SemaTemplate/elaborated-type-specifier.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR6915 {
+ template <typename T>
+ class D {
+ enum T::X v; // expected-error{{use of 'X' with tag type that does not match previous declaration}} \
+ // expected-error{{no enum named 'X' in 'PR6915::D3'}}
+ };
+
+ struct D1 {
+ enum X { value };
+ };
+ struct D2 {
+ class X { }; // expected-note{{previous use is here}}
+ };
+ struct D3 { };
+
+ template class D<D1>;
+ template class D<D2>; // expected-note{{in instantiation of}}
+ template class D<D3>; // expected-note{{in instantiation of}}
+}
+
+template<typename T>
+struct DeclOrDef {
+ enum T::foo; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+ enum T::bar { // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+ value
+ };
+};
+
+namespace PR6649 {
+ template <typename T> struct foo {
+ class T::bar; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+ class T::bar { int x; }; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+ };
+}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index cb0a39a9d0cf..417cdc1f1987 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -16,7 +16,7 @@ namespace PR6161 {
// expected-error{{expected class name}} \
// expected-note{{attempt to specialize declaration here}}
{
- static locale::id id; // expected-error{{use of undeclared identifier}} FIXME: expected-error {{unknown type name}}
+ static locale::id id; // expected-error{{use of undeclared identifier}}
};
numpunct<char>::~numpunct(); // expected-error{{template specialization requires 'template<>'}} \
// expected-error{{specialization of member 'PR6161::numpunct<char>::~numpunct' does not specialize an instantiated member}}
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 6ee30aa7775a..1d62804f68ac 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -127,3 +127,83 @@ namespace PR6022 {
};
}
+namespace FriendTemplateDefinition {
+ template<unsigned > struct int_c { };
+
+ template<typename T>
+ struct X {
+ template<unsigned N>
+ friend void f(X, int_c<N>) {
+ int value = N;
+ };
+ };
+
+ void test_X(X<int> x, int_c<5> i5) {
+ f(x, i5);
+ }
+}
+
+namespace PR7013a {
+ template<class > struct X0
+ {
+ typedef int type;
+ };
+ template<typename > struct X1
+ {
+ };
+ template<typename , typename T> struct X2
+ {
+ typename T::type e;
+ };
+ namespace N
+ {
+ template <typename = int, typename = X1<int> > struct X3
+ {
+ template <typename T1, typename T2, typename B> friend void op(X2<T1, T2>& , B);
+ };
+ template <typename Ch, typename Tr, typename B> void op(X2<Ch, Tr>& , B)
+ {
+ X2<int, Tr> s;
+ }
+ }
+ int n()
+ {
+ X2<int, X0<int> > ngs;
+ N::X3<> b;
+ op(ngs, b);
+ return 0;
+ }
+}
+
+namespace PR7013b {
+ template<class > struct X0
+ {
+ typedef int type;
+ };
+ template<typename > struct X1
+ {
+ };
+ template<typename , typename T> struct X2
+ {
+ typename T::type e;
+ };
+ namespace N
+ {
+ template <typename = X1<int> > struct X3
+ {
+ template <typename T1, typename T2, typename B> friend void op(X2<T1, T2>& , B);
+ };
+ template <typename Ch, typename Tr, typename B> void op(X2<Ch, Tr>& , B)
+ {
+ X2<int, Tr> s;
+ }
+ }
+ int n()
+ {
+ X2<int, X0<int> > ngs;
+ N::X3<> b;
+ op(ngs, b);
+ return 0;
+ }
+
+}
diff --git a/test/SemaTemplate/friend.cpp b/test/SemaTemplate/friend.cpp
index 61ef1865da5d..99685f2396cf 100644
--- a/test/SemaTemplate/friend.cpp
+++ b/test/SemaTemplate/friend.cpp
@@ -12,3 +12,22 @@ void f() {
struct C0 {
friend struct A<int>;
};
+
+namespace PR6770 {
+ namespace N {
+ int f1(int);
+ }
+ using namespace N;
+
+ namespace M {
+ float f1(float);
+ }
+ using M::f1;
+
+ template<typename T> void f1(T, T);
+ template <class T>
+ void f() {
+ friend class f; // expected-error{{'friend' used outside of class}}
+ friend class f1; // expected-error{{ 'friend' used outside of class}}
+ }
+}
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
index 1c9b232f6d36..309921c0a664 100644
--- a/test/SemaTemplate/fun-template-def.cpp
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -42,7 +42,7 @@ T f1(T t1, U u1, int i1)
dummy d1 = sizeof(t1); // expected-error {{no viable conversion}}
dummy d2 = offsetof(T, foo); // expected-error {{no viable conversion}}
dummy d3 = __alignof(u1); // expected-error {{no viable conversion}}
- i1 = typeid(t1); // expected-error {{incompatible type assigning}}
+ i1 = typeid(t1); // expected-error {{assigning to 'int' from incompatible type 'std::type_info const'}}
return u1;
}
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index 586be189b0ab..4c21d2585d32 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -48,3 +48,15 @@ namespace pr6326 {
};
template class A<int>;
}
+
+namespace ForwardDecls {
+ template<typename T>
+ struct X;
+
+ template<typename T>
+ struct X {
+ typedef T foo;
+ typedef X<T> xt;
+ typename xt::foo *t;
+ };
+}
diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp
index 82cc320fd3c4..d854c9e6aacc 100644
--- a/test/SemaTemplate/instantiate-complete.cpp
+++ b/test/SemaTemplate/instantiate-complete.cpp
@@ -11,7 +11,8 @@ struct X {
// expected-error{{data member instantiated with function type 'int (int)'}} \
// expected-error{{data member instantiated with function type 'char (char)'}} \
// expected-error{{data member instantiated with function type 'short (short)'}} \
- // expected-error{{data member instantiated with function type 'float (float)'}}
+ // expected-error{{data member instantiated with function type 'float (float)'}} \
+ // expected-error{{data member instantiated with function type 'long (long)'}}
};
X<int> f() { return 0; }
@@ -43,7 +44,7 @@ void test_memptr(X<long> *p1, long X<long>::*pm1,
X<long(long)> *p2,
long (X<long(long)>::*pm2)(long)) {
(void)(p1->*pm1);
- (void)((p2->*pm2)(0));
+ (void)((p2->*pm2)(0)); // expected-note{{in instantiation of template class 'X<long (long)>' requested here}}
}
// Reference binding to a base
@@ -83,3 +84,18 @@ namespace PR6376 {
template struct Y<int, float>;
}
+
+namespace TemporaryObjectCopy {
+ // Make sure we instantiate classes when we create a temporary copy.
+ template<typename T>
+ struct X {
+ X(T);
+ };
+
+ template<typename T>
+ void f(T t) {
+ const X<int> &x = X<int>(t);
+ }
+
+ template void f(int);
+}
diff --git a/test/SemaTemplate/instantiate-default-assignment-operator.cpp b/test/SemaTemplate/instantiate-default-assignment-operator.cpp
index 5594d6c7d799..8b97f59e87ed 100644
--- a/test/SemaTemplate/instantiate-default-assignment-operator.cpp
+++ b/test/SemaTemplate/instantiate-default-assignment-operator.cpp
@@ -5,13 +5,13 @@ template<typename T> struct RefPtr {
RefPtr& operator=(const PassRefPtr<T>&);
};
-struct A { RefPtr<int> a; };
-struct B : RefPtr<float> { };
+struct A { RefPtr<int> a; }; // expected-note {{instantiation of member function 'RefPtr<int>::operator=' requested here}}
+struct B : RefPtr<float> { }; // expected-note {{in instantiation of member function 'RefPtr<float>::operator=' requested here}}
void f() {
A a1, a2;
- a1 = a2; // expected-note {{instantiation of member function 'RefPtr<int>::operator=' requested here}}
+ a1 = a2;
B b1, b2;
- b1 = b2; // expected-note {{in instantiation of member function 'RefPtr<float>::operator=' requested here}}
+ b1 = b2;
}
diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp
index 4da4e713ec18..b91b398a80e3 100644
--- a/test/SemaTemplate/instantiate-expr-2.cpp
+++ b/test/SemaTemplate/instantiate-expr-2.cpp
@@ -193,3 +193,22 @@ namespace N12 {
void f0(int **a) { C::f0(a); }
}
+
+namespace N13 {
+ class A{
+ A(const A&);
+
+ public:
+ ~A();
+ A(int);
+ template<typename T> A &operator<<(const T&);
+ };
+
+ template<typename T>
+ void f(T t) {
+ A(17) << t;
+ }
+
+ template void f(int);
+
+}
diff --git a/test/SemaTemplate/instantiate-expr-5.cpp b/test/SemaTemplate/instantiate-expr-5.cpp
index 941dae44829a..6cdedda4d880 100644
--- a/test/SemaTemplate/instantiate-expr-5.cpp
+++ b/test/SemaTemplate/instantiate-expr-5.cpp
@@ -1,4 +1,38 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
template <class A> int x(A x) { return x++; }
int y() { return x<int>(1); }
+
+namespace PR5880 {
+ template<typename T>
+ struct A {
+ static const int a = __builtin_offsetof(T, a.array[5].m); // expected-error{{error: no member named 'a' in 'HasM'}}
+ };
+ struct HasM {
+ float m;
+ };
+
+ struct ArrayOfHasM {
+ HasM array[10];
+ };
+
+ struct B { ArrayOfHasM a; };
+ A<B> x;
+ A<HasM> x2; // expected-note{{in instantiation of}}
+
+ template<typename T>
+ struct AnonymousUnion {
+ union {
+ int i;
+ float f;
+ };
+ };
+
+ template<typename T>
+ void test_anon_union() {
+ int array1[__builtin_offsetof(AnonymousUnion<T>, f) == 0? 1 : -1];
+ int array2[__builtin_offsetof(AnonymousUnion<int>, f) == 0? 1 : -1];
+ }
+
+ template void test_anon_union<int>();
+}
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 6e0d71159004..1bda43000b2a 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -220,3 +220,8 @@ namespace test0 {
template <class T> class A { void foo(T array[10]); };
template class A<int>;
}
+
+namespace PR7016 {
+ template<typename T> void f() { T x = x; }
+ template void f<int>();
+}
diff --git a/test/SemaTemplate/instantiate-function-params.cpp b/test/SemaTemplate/instantiate-function-params.cpp
index ea8dd7061988..45de3425d2a2 100644
--- a/test/SemaTemplate/instantiate-function-params.cpp
+++ b/test/SemaTemplate/instantiate-function-params.cpp
@@ -3,13 +3,13 @@
// PR6619
template<bool C> struct if_c { };
template<typename T1> struct if_ {
- typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 7{{in instantiation}}
+ typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 5{{in instantiation}}
};
template <class Model, void (Model::*)()> struct wrap_constraints { };
template <class Model>
-inline char has_constraints_(Model* , // expected-note 4{{while substituting deduced template arguments into function template 'has_constraints_' [with }} \
+inline char has_constraints_(Model* , // expected-note 2{{while substituting deduced template arguments into function template 'has_constraints_' [with }} \
// expected-note 3{{candidate template ignored}}
- wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 4{{in instantiation}}
+ wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 2{{in instantiation}}
template <class Model> struct not_satisfied {
static const bool value = sizeof( has_constraints_((Model*)0) == 1); // expected-error 3{{no matching function}}
@@ -17,20 +17,18 @@ template <class Model> struct not_satisfied {
template <class ModelFn> struct requirement_;
template <void(*)()> struct instantiate {
};
-template <class Model> struct requirement_<void(*)(Model)> : if_< not_satisfied<Model> >::type { // expected-error 3{{no type named}} \
- // expected-note 7{{in instantiation}}
+template <class Model> struct requirement_<void(*)(Model)> : if_< not_satisfied<Model> >::type { // expected-note 5{{in instantiation}}
};
template <class Model> struct usage_requirements {
};
template < typename TT > struct InputIterator {
- typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note 2{{in instantiation}}
+ typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note {{in instantiation}}
};
-template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note 2{{in instantiation}}
- typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note 2 {{in instantiation}}
+template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note {{in instantiation}}
+ typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note {{in instantiation}}
};
-typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX; // expected-error{{no member named}} \
-// expected-note 6{{in instantiation}}
+typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX;// expected-note 3{{in instantiation}}
template<typename T> struct X0 { };
template<typename R, typename A1> struct X0<R(A1 param)> { };
@@ -55,3 +53,26 @@ void use_func_ptr() {
};
template void use_func_ptr<int, float, double>();
+
+namespace PR6990 {
+ template < typename , typename = int, typename = int > struct X1;
+ template <typename >
+ struct X2;
+
+ template <typename = int *, typename TokenT = int,
+ typename = int( X2<TokenT> &)>
+ struct X3
+ {
+ };
+
+ template <typename , typename P>
+ struct X3_base : X3< X1<int, P> >
+ {
+ protected: typedef X1< P> type;
+ X3<type> e;
+ };
+
+ struct r : X3_base<int, int>
+ {
+ };
+}
diff --git a/test/SemaTemplate/instantiate-local-class.cpp b/test/SemaTemplate/instantiate-local-class.cpp
index 72ad90a04f20..d57ba8a68288 100644
--- a/test/SemaTemplate/instantiate-local-class.cpp
+++ b/test/SemaTemplate/instantiate-local-class.cpp
@@ -13,11 +13,11 @@ template void f0<int>();
// PR5764
namespace PR5764 {
- class X {
+ struct X {
template <typename T>
void Bar() {
typedef T ValueType;
- class Y {
+ struct Y {
Y() { V = ValueType(); }
ValueType V;
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 44f396e47af7..f1bdf3e1e6d5 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -18,8 +18,8 @@ X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor na
X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
void test_naming() {
- c1 = c2; // expected-error{{incompatible type assigning 'X<float>::C *', expected 'X<int>::C *'}}
- xi = xf; // expected-error{{incompatible type assigning}}
+ c1 = c2; // expected-error{{assigning to 'X<int>::C *' from incompatible type 'X<float>::C *'}}
+ xi = xf; // expected-error{{assigning to 'X<int>::X<int> *' from incompatible type 'X<float>::X<float> *'}}
// FIXME: error above doesn't print the type X<int>::X cleanly!
}
@@ -40,9 +40,9 @@ X<void>::D::E e2; // expected-note{{in instantiation of member class 'X<void>::D
// Redeclarations.
namespace test1 {
template <typename T> struct Registry {
- class node;
+ struct node;
static node *Head;
- class node {
+ struct node {
node(int v) { Head = this; }
};
};
@@ -64,6 +64,7 @@ namespace test2 {
template <typename T> class B {
class Foo;
class Foo {
+ public:
typedef int X;
};
typename Foo::X x;
diff --git a/test/SemaTemplate/instantiate-member-expr.cpp b/test/SemaTemplate/instantiate-member-expr.cpp
index f3a60679d176..188705ce2139 100644
--- a/test/SemaTemplate/instantiate-member-expr.cpp
+++ b/test/SemaTemplate/instantiate-member-expr.cpp
@@ -43,7 +43,7 @@ namespace test1 {
int a;
template<typename T> struct B : A<T> {
void f() {
- a = 0; // expected-error {{type 'test1::O' is not a direct or virtual base of ''B<int>''}}
+ a = 0; // expected-error {{'test1::O::a' is not a member of class 'test1::O::B<int>'}}
}
};
};
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
index e0594347f262..45503b38b38d 100644
--- a/test/SemaTemplate/instantiate-member-initializers.cpp
+++ b/test/SemaTemplate/instantiate-member-initializers.cpp
@@ -10,8 +10,8 @@ A<int> a0;
A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}}
template<typename T> struct B {
- B() : b(1), // expected-warning {{member 'b' will be initialized after}}
- a(2) { } // expected-note {{field a}}
+ B() : b(1), // expected-warning {{field 'b' will be initialized after field 'a'}}
+ a(2) { }
int a;
int b;
@@ -21,6 +21,7 @@ B<int> b0; // expected-note {{in instantiation of member function 'B<int>::B' re
template <class T> struct AA { AA(int); };
template <class T> class BB : public AA<T> {
+public:
BB() : AA<T>(1) {}
};
BB<int> x;
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index c1260cf6a81e..ae8425e716ee 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -44,7 +44,7 @@ struct X1 {
template<typename U>
struct Inner3 {
- void f0(T t, U u) {
+ void f0(T t, U u) { // expected-note{{passing argument to parameter 't' here}}
(void)(t + u); // expected-error{{invalid operands}}
}
diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp
index 357ea2617759..363115d1844e 100644
--- a/test/SemaTemplate/instantiate-method.cpp
+++ b/test/SemaTemplate/instantiate-method.cpp
@@ -5,7 +5,7 @@ public:
void f(T x); // expected-error{{argument may not have 'void' type}}
void g(T*);
- static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
+ static int h(T, T); // expected-error {{argument may not have 'void' type}}
};
int identity(int x) { return x; }
@@ -117,3 +117,61 @@ struct X3 {
template struct X3<double>;
+
+// Don't try to instantiate this, it's invalid.
+namespace test1 {
+ template <class T> class A {};
+ template <class T> class B {
+ void foo(A<test1::Undeclared> &a) // expected-error {{no member named 'Undeclared' in namespace 'test1'}}
+ {}
+ };
+ template class B<int>;
+}
+
+namespace PR6947 {
+ template< class T >
+ struct X {
+ int f0( )
+ {
+ typedef void ( X::*impl_fun_ptr )( );
+ impl_fun_ptr pImpl = &X::template
+ f0_impl1<int>;
+ }
+ private:
+ int f1() {
+ }
+ template< class Processor>
+ void f0_impl1( )
+ {
+ }
+ };
+
+ char g0() {
+ X<int> pc;
+ pc.f0();
+ }
+
+}
+
+namespace PR7022 {
+ template <typename >
+ struct X1
+ {
+ typedef int state_t( );
+ state_t g ;
+ };
+
+ template < typename U = X1<int> > struct X2
+ {
+ X2( U = U())
+ {
+ }
+ };
+
+ void m(void)
+ {
+ typedef X2<> X2_type;
+ X2_type c;
+ }
+
+}
diff --git a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
index 414e62b13a03..cbadcde2c1c1 100644
--- a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
+++ b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp
@@ -9,6 +9,28 @@ public:
}
};
-int main(int argc, char *argv[]) {
+void test_stringswitch(int argc, char *argv[]) {
(void)StringSwitch<int>();
}
+
+namespace PR6986 {
+ template<class Class,typename Type,Type Class::*>
+ struct non_const_member_base
+ {
+ };
+
+ template<class Class,typename Type,Type Class::*PtrToMember>
+ struct member: non_const_member_base<Class,Type,PtrToMember>
+ {
+ };
+
+ struct test_class
+ {
+ int int_member;
+ };
+ typedef member< test_class,const int,&test_class::int_member > ckey_m;
+ void test()
+ {
+ ckey_m m;
+ }
+}
diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp
index bb168a1c932e..4e6cd24111c4 100644
--- a/test/SemaTemplate/instantiate-typedef.cpp
+++ b/test/SemaTemplate/instantiate-typedef.cpp
@@ -11,6 +11,5 @@ add_pointer<float>::type test2(int * ptr) {
return ptr; // expected-error{{cannot initialize return object of type 'add_pointer<float>::type' (aka 'float *') with an lvalue of type 'int *'}}
}
-add_pointer<int&>::type // expected-note{{in instantiation of template class 'add_pointer<int &>' requested here}} \
-// expected-error {{no type named 'type' in 'add_pointer<int &>'}}
+add_pointer<int&>::type // expected-note{{in instantiation of template class 'add_pointer<int &>' requested here}}
test3();
diff --git a/test/SemaTemplate/instantiate-using-decl.cpp b/test/SemaTemplate/instantiate-using-decl.cpp
index a4394aa21f6e..257904490daa 100644
--- a/test/SemaTemplate/instantiate-using-decl.cpp
+++ b/test/SemaTemplate/instantiate-using-decl.cpp
@@ -38,7 +38,7 @@ namespace test1 {
using Base2::Visit;
};
- class Knot : JoinVisitor<Knot> {
+ class Knot : public JoinVisitor<Knot> {
};
void test() {
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
index f48ede9c44cf..a2b9d2eb1513 100644
--- a/test/SemaTemplate/instantiation-depth.cpp
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -ftemplate-depth 5 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 %s
-template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
-// expected-note{{use -ftemplate-depth-N to increase recursive template instantiation depth}} \
-// expected-note 5 {{instantiation of template class}}
+template<typename T> struct X : X<T*> { }; \
+// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
+// expected-note 3 {{instantiation of template class}} \
+// expected-note {{skipping 2 contexts in backtrace}} \
+// expected-note {{use -ftemplate-depth-N to increase recursive template instantiation depth}}
void test() {
(void)sizeof(X<int>); // expected-note {{instantiation of template class}}
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index 1691db74a115..9d25a051e8a8 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -51,3 +51,16 @@ struct TestA {
typedef typename N::template B<T>::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} \
// expected-error{{expected member name}}
};
+
+// Reduced from a Boost failure.
+namespace test1 {
+ template <class T> struct pair {
+ T x;
+ T y;
+
+ static T pair<T>::* const mem_array[2];
+ };
+
+ template <class T>
+ T pair<T>::* const pair<T>::mem_array[2] = { &pair<T>::x, &pair<T>::y };
+}
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
index 2e3a826ce894..29eab89d84f5 100644
--- a/test/SemaTemplate/qualified-id.cpp
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -21,6 +21,7 @@ namespace test1 {
namespace test2 {
class Impl {
+ public:
int foo();
};
template <class T> class Magic : public Impl {
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
index 80bbda785d05..5a4c8fc16fd6 100644
--- a/test/SemaTemplate/temp_arg.cpp
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -2,7 +2,7 @@
template<typename T,
int I,
template<typename> class TT>
- class A; // expected-note 2 {{template is declared here}}
+ class A; // expected-note 3 {{template is declared here}}
template<typename> class X;
@@ -10,6 +10,7 @@ A<int, 0, X> * a1;
A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
+A a3; // expected-error{{use of class template A requires template arguments}}
namespace test0 {
template <class t> class foo {};
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 6e4f751d47d1..d351eb458838 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -36,19 +36,19 @@ A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'X' mus
float f(float);
-float g(float);
-double g(double);
+float g(float); // expected-note 2{{candidate function}}
+double g(double); // expected-note 2{{candidate function}}
int h(int);
float h2(float);
-template<int fp(int)> struct A3; // expected-note 2{{template parameter is declared here}}
+template<int fp(int)> struct A3; // expected-note 1{{template parameter is declared here}}
A3<h> *a14_1;
A3<&h> *a14_2;
A3<f> *a14_3;
A3<&f> *a14_4;
A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (*)(int)'}}
-A3<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (*)(int)'}}
+A3<g> *a14_7; // expected-error{{address of overloaded function 'g' does not match required type 'int (int)'}}
struct Y { } y;
@@ -61,11 +61,11 @@ A4<*X_volatile_ptr> *a15_2; // expected-error{{non-type template argument does n
A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'X const &' cannot bind to template argument of type 'struct Y'}} \
// FIXME: expected-error{{expected unqualified-id}}
-template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
+template<int (&fr)(int)> struct A5; // expected-note{{template parameter is declared here}}
A5<h> *a16_1;
A5<f> *a16_3;
A5<h2> *a16_6; // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'float (float)'}}
-A5<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (&)(int)'}}
+A5<g> *a14_7; // expected-error{{address of overloaded function 'g' does not match required type 'int (int)'}}
struct Z {
int foo(int);
@@ -176,3 +176,30 @@ namespace PR6723 {
f<512>(arr512); // expected-error{{no matching function for call}}
}
}
+
+// Check that we instantiate declarations whose addresses are taken
+// for non-type template arguments.
+namespace EntityReferenced {
+ template<typename T, void (*)(T)> struct X { };
+
+ template<typename T>
+ struct Y {
+ static void f(T x) {
+ x = 1; // expected-error{{assigning to 'int *' from incompatible type 'int'}}
+ }
+ };
+
+ void g() {
+ typedef X<int*, Y<int*>::f> x; // expected-note{{in instantiation of}}
+ }
+}
+
+namespace PR6964 {
+ template <typename ,int, int = 9223372036854775807L > // expected-warning 2{{non-type template argument value '9223372036854775807' truncated to '-1' for template parameter of type 'int'}} \
+ // expected-note 2{{template parameter is declared here}}
+ struct as_nview { };
+
+ template <typename Sequence, int I0>
+ struct as_nview<Sequence, I0> // expected-note{{while checking a default template argument used here}}
+ { };
+}
diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp
index a1db3f8057ac..3876c256455d 100644
--- a/test/SemaTemplate/temp_arg_type.cpp
+++ b/test/SemaTemplate/temp_arg_type.cpp
@@ -1,16 +1,26 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<typename T> class A; // expected-note 2 {{template parameter is declared here}}
+template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
// [temp.arg.type]p1
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
-A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
+A<A> *a2; // expected-error{{use of class template A requires template arguments}}
A<int> *a3;
A<int()> *a4;
A<int(float)> *a5;
A<A<int> > *a6;
+// Pass an overloaded function template:
+template<typename T> void function_tpl(T);
+A<function_tpl> a7; // expected-error{{template argument for template type parameter must be a type}}
+
+// Pass a qualified name:
+namespace ns {
+template<typename T> class B {}; // expected-note{{template is declared here}}
+}
+A<ns::B> a8; // expected-error{{use of class template ns::B requires template arguments}}
+
// [temp.arg.type]p2
void f() {
class X { };
@@ -18,7 +28,15 @@ void f() {
}
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
-A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}}
+A<__typeof__(Unnamed)> *a9; // expected-error{{template argument uses unnamed type}}
+
+template<typename T, unsigned N>
+struct Array {
+ typedef struct { T x[N]; } type;
+};
+
+template<typename T> struct A1 { };
+A1<Array<int, 17>::type> ax;
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
// belongs somewhere in the template instantiation section).
diff --git a/test/SemaTemplate/template-decl-fail.cpp b/test/SemaTemplate/template-decl-fail.cpp
index eca0f58831a9..ad134cdf225c 100644
--- a/test/SemaTemplate/template-decl-fail.cpp
+++ b/test/SemaTemplate/template-decl-fail.cpp
@@ -4,5 +4,7 @@ template<typename T> typedef T X; // expected-error{{typedef cannot be a templat
template<typename T>
enum t0 { A = T::x }; // expected-error{{enumeration cannot be a template}} \
- // expected-error{{declaration does not declare anything}}
+ // expected-warning{{declaration does not declare anything}}
+enum e0 {};
+template<int x> enum e0 f0(int a=x) {}
diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp
index 280a1b4c3957..8dfb60d70718 100644
--- a/test/SemaTemplate/typename-specifier-4.cpp
+++ b/test/SemaTemplate/typename-specifier-4.cpp
@@ -113,6 +113,6 @@ namespace PR6463 {
// FIXME: Improve source location info here.
template<typename T>
typename A<T>::type& A<T>::a() { // expected-error{{found in multiple base classes}}
- return x; // expected-error{{undeclared identifier}}
+ return x;
}
}
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index 42766a0620b8..3f6fe343f507 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -42,13 +42,10 @@ namespace N {
}
N::X<N::A>::type *ip4 = &i;
-N::X<N::B>::type *ip5 = &i; // expected-note{{in instantiation of template class 'N::X<N::B>' requested here}} \
-// expected-error{{no type named 'type' in}}
-N::X<N::C>::type *ip6 = &i; // expected-note{{in instantiation of template class 'N::X<N::C>' requested here}} \
-// expected-error{{no type named 'type' in}}
+N::X<N::B>::type *ip5 = &i; // expected-note{{in instantiation of template class 'N::X<N::B>' requested here}}
+N::X<N::C>::type *ip6 = &i; // expected-note{{in instantiation of template class 'N::X<N::C>' requested here}}
-N::X<int>::type fail1; // expected-note{{in instantiation of template class 'N::X<int>' requested here}} \
-// expected-error{{no type named 'type' in}}
+N::X<int>::type fail1; // expected-note{{in instantiation of template class 'N::X<int>' requested here}}
template<typename T>
struct Y {
@@ -69,7 +66,5 @@ struct C {
};
::Y<A>::type ip7 = &i;
-::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'Y<B>' requested here}} \
-// expected-error{{no type named 'type' in}}
-::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'Y<C>' requested here}} \
-// expected-error{{no type named 'type' in}}
+::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'Y<B>' requested here}}
+::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'Y<C>' requested here}}
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 01130e22773d..9cdb9659fe95 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -22,8 +22,12 @@
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Program.h"
@@ -35,7 +39,6 @@
using namespace clang;
using namespace clang::cxcursor;
using namespace clang::cxstring;
-using namespace idx;
//===----------------------------------------------------------------------===//
// Crash Reporting.
@@ -242,6 +245,7 @@ public:
// Declaration visitors
bool VisitAttributes(Decl *D);
+ bool VisitBlockDecl(BlockDecl *B);
bool VisitDeclContext(DeclContext *DC);
bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
bool VisitTypedefDecl(TypedefDecl *D);
@@ -297,10 +301,12 @@ public:
bool VisitForStmt(ForStmt *S);
// Expression visitors
- bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
- bool VisitExplicitCastExpr(ExplicitCastExpr *E);
+ bool VisitBlockExpr(BlockExpr *B);
bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ bool VisitExplicitCastExpr(ExplicitCastExpr *E);
bool VisitObjCMessageExpr(ObjCMessageExpr *E);
+ bool VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
};
} // end anonymous namespace
@@ -484,6 +490,15 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
return false;
}
+bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
+ for (BlockDecl::param_iterator I=B->param_begin(), E=B->param_end(); I!=E;++I)
+ if (Decl *D = *I)
+ if (Visit(D))
+ return true;
+
+ return Visit(MakeCXCursor(B->getBody(), StmtParent, TU));
+}
+
bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
for (DeclContext::decl_iterator
I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
@@ -814,8 +829,9 @@ bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
return true;
for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
- if (Visit(MakeCXCursor(TL.getArg(I), TU)))
- return true;
+ if (Decl *D = TL.getArg(I))
+ if (Visit(MakeCXCursor(D, TU)))
+ return true;
return false;
}
@@ -923,6 +939,10 @@ bool CursorVisitor::VisitForStmt(ForStmt *S) {
return false;
}
+bool CursorVisitor::VisitBlockExpr(BlockExpr *B) {
+ return Visit(B->getBlockDecl());
+}
+
bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
if (E->isArgumentType()) {
if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo())
@@ -951,13 +971,18 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
}
bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) {
- ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
- if (CI.Decl && Visit(MakeCursorObjCClassRef(CI.Decl, CI.Loc, TU)))
- return true;
+ if (TypeSourceInfo *TSInfo = E->getClassReceiverTypeInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
return VisitExpr(E);
}
+bool CursorVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ return Visit(E->getEncodedTypeSourceInfo()->getTypeLoc());
+}
+
+
bool CursorVisitor::VisitAttributes(Decl *D) {
for (const Attr *A = D->getAttrs(); A; A = A->getNext())
if (Visit(MakeCXCursor(A, D, TU)))
@@ -1539,6 +1564,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ObjCImplementationDecl");
case CXCursor_ObjCCategoryImplDecl:
return createCXString("ObjCCategoryImplDecl");
+ case CXCursor_CXXMethod:
+ return createCXString("CXXMethod");
case CXCursor_UnexposedDecl:
return createCXString("UnexposedDecl");
case CXCursor_ObjCSuperClassRef:
@@ -1551,6 +1578,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("TypeRef");
case CXCursor_UnexposedExpr:
return createCXString("UnexposedExpr");
+ case CXCursor_BlockExpr:
+ return createCXString("BlockExpr");
case CXCursor_DeclRefExpr:
return createCXString("DeclRefExpr");
case CXCursor_MemberRefExpr:
@@ -1892,8 +1921,6 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
// Declaration kinds that don't make any sense here, but are
// nonetheless harmless.
case Decl::TranslationUnit:
- case Decl::Template:
- case Decl::ObjCContainer:
break;
// Declaration kinds for which the definition is not resolvable.
@@ -2444,6 +2471,67 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
} // end: extern "C"
//===----------------------------------------------------------------------===//
+// Operations for querying language of a cursor.
+//===----------------------------------------------------------------------===//
+
+static CXLanguageKind getDeclLanguage(const Decl *D) {
+ switch (D->getKind()) {
+ default:
+ break;
+ case Decl::ImplicitParam:
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCForwardProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCIvar:
+ case Decl::ObjCMethod:
+ case Decl::ObjCProperty:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCProtocol:
+ return CXLanguage_ObjC;
+ case Decl::CXXConstructor:
+ case Decl::CXXConversion:
+ case Decl::CXXDestructor:
+ case Decl::CXXMethod:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplate:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::FunctionTemplate:
+ case Decl::LinkageSpec:
+ case Decl::Namespace:
+ case Decl::NamespaceAlias:
+ case Decl::NonTypeTemplateParm:
+ case Decl::StaticAssert:
+ case Decl::TemplateTemplateParm:
+ case Decl::TemplateTypeParm:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
+ case Decl::Using:
+ case Decl::UsingDirective:
+ case Decl::UsingShadow:
+ return CXLanguage_CPlusPlus;
+ }
+
+ return CXLanguage_C;
+}
+
+extern "C" {
+CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ return getDeclLanguage(cxcursor::getCursorDecl(cursor));
+
+ return CXLanguage_Invalid;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
// CXString Operations.
//===----------------------------------------------------------------------===//
diff --git a/tools/CIndex/CIndex.darwin.exports b/tools/CIndex/CIndex.darwin.exports
new file mode 100644
index 000000000000..b36116805311
--- /dev/null
+++ b/tools/CIndex/CIndex.darwin.exports
@@ -0,0 +1,81 @@
+_clang_annotateTokens
+_clang_codeComplete
+_clang_codeCompleteGetDiagnostic
+_clang_codeCompleteGetNumDiagnostics
+_clang_constructUSR_ObjCCategory
+_clang_constructUSR_ObjCClass
+_clang_constructUSR_ObjCIvar
+_clang_constructUSR_ObjCMethod
+_clang_constructUSR_ObjCProperty
+_clang_constructUSR_ObjCProtocol
+_clang_createIndex
+_clang_createTranslationUnit
+_clang_createTranslationUnitFromSourceFile
+_clang_defaultDiagnosticDisplayOptions
+_clang_disposeCodeCompleteResults
+_clang_disposeDiagnostic
+_clang_disposeIndex
+_clang_disposeString
+_clang_disposeTokens
+_clang_disposeTranslationUnit
+_clang_enableStackTraces
+_clang_equalCursors
+_clang_equalLocations
+_clang_formatDiagnostic
+_clang_getCString
+_clang_getClangVersion
+_clang_getCompletionChunkCompletionString
+_clang_getCompletionChunkKind
+_clang_getCompletionChunkText
+_clang_getCursor
+_clang_getCursorDefinition
+_clang_getCursorExtent
+_clang_getCursorKind
+_clang_getCursorKindSpelling
+_clang_getCursorLanguage
+_clang_getCursorLinkage
+_clang_getCursorLocation
+_clang_getCursorReferenced
+_clang_getCursorSpelling
+_clang_getCursorUSR
+_clang_getDefinitionSpellingAndExtent
+_clang_getDiagnostic
+_clang_getDiagnosticFixIt
+_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_getNumDiagnostics
+_clang_getRange
+_clang_getRangeEnd
+_clang_getRangeStart
+_clang_getTokenExtent
+_clang_getTokenKind
+_clang_getTokenLocation
+_clang_getTokenSpelling
+_clang_getTranslationUnitCursor
+_clang_getTranslationUnitSpelling
+_clang_isCursorDefinition
+_clang_isDeclaration
+_clang_isExpression
+_clang_isInvalid
+_clang_isPreprocessing
+_clang_isReference
+_clang_isStatement
+_clang_isTranslationUnit
+_clang_isUnexposed
+_clang_setUseExternalASTGeneration
+_clang_tokenize
+_clang_visitChildren
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index d036e5cfd8f2..991bb067f7d0 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -1,80 +1,81 @@
-_clang_annotateTokens
-_clang_codeComplete
-_clang_codeCompleteGetDiagnostic
-_clang_codeCompleteGetNumDiagnostics
-_clang_constructUSR_ObjCClass
-_clang_constructUSR_ObjCCategory
-_clang_constructUSR_ObjCIvar
-_clang_constructUSR_ObjCMethod
-_clang_constructUSR_ObjCProtocol
-_clang_constructUSR_ObjCProperty
-_clang_createIndex
-_clang_createTranslationUnit
-_clang_createTranslationUnitFromSourceFile
-_clang_defaultDiagnosticDisplayOptions
-_clang_disposeCodeCompleteResults
-_clang_disposeDiagnostic
-_clang_disposeIndex
-_clang_disposeString
-_clang_disposeTokens
-_clang_disposeTranslationUnit
-_clang_enableStackTraces
-_clang_equalCursors
-_clang_equalLocations
-_clang_formatDiagnostic
-_clang_getClangVersion
-_clang_getCString
-_clang_getCompletionChunkCompletionString
-_clang_getCompletionChunkKind
-_clang_getCompletionChunkText
-_clang_getCursor
-_clang_getCursorDefinition
-_clang_getCursorExtent
-_clang_getCursorKind
-_clang_getCursorKindSpelling
-_clang_getCursorLinkage
-_clang_getCursorLocation
-_clang_getCursorReferenced
-_clang_getCursorSpelling
-_clang_getCursorUSR
-_clang_getDefinitionSpellingAndExtent
-_clang_getDiagnostic
-_clang_getDiagnosticFixIt
-_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_getNumDiagnostics
-_clang_getRange
-_clang_getRangeEnd
-_clang_getRangeStart
-_clang_getTokenExtent
-_clang_getTokenKind
-_clang_getTokenLocation
-_clang_getTokenSpelling
-_clang_getTranslationUnitCursor
-_clang_getTranslationUnitSpelling
-_clang_isCursorDefinition
-_clang_isDeclaration
-_clang_isExpression
-_clang_isInvalid
-_clang_isPreprocessing
-_clang_isReference
-_clang_isStatement
-_clang_isTranslationUnit
-_clang_isUnexposed
-_clang_setUseExternalASTGeneration
-_clang_tokenize
-_clang_visitChildren
+clang_annotateTokens
+clang_codeComplete
+clang_codeCompleteGetDiagnostic
+clang_codeCompleteGetNumDiagnostics
+clang_constructUSR_ObjCCategory
+clang_constructUSR_ObjCClass
+clang_constructUSR_ObjCIvar
+clang_constructUSR_ObjCMethod
+clang_constructUSR_ObjCProperty
+clang_constructUSR_ObjCProtocol
+clang_createIndex
+clang_createTranslationUnit
+clang_createTranslationUnitFromSourceFile
+clang_defaultDiagnosticDisplayOptions
+clang_disposeCodeCompleteResults
+clang_disposeDiagnostic
+clang_disposeIndex
+clang_disposeString
+clang_disposeTokens
+clang_disposeTranslationUnit
+clang_enableStackTraces
+clang_equalCursors
+clang_equalLocations
+clang_formatDiagnostic
+clang_getCString
+clang_getClangVersion
+clang_getCompletionChunkCompletionString
+clang_getCompletionChunkKind
+clang_getCompletionChunkText
+clang_getCursor
+clang_getCursorDefinition
+clang_getCursorExtent
+clang_getCursorKind
+clang_getCursorKindSpelling
+clang_getCursorLanguage
+clang_getCursorLinkage
+clang_getCursorLocation
+clang_getCursorReferenced
+clang_getCursorSpelling
+clang_getCursorUSR
+clang_getDefinitionSpellingAndExtent
+clang_getDiagnostic
+clang_getDiagnosticFixIt
+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_getNumDiagnostics
+clang_getRange
+clang_getRangeEnd
+clang_getRangeStart
+clang_getTokenExtent
+clang_getTokenKind
+clang_getTokenLocation
+clang_getTokenSpelling
+clang_getTranslationUnitCursor
+clang_getTranslationUnitSpelling
+clang_isCursorDefinition
+clang_isDeclaration
+clang_isExpression
+clang_isInvalid
+clang_isPreprocessing
+clang_isReference
+clang_isStatement
+clang_isTranslationUnit
+clang_isUnexposed
+clang_setUseExternalASTGeneration
+clang_tokenize
+clang_visitChildren
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
index d11b8dfb50f7..a21614c74735 100644
--- a/tools/CIndex/CIndexCodeCompletion.cpp
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -14,12 +14,26 @@
#include "CIndexer.h"
#include "CIndexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Program.h"
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
using namespace clang;
using namespace clang::cxstring;
@@ -226,6 +240,12 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
const char *complete_filename,
unsigned complete_line,
unsigned complete_column) {
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
+ const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
+#endif
+#endif
+
// The indexer, which is mainly used to determine where diagnostics go.
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
@@ -383,6 +403,78 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
// destroyed.
Results->TemporaryFiles.swap(TemporaryFiles);
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
+ const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
+ llvm::SmallString<256> LogResult;
+ llvm::raw_svector_ostream os(LogResult);
+
+ // Figure out the language and whether or not it uses PCH.
+ const char *lang = 0;
+ bool usesPCH = false;
+
+ for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
+ I != E; ++I) {
+ if (*I == 0)
+ continue;
+ if (strcmp(*I, "-x") == 0) {
+ if (I + 1 != E) {
+ lang = *(++I);
+ continue;
+ }
+ }
+ else if (strcmp(*I, "-include") == 0) {
+ if (I+1 != E) {
+ const char *arg = *(++I);
+ llvm::SmallString<512> pchName;
+ {
+ llvm::raw_svector_ostream os(pchName);
+ os << arg << ".pth";
+ }
+ pchName.push_back('\0');
+ struct stat stat_results;
+ if (stat(pchName.data(), &stat_results) == 0)
+ usesPCH = true;
+ continue;
+ }
+ }
+ }
+
+ os << "{ ";
+ os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
+ os << ", \"numRes\": " << Results->NumResults;
+ os << ", \"diags\": " << Results->Diagnostics.size();
+ os << ", \"pch\": " << (usesPCH ? "true" : "false");
+ os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
+ const char *name = getlogin();
+ os << ", \"user\": \"" << (name ? name : "unknown") << '"';
+ os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
+ os << " }";
+
+ llvm::StringRef res = os.str();
+ if (res.size() > 0) {
+ do {
+ // Setup the UDP socket.
+ struct sockaddr_in servaddr;
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
+ if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
+ &servaddr.sin_addr) <= 0)
+ break;
+
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0)
+ break;
+
+ sendto(sockfd, res.data(), res.size(), 0,
+ (struct sockaddr *)&servaddr, sizeof(servaddr));
+ close(sockfd);
+ }
+ while (false);
+ }
+#endif
+#endif
return Results;
}
diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp
index bcf066daf217..3db37b97da14 100644
--- a/tools/CIndex/CIndexDiagnostic.cpp
+++ b/tools/CIndex/CIndexDiagnostic.cpp
@@ -14,6 +14,7 @@
#include "CIndexer.h"
#include "CXSourceLocation.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
diff --git a/tools/CIndex/CIndexDiagnostic.h b/tools/CIndex/CIndexDiagnostic.h
index 79a5df03812d..919c21cfdbe4 100644
--- a/tools/CIndex/CIndexDiagnostic.h
+++ b/tools/CIndex/CIndexDiagnostic.h
@@ -13,20 +13,21 @@
#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"
-#include "llvm/ADT/SmallVector.h"
+struct CXUnsavedFile;
-namespace llvm { namespace sys {
-class Path;
-} }
+namespace llvm {
+template<typename T> class SmallVectorImpl;
+namespace sys { class Path; }
+}
namespace clang {
class Diagnostic;
+class FileManager;
class LangOptions;
class Preprocessor;
+class StoredDiagnostic;
+class SourceManager;
/// \brief The storage behind a CXDiagnostic
struct CXStoredDiagnostic {
diff --git a/tools/CIndex/CIndexInclusionStack.cpp b/tools/CIndex/CIndexInclusionStack.cpp
index 4a884e588432..e86323956f91 100644
--- a/tools/CIndex/CIndexInclusionStack.cpp
+++ b/tools/CIndex/CIndexInclusionStack.cpp
@@ -15,8 +15,10 @@
#include "CIndexer.h"
#include "CXSourceLocation.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+using namespace clang;
extern "C" {
void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index 379320c31c85..58870b930b19 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -14,9 +14,12 @@
#include "CIndexer.h"
#include "CXCursor.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+using namespace clang;
using namespace clang::cxstring;
//===----------------------------------------------------------------------===//
@@ -27,8 +30,10 @@ namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
llvm::raw_ostream &Out;
bool IgnoreResults;
+ ASTUnit *AU;
public:
- USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {}
+ USRGenerator(ASTUnit *au, llvm::raw_ostream &out)
+ : Out(out), IgnoreResults(false), AU(au) {}
bool ignoreResults() const { return IgnoreResults; }
@@ -39,12 +44,19 @@ public:
void VisitFunctionDecl(FunctionDecl *D);
void VisitNamedDecl(NamedDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *CD);
void VisitObjCContainerDecl(ObjCContainerDecl *CD);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P);
void VisitObjCMethodDecl(ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitTagDecl(TagDecl *D);
void VisitTypedefDecl(TypedefDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ /// Generate the string component containing the location of the
+ /// declaration.
+ void GenLoc(const Decl *D);
/// String generation methods used both by the visitation methods
/// and from other clients that want to directly generate USRs. These
@@ -78,10 +90,10 @@ private:
llvm::raw_svector_ostream Out;
USRGenerator UG;
public:
- StringUSRGenerator()
- : Out(StrBuf), UG(Out) {
+ StringUSRGenerator(const CXCursor *C = 0)
+ : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) {
// Add the USR space prefix.
- Out << "c:";
+ Out << "c:";
}
llvm::StringRef str() {
@@ -106,7 +118,7 @@ public:
void USRGenerator::VisitBlockDecl(BlockDecl *D) {
VisitDeclContext(D->getDeclContext());
// FIXME: Better support for anonymous blocks.
- Out << "@B^anon";
+ Out << "@B@anon";
}
void USRGenerator::VisitDeclContext(DeclContext *DC) {
@@ -122,24 +134,48 @@ void USRGenerator::VisitFieldDecl(FieldDecl *D) {
return;
}
VisitDeclContext(D->getDeclContext());
- Out << "@^FI^" << s;
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s;
}
void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
VisitDeclContext(D->getDeclContext());
- Out << "@F^" << D->getNameAsString();
+ Out << "@F@" << D;
}
void USRGenerator::VisitNamedDecl(NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
const std::string &s = D->getNameAsString();
- // assert(!s.empty());
- GenNamedDecl(s);
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ GenNamedDecl(s);
+}
+
+void USRGenerator::VisitVarDecl(VarDecl *D) {
+ // VarDecls can be declared 'extern' within a function or method body,
+ // but their enclosing DeclContext is the function, not the TU. We need
+ // to check the storage class to correctly generate the USR.
+ if (!D->hasExternalStorage())
+ VisitDeclContext(D->getDeclContext());
+
+ const std::string &s = D->getNameAsString();
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ GenNamedDecl(s);
}
void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
VisitDeclContext(D->getDeclContext());
- Out << "@N^" << D->getNameAsString();
+ Out << "@N@" << D;
}
void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
@@ -148,6 +184,18 @@ void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
D->isInstanceMethod());
}
+void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
+ // FIXME: @class declarations can refer to multiple classes. We need
+ // to be able to traverse these.
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ // FIXME: @protocol declarations can refer to multiple protocols. We need
+ // to be able to traverse these.
+ IgnoreResults = true;
+}
+
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
switch (D->getKind()) {
default:
@@ -195,32 +243,85 @@ void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
GenObjCProperty(D->getName());
}
+void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
+ VisitObjCPropertyDecl(PD);
+ return;
+ }
+
+ IgnoreResults = true;
+}
+
void USRGenerator::VisitTagDecl(TagDecl *D) {
+ D = D->getCanonicalDecl();
VisitDeclContext(D->getDeclContext());
switch (D->getTagKind()) {
- case TagDecl::TK_struct: Out << "@S^"; break;
- case TagDecl::TK_class: Out << "@C^"; break;
- case TagDecl::TK_union: Out << "@U^"; break;
- case TagDecl::TK_enum: Out << "@E^"; break;
+ case TagDecl::TK_struct: Out << "@S"; break;
+ case TagDecl::TK_class: Out << "@C"; break;
+ case TagDecl::TK_union: Out << "@U"; break;
+ case TagDecl::TK_enum: Out << "@E"; break;
}
- // FIXME: Better support for anonymous structures and enums.
const std::string &s = D->getNameAsString();
+ const TypedefDecl *TD = 0;
if (s.empty()) {
- if (TypedefDecl *TD = D->getTypedefForAnonDecl())
- Out << "^anontd^" << TD->getNameAsString();
- else
- Out << "^anon";
+ TD = D->getTypedefForAnonDecl();
+ Out << (TD ? 'A' : 'a');
+ }
+
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (D->getLinkage() == NoLinkage) {
+ Out << '@';
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ }
+
+ if (s.empty()) {
+ if (TD)
+ Out << '@' << TD;
}
else
- Out << s;
+ Out << '@' << s;
}
void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
DeclContext *DC = D->getDeclContext();
if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
Visit(DCN);
- Out << "typedef@" << D->getName();
+ Out << "@T@";
+ if (D->getLinkage() == NoLinkage) {
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ Out << '@';
+ }
+ Out << D->getName();
+}
+
+void USRGenerator::GenLoc(const Decl *D) {
+ const SourceManager &SM = AU->getSourceManager();
+ SourceLocation L = D->getLocStart();
+ if (L.isInvalid()) {
+ IgnoreResults = true;
+ return;
+ }
+ L = SM.getInstantiationLoc(L);
+ const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
+ const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+ if (FE) {
+ llvm::sys::Path P(FE->getName());
+ Out << P.getLast();
+ }
+ else {
+ // This case really isn't interesting.
+ IgnoreResults = true;
+ return;
+ }
+ Out << '@'
+ << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':'
+ << SM.getColumnNumber(Decomposed.first, Decomposed.second);
}
//===----------------------------------------------------------------------===//
@@ -228,7 +329,7 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
//===----------------------------------------------------------------------===//
void USRGenerator::GenNamedDecl(llvm::StringRef name) {
- Out << "@^" << name;
+ Out << "@" << name;
}
void USRGenerator::GenObjCClass(llvm::StringRef cls) {
@@ -236,7 +337,7 @@ void USRGenerator::GenObjCClass(llvm::StringRef cls) {
}
void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
- Out << "objc(cy)" << cls << '^' << cat;
+ Out << "objc(cy)" << cls << '@' << cat;
}
void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
@@ -259,29 +360,69 @@ void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
// API hooks.
//===----------------------------------------------------------------------===//
-extern "C" {
+static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
+ return s.startswith("c:") ? s.substr(2) : "";
+}
-CXString clang_getCursorUSR(CXCursor C) {
+static CXString getDeclCursorUSR(const CXCursor &C) {
Decl *D = cxcursor::getCursorDecl(C);
- if (!D)
- return createCXString(NULL);
- StringUSRGenerator SUG;
- SUG->Visit(static_cast<Decl*>(D));
+ // Don't generate USRs for things with invalid locations.
+ if (!D || D->getLocStart().isInvalid())
+ return createCXString("");
+
+ // Check if the cursor has 'NoLinkage'.
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ switch (ND->getLinkage()) {
+ case ExternalLinkage:
+ // Generate USRs for all entities with external linkage.
+ break;
+ case NoLinkage:
+ // We allow enums, typedefs, and structs that have no linkage to
+ // have USRs that are anchored to the file they were defined in
+ // (e.g., the header). This is a little gross, but in principal
+ // enums/anonymous structs/etc. defined in a common header file
+ // are referred to across multiple translation units.
+ if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
+ isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND))
+ break;
+ // Fall-through.
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return createCXString("");
+ }
+
+ StringUSRGenerator SUG(&C);
+ SUG->Visit(D);
if (SUG->ignoreResults())
return createCXString("");
- // Return a copy of the string that must be disposed by the caller.
+ // For development testing.
+ // assert(SUG.str().size() > 2);
+
+ // Return a copy of the string that must be disposed by the caller.
return createCXString(SUG.str(), true);
}
-static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
- if (!(s.size() >= 2 && s[0] == 'c' && s[1] == ':'))
- return "";
- return s.substr(2);
+extern "C" {
+
+CXString clang_getCursorUSR(CXCursor C) {
+ const CXCursorKind &K = clang_getCursorKind(C);
+
+ if (clang_isDeclaration(K))
+ return getDeclCursorUSR(C);
+
+ if (K == CXCursor_MacroDefinition) {
+ StringUSRGenerator SUG(&C);
+ SUG << "macro@"
+ << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
+ return createCXString(SUG.str(), true);
+ }
+
+ return createCXString("");
}
-
+
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
StringUSRGenerator SUG;
SUG << extractUSRSuffix(clang_getCString(classUSR));
diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp
index 0774ae2f3722..d5131ff6d869 100644
--- a/tools/CIndex/CIndexer.cpp
+++ b/tools/CIndex/CIndexer.cpp
@@ -38,7 +38,6 @@
#endif
using namespace clang;
-using namespace idx;
const llvm::sys::Path& CIndexer::getClangPath() {
// Did we already compute the path?
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
index 1fa3ca93876e..31bf779ea4a5 100644
--- a/tools/CIndex/CIndexer.h
+++ b/tools/CIndex/CIndexer.h
@@ -16,14 +16,10 @@
#define LLVM_CLANG_CINDEXER_H
#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;
-
namespace clang {
namespace cxstring {
CXString createCXString(const char *String, bool DupString = false);
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
index 6aa7a579839f..609719e627fd 100644
--- a/tools/CIndex/CMakeLists.txt
+++ b/tools/CIndex/CMakeLists.txt
@@ -32,9 +32,13 @@ add_clang_library(CIndex
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# FIXME: Deal with LLVM_SUBMIT_VERSION?
+ # FIXME: This uses a special darwin-specific exports file in order to
+ # get underscore-prefixed names. It would be better to have build rules
+ # which know how to produce a darwin-suitable exports file from the
+ # regular exports file.
set_target_properties(CIndex
PROPERTIES
- LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/CIndex.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000"
+ LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/CIndex.darwin.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000"
INSTALL_NAME_DIR "@executable_path/../lib"
)
endif()
diff --git a/tools/CIndex/CXCursor.cpp b/tools/CIndex/CXCursor.cpp
index cbf9d7e6f919..3bc5d01fbada 100644
--- a/tools/CIndex/CXCursor.cpp
+++ b/tools/CIndex/CXCursor.cpp
@@ -50,6 +50,7 @@ static CXCursorKind GetCursorKind(Decl *D) {
case Decl::ObjCMethod:
return cast<ObjCMethodDecl>(D)->isInstanceMethod()
? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl;
+ case Decl::CXXMethod: return CXCursor_CXXMethod;
case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl;
case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
case Decl::ParmVar: return CXCursor_ParmDecl;
@@ -159,7 +160,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) {
case Stmt::TypesCompatibleExprClass:
case Stmt::ChooseExprClass:
case Stmt::GNUNullExprClass:
- case Stmt::CXXNamedCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXReinterpretCastExprClass:
diff --git a/tools/CIndex/CXSourceLocation.h b/tools/CIndex/CXSourceLocation.h
index 8bfc6f9da7ab..66566c126891 100644
--- a/tools/CIndex/CXSourceLocation.h
+++ b/tools/CIndex/CXSourceLocation.h
@@ -16,13 +16,12 @@
#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;
+
+class SourceManager;
namespace cxloc {
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
index 650bcd3645d2..391746d4d4fd 100644
--- a/tools/CIndex/Makefile
+++ b/tools/CIndex/Makefile
@@ -10,6 +10,8 @@
LEVEL = ../../../..
LIBRARYNAME = CIndex
+EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/CIndex.exports
+
CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
# Include this here so we can get the configuration of the targets
@@ -40,7 +42,6 @@ ifeq ($(HOST_OS),Darwin)
# extra options to override libtool defaults
LLVMLibsOptions := $(LLVMLibsOptions) \
-avoid-version \
- -Wl,-exported_symbols_list -Wl,$(PROJ_SRC_DIR)/CIndex.exports \
-Wl,-dead_strip \
-Wl,-seg1addr -Wl,0xE0000000
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 64c3a213cd78..ae33b782d49d 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,3 +1,3 @@
-add_subdirectory(CIndex)
+add_subdirectory(libclang)
add_subdirectory(c-index-test)
add_subdirectory(driver)
diff --git a/tools/Makefile b/tools/Makefile
index bfd5ad12f93d..8407dfdedde7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,12 +8,12 @@
##===----------------------------------------------------------------------===##
LEVEL := ../../..
-DIRS := driver CIndex c-index-test
+DIRS := driver libclang c-index-test
include $(LEVEL)/Makefile.config
ifeq ($(OS), $(filter $(OS), Cygwin MingW))
-DIRS := $(filter-out CIndex c-index-test, $(DIRS))
+DIRS := $(filter-out libclang c-index-test, $(DIRS))
endif
include $(LEVEL)/Makefile.common
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index f0a34a57987e..d965fd2b51e2 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -1,7 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
- CIndex
+ libclang
clangIndex
clangFrontend
clangDriver
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index e9ba174275a4..24fed16006dd 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
-NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
@@ -18,7 +17,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := bitreader mc core
-USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangDriver.a clangSema.a \
+USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a clangSema.a \
clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index d7f3483ffbfd..494181675c5a 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -372,12 +372,13 @@ enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
VisitorData *Data = (VisitorData *)ClientData;
if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
CXString USR = clang_getCursorUSR(C);
- if (!clang_getCString(USR)) {
+ const char *cstr = clang_getCString(USR);
+ if (!cstr || cstr[0] == '\0') {
clang_disposeString(USR);
- return CXChildVisit_Continue;
+ return CXChildVisit_Recurse;
}
- printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C),
- clang_getCString(USR));
+ printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
+
PrintCursorExtent(C);
printf("\n");
clang_disposeString(USR);
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index c4320b0c905c..ca2f4081aa9f 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -30,6 +30,7 @@ add_clang_executable(clang
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
+ set(CLANGXX_DESTDIR $ENV{DESTDIR}/)
else()
set(CLANGXX_LINK_OR_COPY copy)
endif()
@@ -45,4 +46,4 @@ install(TARGETS clang
RUNTIME DESTINATION bin)
# Create the clang++ symlink at installation time.
-install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"\$ENV{DESTDIR}/\${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
+install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index dd440f5227b4..144a734b151d 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -64,7 +64,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case ASTPrintXML: return new ASTPrintXMLAction();
case ASTView: return new ASTViewAction();
case DumpRawTokens: return new DumpRawTokensAction();
- case DumpRecordLayouts: return new DumpRecordAction();
case DumpTokens: return new DumpTokensAction();
case EmitAssembly: return new EmitAssemblyAction();
case EmitBC: return new EmitBCAction();
@@ -199,7 +198,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
- Clang->setLLVMContext(new llvm::LLVMContext);
+ Clang->setLLVMContext(new llvm::LLVMContext());
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") {
@@ -242,6 +241,19 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
return 0;
}
+ // Honor -mllvm.
+ //
+ // FIXME: Remove this, one day.
+ if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
+ unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
+ const char **Args = new const char*[NumArgs + 2];
+ Args[0] = "clang (LLVM option parsing)";
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
+ Args[NumArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
+ }
+
// Create the actual diagnostics engine.
Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin));
if (!Clang->hasDiagnostics())
@@ -249,7 +261,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
- llvm::llvm_install_error_handler(LLVMErrorHandler,
+ llvm::install_fatal_error_handler(LLVMErrorHandler,
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer.FlushDiagnostics(Clang->getDiagnostics());
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
new file mode 100644
index 000000000000..f9f735113f7a
--- /dev/null
+++ b/tools/libclang/CIndex.cpp
@@ -0,0 +1,2598 @@
+//===- CIndex.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 implements the main API hooks in the Clang-C Source Indexing
+// library.
+//
+//===----------------------------------------------------------------------===//
+
+#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/Basic/Diagnostic.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Program.h"
+#include "llvm/System/Signals.h"
+
+// Needed to define L_TMPNAM on some systems.
+#include <cstdio>
+
+using namespace clang;
+using namespace clang::cxcursor;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Crash Reporting.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+#define USE_CRASHTRACER
+#include "clang/Analysis/Support/SaveAndRestore.h"
+// Integrate with crash reporter.
+extern "C" const char *__crashreporter_info__;
+#define NUM_CRASH_STRINGS 32
+static unsigned crashtracer_counter = 0;
+static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 };
+static const char *crashtracer_strings[NUM_CRASH_STRINGS] = { 0 };
+static const char *agg_crashtracer_strings[NUM_CRASH_STRINGS] = { 0 };
+
+static unsigned SetCrashTracerInfo(const char *str,
+ llvm::SmallString<1024> &AggStr) {
+
+ unsigned slot = 0;
+ while (crashtracer_strings[slot]) {
+ if (++slot == NUM_CRASH_STRINGS)
+ slot = 0;
+ }
+ crashtracer_strings[slot] = str;
+ crashtracer_counter_id[slot] = ++crashtracer_counter;
+
+ // We need to create an aggregate string because multiple threads
+ // may be in this method at one time. The crash reporter string
+ // will attempt to overapproximate the set of in-flight invocations
+ // of this function. Race conditions can still cause this goal
+ // to not be achieved.
+ {
+ llvm::raw_svector_ostream Out(AggStr);
+ for (unsigned i = 0; i < NUM_CRASH_STRINGS; ++i)
+ if (crashtracer_strings[i]) Out << crashtracer_strings[i] << '\n';
+ }
+ __crashreporter_info__ = agg_crashtracer_strings[slot] = AggStr.c_str();
+ return slot;
+}
+
+static void ResetCrashTracerInfo(unsigned slot) {
+ unsigned max_slot = 0;
+ unsigned max_value = 0;
+
+ crashtracer_strings[slot] = agg_crashtracer_strings[slot] = 0;
+
+ for (unsigned i = 0 ; i < NUM_CRASH_STRINGS; ++i)
+ if (agg_crashtracer_strings[i] &&
+ crashtracer_counter_id[i] > max_value) {
+ max_slot = i;
+ max_value = crashtracer_counter_id[i];
+ }
+
+ __crashreporter_info__ = agg_crashtracer_strings[max_slot];
+}
+
+namespace {
+class ArgsCrashTracerInfo {
+ llvm::SmallString<1024> CrashString;
+ llvm::SmallString<1024> AggregateString;
+ unsigned crashtracerSlot;
+public:
+ ArgsCrashTracerInfo(llvm::SmallVectorImpl<const char*> &Args)
+ : crashtracerSlot(0)
+ {
+ {
+ llvm::raw_svector_ostream Out(CrashString);
+ Out << "ClangCIndex [" << getClangFullVersion() << "]"
+ << "[createTranslationUnitFromSourceFile]: clang";
+ for (llvm::SmallVectorImpl<const char*>::iterator I=Args.begin(),
+ E=Args.end(); I!=E; ++I)
+ Out << ' ' << *I;
+ }
+ crashtracerSlot = SetCrashTracerInfo(CrashString.c_str(),
+ AggregateString);
+ }
+
+ ~ArgsCrashTracerInfo() {
+ ResetCrashTracerInfo(crashtracerSlot);
+ }
+};
+}
+#endif
+
+/// \brief The result of comparing two source ranges.
+enum RangeComparisonResult {
+ /// \brief Either the ranges overlap or one of the ranges is invalid.
+ RangeOverlap,
+
+ /// \brief The first range ends before the second range starts.
+ RangeBefore,
+
+ /// \brief The first range starts after the second range ends.
+ RangeAfter
+};
+
+/// \brief Compare two source ranges to determine their relative position in
+/// the translation unit.
+static RangeComparisonResult RangeCompare(SourceManager &SM,
+ SourceRange R1,
+ SourceRange R2) {
+ assert(R1.isValid() && "First range is invalid?");
+ assert(R2.isValid() && "Second range is invalid?");
+ if (R1.getEnd() == R2.getBegin() ||
+ SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
+ return RangeBefore;
+ 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) {
+ // We want the last character in this location, so we will adjust the
+ // location accordingly.
+ // FIXME: How do do this with a macro instantiation location?
+ SourceLocation EndLoc = R.getEnd();
+ if (!EndLoc.isInvalid() && EndLoc.isFileID()) {
+ unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
+ EndLoc = EndLoc.getFileLocWithOffset(Length);
+ }
+
+ CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
+ R.getBegin().getRawEncoding(),
+ EndLoc.getRawEncoding() };
+ return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Cursor visitor.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+// Cursor visitor.
+class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
+ public TypeLocVisitor<CursorVisitor, bool>,
+ public StmtVisitor<CursorVisitor, bool>
+{
+ /// \brief The translation unit we are traversing.
+ ASTUnit *TU;
+
+ /// \brief The parent cursor whose children we are traversing.
+ CXCursor Parent;
+
+ /// \brief The declaration that serves at the parent of any statement or
+ /// expression nodes.
+ Decl *StmtParent;
+
+ /// \brief The visitor function.
+ CXCursorVisitor Visitor;
+
+ /// \brief The opaque client data, to be passed along to the visitor.
+ CXClientData ClientData;
+
+ // MaxPCHLevel - the maximum PCH level of declarations that we will pass on
+ // to the visitor. Declarations with a PCH level greater than this value will
+ // be suppressed.
+ unsigned MaxPCHLevel;
+
+ /// \brief When valid, a source range to which the cursor should restrict
+ /// its search.
+ SourceRange RegionOfInterest;
+
+ using DeclVisitor<CursorVisitor, bool>::Visit;
+ using TypeLocVisitor<CursorVisitor, bool>::Visit;
+ using StmtVisitor<CursorVisitor, bool>::Visit;
+
+ /// \brief Determine whether this particular source range comes before, comes
+ /// after, or overlaps the region of interest.
+ ///
+ /// \param R a half-open source range retrieved from the abstract syntax tree.
+ RangeComparisonResult CompareRegionOfInterest(SourceRange R);
+
+public:
+ CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData,
+ unsigned MaxPCHLevel,
+ SourceRange RegionOfInterest = SourceRange())
+ : TU(TU), Visitor(Visitor), ClientData(ClientData),
+ MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest)
+ {
+ Parent.kind = CXCursor_NoDeclFound;
+ Parent.data[0] = 0;
+ Parent.data[1] = 0;
+ Parent.data[2] = 0;
+ StmtParent = 0;
+ }
+
+ bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ getPreprocessedEntities();
+
+ bool VisitChildren(CXCursor Parent);
+
+ // Declaration visitors
+ bool VisitAttributes(Decl *D);
+ bool VisitBlockDecl(BlockDecl *B);
+ bool VisitDeclContext(DeclContext *DC);
+ bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ bool VisitTypedefDecl(TypedefDecl *D);
+ bool VisitTagDecl(TagDecl *D);
+ bool VisitEnumConstantDecl(EnumConstantDecl *D);
+ bool VisitDeclaratorDecl(DeclaratorDecl *DD);
+ bool VisitFunctionDecl(FunctionDecl *ND);
+ bool VisitFieldDecl(FieldDecl *D);
+ bool VisitVarDecl(VarDecl *);
+ bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
+ bool VisitObjCContainerDecl(ObjCContainerDecl *D);
+ bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
+ bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ bool VisitObjCImplDecl(ObjCImplDecl *D);
+ bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ bool VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ // FIXME: ObjCPropertyDecl requires TypeSourceInfo, getter/setter locations,
+ // etc.
+ // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
+ bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
+ bool VisitObjCClassDecl(ObjCClassDecl *D);
+
+ // Type visitors
+ // FIXME: QualifiedTypeLoc doesn't provide any location information
+ bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL);
+ bool VisitTypedefTypeLoc(TypedefTypeLoc TL);
+ bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL);
+ bool VisitTagTypeLoc(TagTypeLoc TL);
+ // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information
+ bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL);
+ bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL);
+ bool VisitPointerTypeLoc(PointerTypeLoc TL);
+ bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL);
+ bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL);
+ bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL);
+ bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL);
+ bool VisitFunctionTypeLoc(FunctionTypeLoc TL);
+ bool VisitArrayTypeLoc(ArrayTypeLoc TL);
+ // FIXME: Implement for TemplateSpecializationTypeLoc
+ // FIXME: Implement visitors here when the unimplemented TypeLocs get
+ // implemented
+ bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL);
+ bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL);
+
+ // Statement visitors
+ bool VisitStmt(Stmt *S);
+ bool VisitDeclStmt(DeclStmt *S);
+ // FIXME: LabelStmt label?
+ bool VisitIfStmt(IfStmt *S);
+ bool VisitSwitchStmt(SwitchStmt *S);
+ bool VisitWhileStmt(WhileStmt *S);
+ bool VisitForStmt(ForStmt *S);
+
+ // Expression visitors
+ bool VisitBlockExpr(BlockExpr *B);
+ bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ bool VisitExplicitCastExpr(ExplicitCastExpr *E);
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E);
+ bool VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+ bool VisitOffsetOfExpr(OffsetOfExpr *E);
+ bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+};
+
+} // end anonymous namespace
+
+RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
+ return RangeCompare(TU->getSourceManager(), R, RegionOfInterest);
+}
+
+/// \brief Visit the given cursor and, if requested by the visitor,
+/// its children.
+///
+/// \param Cursor the cursor to visit.
+///
+/// \param CheckRegionOfInterest if true, then the caller already checked that
+/// this cursor is within the region of interest.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
+ if (clang_isInvalid(Cursor.kind))
+ return false;
+
+ if (clang_isDeclaration(Cursor.kind)) {
+ Decl *D = getCursorDecl(Cursor);
+ assert(D && "Invalid declaration cursor");
+ if (D->getPCHLevel() > MaxPCHLevel)
+ return false;
+
+ if (D->isImplicit())
+ return false;
+ }
+
+ // If we have a range of interest, and this cursor doesn't intersect with it,
+ // we're done.
+ if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
+ SourceRange Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid() || CompareRegionOfInterest(Range))
+ return false;
+ }
+
+ switch (Visitor(Cursor, Parent, ClientData)) {
+ case CXChildVisit_Break:
+ return true;
+
+ case CXChildVisit_Continue:
+ return false;
+
+ case CXChildVisit_Recurse:
+ return VisitChildren(Cursor);
+ }
+
+ return false;
+}
+
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+CursorVisitor::getPreprocessedEntities() {
+ PreprocessingRecord &PPRec
+ = *TU->getPreprocessor().getPreprocessingRecord();
+
+ bool OnlyLocalDecls
+ = !TU->isMainFileAST() && TU->getOnlyLocalDecls();
+
+ // There is no region of interest; we have to walk everything.
+ if (RegionOfInterest.isInvalid())
+ return std::make_pair(PPRec.begin(OnlyLocalDecls),
+ PPRec.end(OnlyLocalDecls));
+
+ // Find the file in which the region of interest lands.
+ SourceManager &SM = TU->getSourceManager();
+ std::pair<FileID, unsigned> Begin
+ = SM.getDecomposedInstantiationLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> End
+ = SM.getDecomposedInstantiationLoc(RegionOfInterest.getEnd());
+
+ // The region of interest spans files; we have to walk everything.
+ if (Begin.first != End.first)
+ return std::make_pair(PPRec.begin(OnlyLocalDecls),
+ PPRec.end(OnlyLocalDecls));
+
+ ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap
+ = TU->getPreprocessedEntitiesByFile();
+ if (ByFileMap.empty()) {
+ // Build the mapping from files to sets of preprocessed entities.
+ for (PreprocessingRecord::iterator E = PPRec.begin(OnlyLocalDecls),
+ EEnd = PPRec.end(OnlyLocalDecls);
+ E != EEnd; ++E) {
+ std::pair<FileID, unsigned> P
+ = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin());
+ ByFileMap[P.first].push_back(*E);
+ }
+ }
+
+ return std::make_pair(ByFileMap[Begin.first].begin(),
+ ByFileMap[Begin.first].end());
+}
+
+/// \brief Visit the children of the given cursor.
+///
+/// \returns true if the visitation should be aborted, false if it
+/// should continue.
+bool CursorVisitor::VisitChildren(CXCursor Cursor) {
+ if (clang_isReference(Cursor.kind)) {
+ // By definition, references have no children.
+ return false;
+ }
+
+ // Set the Parent field to Cursor, then back to its old value once we're
+ // done.
+ class SetParentRAII {
+ CXCursor &Parent;
+ Decl *&StmtParent;
+ CXCursor OldParent;
+
+ public:
+ SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
+ {
+ Parent = NewParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+
+ ~SetParentRAII() {
+ Parent = OldParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+ } SetParent(Parent, StmtParent, Cursor);
+
+ if (clang_isDeclaration(Cursor.kind)) {
+ Decl *D = getCursorDecl(Cursor);
+ assert(D && "Invalid declaration cursor");
+ return VisitAttributes(D) || Visit(D);
+ }
+
+ if (clang_isStatement(Cursor.kind))
+ return Visit(getCursorStmt(Cursor));
+ if (clang_isExpression(Cursor.kind))
+ return Visit(getCursorExpr(Cursor));
+
+ if (clang_isTranslationUnit(Cursor.kind)) {
+ ASTUnit *CXXUnit = getCursorASTUnit(Cursor);
+ if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
+ RegionOfInterest.isInvalid()) {
+ const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls();
+ for (std::vector<Decl*>::const_iterator it = TLDs.begin(),
+ ie = TLDs.end(); it != ie; ++it) {
+ if (Visit(MakeCXCursor(*it, CXXUnit), true))
+ return true;
+ }
+ } else if (VisitDeclContext(
+ CXXUnit->getASTContext().getTranslationUnitDecl()))
+ return true;
+
+ // Walk the preprocessing record.
+ if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
+ // FIXME: Once we have the ability to deserialize a preprocessing record,
+ // do so.
+ PreprocessingRecord::iterator E, EEnd;
+ for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
+ if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+ if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))
+ return true;
+
+ continue;
+ }
+
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+ if (Visit(MakeMacroDefinitionCursor(MD, CXXUnit)))
+ return true;
+
+ continue;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Nothing to visit at the moment.
+ return false;
+}
+
+bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
+ for (BlockDecl::param_iterator I=B->param_begin(), E=B->param_end(); I!=E;++I)
+ if (Decl *D = *I)
+ if (Visit(D))
+ return true;
+
+ return Visit(MakeCXCursor(B->getBody(), StmtParent, TU));
+}
+
+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 Range =
+ cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor));
+ if (Range.isInvalid())
+ continue;
+
+ switch (CompareRegionOfInterest(Range)) {
+ case RangeBefore:
+ // This declaration comes before the region of interest; skip it.
+ continue;
+
+ case RangeAfter:
+ // This declaration comes after the region of interest; we're done.
+ return false;
+
+ case RangeOverlap:
+ // This declaration overlaps the region of interest; visit it.
+ break;
+ }
+ }
+
+ if (Visit(Cursor, true))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ llvm_unreachable("Translation units are visited directly by Visit()");
+ return false;
+}
+
+bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) {
+ if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitTagDecl(TagDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ if (Expr *Init = D->getInitExpr())
+ return Visit(MakeCXCursor(Init, StmtParent, TU));
+ return false;
+}
+
+bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
+ if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+ if (VisitDeclaratorDecl(ND))
+ return true;
+
+ if (ND->isThisDeclarationADefinition() &&
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitFieldDecl(FieldDecl *D) {
+ if (VisitDeclaratorDecl(D))
+ return true;
+
+ if (Expr *BitWidth = D->getBitWidth())
+ return Visit(MakeCXCursor(BitWidth, StmtParent, TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitVarDecl(VarDecl *D) {
+ if (VisitDeclaratorDecl(D))
+ return true;
+
+ if (Expr *Init = D->getInit())
+ return Visit(MakeCXCursor(Init, StmtParent, TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+ if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ for (ObjCMethodDecl::param_iterator P = ND->param_begin(),
+ PEnd = ND->param_end();
+ P != PEnd; ++P) {
+ if (Visit(MakeCXCursor(*P, TU)))
+ return true;
+ }
+
+ if (ND->isThisDeclarationADefinition() &&
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ return VisitDeclContext(D);
+}
+
+bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(),
+ TU)))
+ return true;
+
+ ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin();
+ for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(),
+ E = ND->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(ND);
+}
+
+bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin();
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(PID);
+}
+
+bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Issue callbacks for super class.
+ if (D->getSuperClass() &&
+ Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
+ D->getSuperClassLoc(),
+ TU)))
+ return true;
+
+ ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return VisitObjCContainerDecl(D);
+}
+
+bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) {
+ return VisitObjCContainerDecl(D);
+}
+
+bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ // 'ID' could be null when dealing with invalid code.
+ if (ObjCInterfaceDecl *ID = D->getClassInterface())
+ if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU)))
+ return true;
+
+ return VisitObjCImplDecl(D);
+}
+
+bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+#if 0
+ // Issue callbacks for super class.
+ // FIXME: No source location information!
+ if (D->getSuperClass() &&
+ Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
+ D->getSuperClassLoc(),
+ TU)))
+ return true;
+#endif
+
+ return VisitObjCImplDecl(D);
+}
+
+bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
+ for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I, ++PL)
+ if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
+ for (ObjCClassDecl::iterator C = D->begin(), CEnd = D->end(); C != CEnd; ++C)
+ if (Visit(MakeCursorObjCClassRef(C->getInterface(), C->getLocation(), TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ ASTContext &Context = TU->getASTContext();
+
+ // Some builtin types (such as Objective-C's "id", "sel", and
+ // "Class") have associated declarations. Create cursors for those.
+ QualType VisitType;
+ switch (TL.getType()->getAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::Bool:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ break;
+
+ case BuiltinType::UndeducedAuto: // FIXME: Deserves a cursor?
+ break;
+
+ case BuiltinType::ObjCId:
+ VisitType = Context.getObjCIdType();
+ break;
+
+ case BuiltinType::ObjCClass:
+ VisitType = Context.getObjCClassType();
+ break;
+
+ case BuiltinType::ObjCSel:
+ VisitType = Context.getObjCSelType();
+ break;
+ }
+
+ if (!VisitType.isNull()) {
+ if (const TypedefType *Typedef = VisitType->getAs<TypedefType>())
+ return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(),
+ TU));
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getTypedefDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
+ return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
+}
+
+bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)))
+ return true;
+
+ for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
+ if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
+ TU)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc()))
+ return true;
+
+ if (TL.hasProtocolsAsWritten()) {
+ for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
+ if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I),
+ TL.getProtocolLoc(I),
+ TU)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
+ return Visit(TL.getPointeeLoc());
+}
+
+bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
+ if (Visit(TL.getResultLoc()))
+ return true;
+
+ for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
+ if (Decl *D = TL.getArg(I))
+ if (Visit(MakeCXCursor(D, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
+ if (Visit(TL.getElementLoc()))
+ return true;
+
+ if (Expr *Size = TL.getSizeExpr())
+ return Visit(MakeCXCursor(Size, StmtParent, TU));
+
+ return false;
+}
+
+bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU));
+}
+
+bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
+bool CursorVisitor::VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end();
+ Child != ChildEnd; ++Child) {
+ if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitDeclStmt(DeclStmt *S) {
+ for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ if (*D && Visit(MakeCXCursor(*D, TU)))
+ return true;
+ }
+
+ return false;
+}
+
+bool CursorVisitor::VisitIfStmt(IfStmt *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->getThen() && Visit(MakeCXCursor(S->getThen(), StmtParent, TU)))
+ return true;
+ if (S->getElse() && Visit(MakeCXCursor(S->getElse(), StmtParent, TU)))
+ return true;
+
+ return false;
+}
+
+bool CursorVisitor::VisitSwitchStmt(SwitchStmt *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::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;
+
+ return false;
+}
+
+bool CursorVisitor::VisitBlockExpr(BlockExpr *B) {
+ return Visit(B->getBlockDecl());
+}
+
+bool CursorVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
+ // FIXME: Visit fields as well?
+ if (Visit(E->getTypeSourceInfo()->getTypeLoc()))
+ return true;
+
+ return VisitExpr(E);
+}
+
+bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ if (E->isArgumentType()) {
+ if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+ }
+
+ return VisitExpr(E);
+}
+
+bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ return VisitCastExpr(E);
+}
+
+bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ if (TypeSourceInfo *TSInfo = E->getTypeSourceInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ return VisitExpr(E);
+}
+
+bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (TypeSourceInfo *TSInfo = E->getClassReceiverTypeInfo())
+ if (Visit(TSInfo->getTypeLoc()))
+ return true;
+
+ return VisitExpr(E);
+}
+
+bool CursorVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+ return Visit(E->getEncodedTypeSourceInfo()->getTypeLoc());
+}
+
+
+bool CursorVisitor::VisitAttributes(Decl *D) {
+ for (const Attr *A = D->getAttrs(); A; A = A->getNext())
+ if (Visit(MakeCXCursor(A, D, TU)))
+ return true;
+
+ return false;
+}
+
+extern "C" {
+CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
+ int displayDiagnostics) {
+ CIndexer *CIdxr = new CIndexer();
+ if (excludeDeclarationsFromPCH)
+ CIdxr->setOnlyLocalDecls();
+ if (displayDiagnostics)
+ CIdxr->setDisplayDiagnostics();
+ return CIdxr;
+}
+
+void clang_disposeIndex(CXIndex CIdx) {
+ if (CIdx)
+ delete static_cast<CIndexer *>(CIdx);
+}
+
+void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) {
+ if (CIdx) {
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ CXXIdx->setUseExternalASTGeneration(value);
+ }
+}
+
+CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
+ const char *ast_filename) {
+ if (!CIdx)
+ return 0;
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
+ return ASTUnit::LoadFromPCHFile(ast_filename, Diags,
+ CXXIdx->getOnlyLocalDecls(),
+ 0, 0, true);
+}
+
+CXTranslationUnit
+clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
+ const char *source_filename,
+ int num_command_line_args,
+ const char **command_line_args,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files) {
+ if (!CIdx)
+ return 0;
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+
+ llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+ RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
+ Buffer));
+ }
+
+ if (!CXXIdx->getUseExternalASTGeneration()) {
+ llvm::SmallVector<const char *, 16> Args;
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ if (source_filename)
+ Args.push_back(source_filename);
+ Args.insert(Args.end(), command_line_args,
+ command_line_args + num_command_line_args);
+ Args.push_back("-Xclang");
+ Args.push_back("-detailed-preprocessing-record");
+ unsigned NumErrors = Diags->getNumErrors();
+
+#ifdef USE_CRASHTRACER
+ ArgsCrashTracerInfo ACTI(Args);
+#endif
+
+ llvm::OwningPtr<ASTUnit> Unit(
+ ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
+ Diags,
+ CXXIdx->getClangResourcesPath(),
+ CXXIdx->getOnlyLocalDecls(),
+ RemappedFiles.data(),
+ RemappedFiles.size(),
+ /*CaptureDiagnostics=*/true));
+
+ // FIXME: Until we have broader testing, just drop the entire AST if we
+ // encountered an error.
+ if (NumErrors != Diags->getNumErrors()) {
+ // Make sure to check that 'Unit' is non-NULL.
+ if (CXXIdx->getDisplayDiagnostics() && Unit.get()) {
+ for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
+ DEnd = Unit->stored_diag_end();
+ D != DEnd; ++D) {
+ CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions());
+ CXString Msg = clang_formatDiagnostic(&Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(Msg));
+ clang_disposeString(Msg);
+ }
+#ifdef LLVM_ON_WIN32
+ // On Windows, force a flush, since there may be multiple copies of
+ // stderr and stdout in the file system, all with different buffers
+ // but writing to the same device.
+ fflush(stderr);
+#endif
+ }
+ }
+
+ return Unit.take();
+ }
+
+ // Build up the arguments for invoking 'clang'.
+ std::vector<const char *> argv;
+
+ // First add the complete path to the 'clang' executable.
+ llvm::sys::Path ClangPath = static_cast<CIndexer *>(CIdx)->getClangPath();
+ argv.push_back(ClangPath.c_str());
+
+ // Add the '-emit-ast' option as our execution mode for 'clang'.
+ argv.push_back("-emit-ast");
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ if (source_filename)
+ argv.push_back(source_filename);
+
+ // Generate a temporary name for the AST file.
+ argv.push_back("-o");
+ char astTmpFile[L_tmpnam];
+ argv.push_back(tmpnam(astTmpFile));
+
+ // Remap any unsaved files to temporary files.
+ std::vector<llvm::sys::Path> TemporaryFiles;
+ std::vector<std::string> RemapArgs;
+ if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
+ return 0;
+
+ // The pointers into the elements of RemapArgs are stable because we
+ // won't be adding anything to RemapArgs after this point.
+ for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
+ argv.push_back(RemapArgs[i].c_str());
+
+ // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
+ for (int i = 0; i < num_command_line_args; ++i)
+ if (const char *arg = command_line_args[i]) {
+ if (strcmp(arg, "-o") == 0) {
+ ++i; // Also skip the matching argument.
+ continue;
+ }
+ if (strcmp(arg, "-emit-ast") == 0 ||
+ strcmp(arg, "-c") == 0 ||
+ strcmp(arg, "-fsyntax-only") == 0) {
+ continue;
+ }
+
+ // Keep the argument.
+ 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");
+
+ argv.push_back("-Xclang");
+ argv.push_back("-detailed-preprocessing-record");
+
+ // Add the null terminator.
+ argv.push_back(NULL);
+
+ // 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, &DevNull, &DiagnosticsFile,
+ NULL };
+ llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
+ /* redirects */ &Redirects[0],
+ /* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
+
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
+ for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
+ I != E; ++I) {
+ AllArgs += ' ';
+ if (*I)
+ AllArgs += *I;
+ }
+
+ Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
+ }
+
+ ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, Diags,
+ CXXIdx->getOnlyLocalDecls(),
+ RemappedFiles.data(),
+ RemappedFiles.size(),
+ /*CaptureDiagnostics=*/true);
+ if (ATU) {
+ LoadSerializedDiagnostics(DiagnosticsFile,
+ num_unsaved_files, unsaved_files,
+ ATU->getFileManager(),
+ ATU->getSourceManager(),
+ ATU->getStoredDiagnostics());
+ } else if (CXXIdx->getDisplayDiagnostics()) {
+ // We failed to load the ASTUnit, but we can still deserialize the
+ // diagnostics and emit them.
+ FileManager FileMgr;
+ Diagnostic Diag;
+ SourceManager SourceMgr(Diag);
+ // FIXME: Faked LangOpts!
+ LangOptions LangOpts;
+ llvm::SmallVector<StoredDiagnostic, 4> Diags;
+ LoadSerializedDiagnostics(DiagnosticsFile,
+ num_unsaved_files, unsaved_files,
+ FileMgr, SourceMgr, Diags);
+ for (llvm::SmallVector<StoredDiagnostic, 4>::iterator D = Diags.begin(),
+ DEnd = Diags.end();
+ D != DEnd; ++D) {
+ CXStoredDiagnostic Diag(*D, LangOpts);
+ CXString Msg = clang_formatDiagnostic(&Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(Msg));
+ clang_disposeString(Msg);
+ }
+
+#ifdef LLVM_ON_WIN32
+ // On Windows, force a flush, since there may be multiple copies of
+ // stderr and stdout in the file system, all with different buffers
+ // but writing to the same device.
+ fflush(stderr);
+#endif
+ }
+
+ if (ATU) {
+ // Make the translation unit responsible for destroying all temporary files.
+ for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
+ ATU->addTemporaryFile(TemporaryFiles[i]);
+ ATU->addTemporaryFile(llvm::sys::Path(ATU->getPCHFileName()));
+ } else {
+ // Destroy all of the temporary files now; they can't be referenced any
+ // longer.
+ llvm::sys::Path(astTmpFile).eraseFromDisk();
+ for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
+ TemporaryFiles[i].eraseFromDisk();
+ }
+
+ return ATU;
+}
+
+void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
+ if (CTUnit)
+ delete static_cast<ASTUnit *>(CTUnit);
+}
+
+CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
+ if (!CTUnit)
+ return createCXString("");
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+ return createCXString(CXXUnit->getOriginalSourceFileName(), true);
+}
+
+CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
+ CXCursor Result = { CXCursor_TranslationUnit, { 0, 0, TU } };
+ return Result;
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXSourceLocation and CXSourceRange Operations.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXSourceLocation clang_getNullLocation() {
+ CXSourceLocation Result = { { 0, 0 }, 0 };
+ return Result;
+}
+
+unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
+ 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,
+ CXFile file,
+ unsigned line,
+ unsigned column) {
+ if (!tu || !file)
+ return clang_getNullLocation();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu);
+ SourceLocation SLoc
+ = CXXUnit->getSourceManager().getLocation(
+ static_cast<const FileEntry *>(file),
+ line, column);
+
+ 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[0] != end.ptr_data[0] ||
+ begin.ptr_data[1] != end.ptr_data[1])
+ return clang_getNullRange();
+
+ 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,
+ unsigned *offset) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
+ if (file)
+ *file = 0;
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+ }
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation InstLoc = SM.getInstantiationLoc(Loc);
+
+ if (file)
+ *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc));
+ if (line)
+ *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[0], range.ptr_data[1] },
+ range.begin_int_data };
+ return Result;
+}
+
+CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.end_int_data };
+ return Result;
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXFile Operations.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXString clang_getFileName(CXFile SFile) {
+ if (!SFile)
+ return createCXString(NULL);
+
+ FileEntry *FEnt = static_cast<FileEntry *>(SFile);
+ return createCXString(FEnt->getName());
+}
+
+time_t clang_getFileTime(CXFile SFile) {
+ if (!SFile)
+ return 0;
+
+ FileEntry *FEnt = static_cast<FileEntry *>(SFile);
+ return FEnt->getModificationTime();
+}
+
+CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
+ if (!tu)
+ return 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu);
+
+ FileManager &FMgr = CXXUnit->getFileManager();
+ const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name));
+ return const_cast<FileEntry *>(File);
+}
+
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXCursor Operations.
+//===----------------------------------------------------------------------===//
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+ if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ return OME->getMethodDecl();
+
+ 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,
+ CXCursorVisitor visitor,
+ CXClientData client_data) {
+ ASTUnit *CXXUnit = getCursorASTUnit(parent);
+
+ unsigned PCHLevel = Decl::MaxPCHLevel;
+
+ // Set the PCHLevel to filter out unwanted decls if requested.
+ if (CXXUnit->getOnlyLocalDecls()) {
+ PCHLevel = 0;
+
+ // If the main input was an AST, bump the level.
+ if (CXXUnit->isMainFileAST())
+ ++PCHLevel;
+ }
+
+ CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel);
+ return CursorVis.VisitChildren(parent);
+}
+
+static CXString getDeclSpelling(Decl *D) {
+ NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D);
+ if (!ND)
+ return createCXString("");
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ return createCXString(OMD->getSelector().getAsString());
+
+ if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
+ // No, this isn't the same as the code below. getIdentifier() is non-virtual
+ // and returns different names. NamedDecl returns the class name and
+ // ObjCCategoryImplDecl returns the category name.
+ return createCXString(CIMP->getIdentifier()->getNameStart());
+
+ if (ND->getIdentifier())
+ return createCXString(ND->getIdentifier()->getNameStart());
+
+ return createCXString("");
+}
+
+CXString clang_getCursorSpelling(CXCursor C) {
+ if (clang_isTranslationUnit(C.kind))
+ return clang_getTranslationUnitSpelling(C.data[2]);
+
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef: {
+ ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first;
+ return createCXString(Super->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCClassRef: {
+ ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ return createCXString(Class->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first;
+ assert(OID && "getCursorSpelling(): Missing protocol decl");
+ return createCXString(OID->getIdentifier()->getNameStart());
+ }
+ case CXCursor_TypeRef: {
+ TypeDecl *Type = getCursorTypeRef(C).first;
+ assert(Type && "Missing type decl");
+
+ return createCXString(getCursorContext(C).getTypeDeclType(Type).
+ getAsString());
+ }
+
+ default:
+ return createCXString("<not implemented>");
+ }
+ }
+
+ if (clang_isExpression(C.kind)) {
+ Decl *D = getDeclFromExpr(getCursorExpr(C));
+ if (D)
+ return getDeclSpelling(D);
+ return createCXString("");
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation)
+ return createCXString(getCursorMacroInstantiation(C)->getName()
+ ->getNameStart());
+
+ if (C.kind == CXCursor_MacroDefinition)
+ return createCXString(getCursorMacroDefinition(C)->getName()
+ ->getNameStart());
+
+ if (clang_isDeclaration(C.kind))
+ return getDeclSpelling(getCursorDecl(C));
+
+ return createCXString("");
+}
+
+CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
+ switch (Kind) {
+ case CXCursor_FunctionDecl:
+ return createCXString("FunctionDecl");
+ case CXCursor_TypedefDecl:
+ return createCXString("TypedefDecl");
+ case CXCursor_EnumDecl:
+ return createCXString("EnumDecl");
+ case CXCursor_EnumConstantDecl:
+ return createCXString("EnumConstantDecl");
+ case CXCursor_StructDecl:
+ return createCXString("StructDecl");
+ case CXCursor_UnionDecl:
+ return createCXString("UnionDecl");
+ case CXCursor_ClassDecl:
+ return createCXString("ClassDecl");
+ case CXCursor_FieldDecl:
+ return createCXString("FieldDecl");
+ case CXCursor_VarDecl:
+ return createCXString("VarDecl");
+ case CXCursor_ParmDecl:
+ return createCXString("ParmDecl");
+ case CXCursor_ObjCInterfaceDecl:
+ return createCXString("ObjCInterfaceDecl");
+ case CXCursor_ObjCCategoryDecl:
+ return createCXString("ObjCCategoryDecl");
+ case CXCursor_ObjCProtocolDecl:
+ return createCXString("ObjCProtocolDecl");
+ case CXCursor_ObjCPropertyDecl:
+ return createCXString("ObjCPropertyDecl");
+ case CXCursor_ObjCIvarDecl:
+ return createCXString("ObjCIvarDecl");
+ case CXCursor_ObjCInstanceMethodDecl:
+ return createCXString("ObjCInstanceMethodDecl");
+ case CXCursor_ObjCClassMethodDecl:
+ return createCXString("ObjCClassMethodDecl");
+ case CXCursor_ObjCImplementationDecl:
+ return createCXString("ObjCImplementationDecl");
+ case CXCursor_ObjCCategoryImplDecl:
+ return createCXString("ObjCCategoryImplDecl");
+ case CXCursor_CXXMethod:
+ return createCXString("CXXMethod");
+ case CXCursor_UnexposedDecl:
+ return createCXString("UnexposedDecl");
+ case CXCursor_ObjCSuperClassRef:
+ return createCXString("ObjCSuperClassRef");
+ case CXCursor_ObjCProtocolRef:
+ return createCXString("ObjCProtocolRef");
+ case CXCursor_ObjCClassRef:
+ return createCXString("ObjCClassRef");
+ case CXCursor_TypeRef:
+ return createCXString("TypeRef");
+ case CXCursor_UnexposedExpr:
+ return createCXString("UnexposedExpr");
+ case CXCursor_BlockExpr:
+ return createCXString("BlockExpr");
+ case CXCursor_DeclRefExpr:
+ return createCXString("DeclRefExpr");
+ case CXCursor_MemberRefExpr:
+ return createCXString("MemberRefExpr");
+ case CXCursor_CallExpr:
+ return createCXString("CallExpr");
+ case CXCursor_ObjCMessageExpr:
+ return createCXString("ObjCMessageExpr");
+ case CXCursor_UnexposedStmt:
+ return createCXString("UnexposedStmt");
+ case CXCursor_InvalidFile:
+ return createCXString("InvalidFile");
+ case CXCursor_InvalidCode:
+ return createCXString("InvalidCode");
+ case CXCursor_NoDeclFound:
+ return createCXString("NoDeclFound");
+ case CXCursor_NotImplemented:
+ return createCXString("NotImplemented");
+ case CXCursor_TranslationUnit:
+ return createCXString("TranslationUnit");
+ case CXCursor_UnexposedAttr:
+ return createCXString("UnexposedAttr");
+ case CXCursor_IBActionAttr:
+ return createCXString("attribute(ibaction)");
+ case CXCursor_IBOutletAttr:
+ return createCXString("attribute(iboutlet)");
+ case CXCursor_PreprocessingDirective:
+ return createCXString("preprocessing directive");
+ case CXCursor_MacroDefinition:
+ return createCXString("macro definition");
+ case CXCursor_MacroInstantiation:
+ return createCXString("macro instantiation");
+ }
+
+ llvm_unreachable("Unhandled CXCursorKind");
+ return createCXString(NULL);
+}
+
+enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ CXCursor *BestCursor = static_cast<CXCursor *>(client_data);
+ *BestCursor = cursor;
+ return CXChildVisit_Recurse;
+}
+
+CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
+ if (!TU)
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
+ CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
+ if (SLoc.isValid()) {
+ 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
+ // the region of interest, rather than starting from the translation unit.
+ CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
+ CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result,
+ Decl::MaxPCHLevel, RegionOfInterest);
+ CursorVis.VisitChildren(Parent);
+ }
+ return Result;
+}
+
+CXCursor clang_getNullCursor(void) {
+ return MakeCXCursorInvalid(CXCursor_InvalidFile);
+}
+
+unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
+ return X == Y;
+}
+
+unsigned clang_isInvalid(enum CXCursorKind K) {
+ return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
+}
+
+unsigned clang_isDeclaration(enum CXCursorKind K) {
+ return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
+}
+
+unsigned clang_isReference(enum CXCursorKind K) {
+ return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
+}
+
+unsigned clang_isExpression(enum CXCursorKind K) {
+ return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr;
+}
+
+unsigned clang_isStatement(enum CXCursorKind K) {
+ return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt;
+}
+
+unsigned clang_isTranslationUnit(enum CXCursorKind K) {
+ return K == CXCursor_TranslationUnit;
+}
+
+unsigned clang_isPreprocessing(enum CXCursorKind K) {
+ return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing;
+}
+
+unsigned clang_isUnexposed(enum CXCursorKind K) {
+ switch (K) {
+ case CXCursor_UnexposedDecl:
+ case CXCursor_UnexposedExpr:
+ case CXCursor_UnexposedStmt:
+ case CXCursor_UnexposedAttr:
+ return true;
+ default:
+ return false;
+ }
+}
+
+CXCursorKind clang_getCursorKind(CXCursor C) {
+ return C.kind;
+}
+
+CXSourceLocation clang_getCursorLocation(CXCursor C) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCSuperClassRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCProtocolRef: {
+ std::pair<ObjCProtocolDecl *, SourceLocation> P
+ = getCursorObjCProtocolRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCClassRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_TypeRef: {
+ std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
+ default:
+ // FIXME: Need a way to enumerate all non-reference cases.
+ llvm_unreachable("Missed a reference kind");
+ }
+ }
+
+ if (clang_isExpression(C.kind))
+ return cxloc::translateSourceLocation(getCursorContext(C),
+ getLocationFromExpr(getCursorExpr(C)));
+
+ if (C.kind == CXCursor_PreprocessingDirective) {
+ SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation) {
+ SourceLocation L
+ = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation();
+ return cxloc::translateSourceLocation(getCursorContext(C), L);
+ }
+
+ 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 cxloc::translateSourceLocation(getCursorContext(C), Loc);
+}
+
+CXSourceRange clang_getCursorExtent(CXCursor C) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCSuperClassRef(C);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCProtocolRef: {
+ std::pair<ObjCProtocolDecl *, SourceLocation> P
+ = getCursorObjCProtocolRef(C);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ = getCursorObjCClassRef(C);
+
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
+ }
+
+ case CXCursor_TypeRef: {
+ std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
+ return cxloc::translateSourceRange(P.first->getASTContext(), P.second);
+ }
+
+ default:
+ // FIXME: Need a way to enumerate all non-reference cases.
+ llvm_unreachable("Missed a reference kind");
+ }
+ }
+
+ if (clang_isExpression(C.kind))
+ return cxloc::translateSourceRange(getCursorContext(C),
+ getCursorExpr(C)->getSourceRange());
+
+ if (clang_isStatement(C.kind))
+ return cxloc::translateSourceRange(getCursorContext(C),
+ getCursorStmt(C)->getSourceRange());
+
+ if (C.kind == CXCursor_PreprocessingDirective) {
+ SourceRange R = cxcursor::getCursorPreprocessingDirective(C);
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation) {
+ SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange();
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ if (C.kind == CXCursor_MacroDefinition) {
+ SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange();
+ return cxloc::translateSourceRange(getCursorContext(C), R);
+ }
+
+ if (!getCursorDecl(C))
+ return clang_getNullRange();
+
+ Decl *D = getCursorDecl(C);
+ return cxloc::translateSourceRange(getCursorContext(C), D->getSourceRange());
+}
+
+CXCursor clang_getCursorReferenced(CXCursor C) {
+ if (clang_isInvalid(C.kind))
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = getCursorASTUnit(C);
+ if (clang_isDeclaration(C.kind))
+ return C;
+
+ if (clang_isExpression(C.kind)) {
+ Decl *D = getDeclFromExpr(getCursorExpr(C));
+ if (D)
+ return MakeCXCursor(D, CXXUnit);
+ return clang_getNullCursor();
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation) {
+ if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition())
+ return MakeMacroDefinitionCursor(Def, CXXUnit);
+ }
+
+ if (!clang_isReference(C.kind))
+ return clang_getNullCursor();
+
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef:
+ return MakeCXCursor(getCursorObjCSuperClassRef(C).first, CXXUnit);
+
+ case CXCursor_ObjCProtocolRef: {
+ return MakeCXCursor(getCursorObjCProtocolRef(C).first, CXXUnit);
+
+ case CXCursor_ObjCClassRef:
+ return MakeCXCursor(getCursorObjCClassRef(C).first, CXXUnit);
+
+ case CXCursor_TypeRef:
+ return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit);
+
+ default:
+ // We would prefer to enumerate all non-reference cursor kinds here.
+ llvm_unreachable("Unhandled reference cursor kind");
+ break;
+ }
+ }
+
+ return clang_getNullCursor();
+}
+
+CXCursor clang_getCursorDefinition(CXCursor C) {
+ if (clang_isInvalid(C.kind))
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = getCursorASTUnit(C);
+
+ bool WasReference = false;
+ if (clang_isReference(C.kind) || clang_isExpression(C.kind)) {
+ C = clang_getCursorReferenced(C);
+ WasReference = true;
+ }
+
+ if (C.kind == CXCursor_MacroInstantiation)
+ return clang_getCursorReferenced(C);
+
+ if (!clang_isDeclaration(C.kind))
+ return clang_getNullCursor();
+
+ Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullCursor();
+
+ switch (D->getKind()) {
+ // Declaration kinds that don't really separate the notions of
+ // declaration and definition.
+ case Decl::Namespace:
+ case Decl::Typedef:
+ case Decl::TemplateTypeParm:
+ case Decl::EnumConstant:
+ case Decl::Field:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ case Decl::NonTypeTemplateParm:
+ case Decl::TemplateTemplateParm:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::FileScopeAsm:
+ case Decl::StaticAssert:
+ case Decl::Block:
+ return C;
+
+ // Declaration kinds that don't make any sense here, but are
+ // nonetheless harmless.
+ case Decl::TranslationUnit:
+ break;
+
+ // Declaration kinds for which the definition is not resolvable.
+ case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
+ break;
+
+ case Decl::UsingDirective:
+ return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(),
+ CXXUnit);
+
+ case Decl::NamespaceAlias:
+ return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), CXXUnit);
+
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ if (TagDecl *Def = cast<TagDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, CXXUnit);
+ return clang_getNullCursor();
+
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion: {
+ const FunctionDecl *Def = 0;
+ if (cast<FunctionDecl>(D)->getBody(Def))
+ return MakeCXCursor(const_cast<FunctionDecl *>(Def), CXXUnit);
+ return clang_getNullCursor();
+ }
+
+ case Decl::Var: {
+ // 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: {
+ const FunctionDecl *Def = 0;
+ if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def))
+ return MakeCXCursor(Def->getDescribedFunctionTemplate(), CXXUnit);
+ return clang_getNullCursor();
+ }
+
+ case Decl::ClassTemplate: {
+ if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl()
+ ->getDefinition())
+ return MakeCXCursor(
+ cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(),
+ CXXUnit);
+ return clang_getNullCursor();
+ }
+
+ case Decl::Using: {
+ UsingDecl *Using = cast<UsingDecl>(D);
+ CXCursor Def = clang_getNullCursor();
+ for (UsingDecl::shadow_iterator S = Using->shadow_begin(),
+ SEnd = Using->shadow_end();
+ S != SEnd; ++S) {
+ if (Def != clang_getNullCursor()) {
+ // FIXME: We have no way to return multiple results.
+ return clang_getNullCursor();
+ }
+
+ Def = clang_getCursorDefinition(MakeCXCursor((*S)->getTargetDecl(),
+ CXXUnit));
+ }
+
+ return Def;
+ }
+
+ case Decl::UsingShadow:
+ return clang_getCursorDefinition(
+ MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(),
+ CXXUnit));
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D);
+ if (Method->isThisDeclarationADefinition())
+ return C;
+
+ // Dig out the method definition in the associated
+ // @implementation, if we have it.
+ // FIXME: The ASTs should make finding the definition easier.
+ if (ObjCInterfaceDecl *Class
+ = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()))
+ if (ObjCImplementationDecl *ClassImpl = Class->getImplementation())
+ if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Def->isThisDeclarationADefinition())
+ return MakeCXCursor(Def, CXXUnit);
+
+ return clang_getNullCursor();
+ }
+
+ case Decl::ObjCCategory:
+ if (ObjCCategoryImplDecl *Impl
+ = cast<ObjCCategoryDecl>(D)->getImplementation())
+ return MakeCXCursor(Impl, CXXUnit);
+ return clang_getNullCursor();
+
+ case Decl::ObjCProtocol:
+ if (!cast<ObjCProtocolDecl>(D)->isForwardDecl())
+ return C;
+ return clang_getNullCursor();
+
+ case Decl::ObjCInterface:
+ // There are two notions of a "definition" for an Objective-C
+ // class: the interface and its implementation. When we resolved a
+ // reference to an Objective-C class, produce the @interface as
+ // the definition; when we were provided with the interface,
+ // produce the @implementation as the definition.
+ if (WasReference) {
+ if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl())
+ return C;
+ } else if (ObjCImplementationDecl *Impl
+ = cast<ObjCInterfaceDecl>(D)->getImplementation())
+ return MakeCXCursor(Impl, CXXUnit);
+ return clang_getNullCursor();
+
+ case Decl::ObjCProperty:
+ // FIXME: We don't really know where to find the
+ // ObjCPropertyImplDecls that implement this property.
+ return clang_getNullCursor();
+
+ case Decl::ObjCCompatibleAlias:
+ if (ObjCInterfaceDecl *Class
+ = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
+ if (!Class->isForwardDecl())
+ return MakeCXCursor(Class, CXXUnit);
+
+ return clang_getNullCursor();
+
+ case Decl::ObjCForwardProtocol: {
+ ObjCForwardProtocolDecl *Forward = cast<ObjCForwardProtocolDecl>(D);
+ if (Forward->protocol_size() == 1)
+ return clang_getCursorDefinition(
+ MakeCXCursor(*Forward->protocol_begin(),
+ CXXUnit));
+
+ // FIXME: Cannot return multiple definitions.
+ return clang_getNullCursor();
+ }
+
+ case Decl::ObjCClass: {
+ ObjCClassDecl *Class = cast<ObjCClassDecl>(D);
+ if (Class->size() == 1) {
+ ObjCInterfaceDecl *IFace = Class->begin()->getInterface();
+ if (!IFace->isForwardDecl())
+ return MakeCXCursor(IFace, CXXUnit);
+ return clang_getNullCursor();
+ }
+
+ // FIXME: Cannot return multiple definitions.
+ return clang_getNullCursor();
+ }
+
+ case Decl::Friend:
+ if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl())
+ return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit));
+ return clang_getNullCursor();
+
+ case Decl::FriendTemplate:
+ if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl())
+ return clang_getCursorDefinition(MakeCXCursor(Friend, CXXUnit));
+ return clang_getNullCursor();
+ }
+
+ return clang_getNullCursor();
+}
+
+unsigned clang_isCursorDefinition(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ return clang_getCursorDefinition(C) == C;
+}
+
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
+ const char **startBuf,
+ const char **endBuf,
+ unsigned *startLine,
+ unsigned *startColumn,
+ unsigned *endLine,
+ unsigned *endColumn) {
+ assert(getCursorDecl(C) && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C));
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
+
+ SourceManager &SM = FD->getASTContext().getSourceManager();
+ *startBuf = SM.getCharacterData(Body->getLBracLoc());
+ *endBuf = SM.getCharacterData(Body->getRBracLoc());
+ *startLine = SM.getSpellingLineNumber(Body->getLBracLoc());
+ *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc());
+ *endLine = SM.getSpellingLineNumber(Body->getRBracLoc());
+ *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
+}
+
+void clang_enableStackTraces(void) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+}
+
+} // 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 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 createCXString(llvm::StringRef(Text, CXTok.int_data[2]));
+ }
+
+ 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 createCXString("");
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
+ std::pair<FileID, unsigned> LocInfo
+ = CXXUnit->getSourceManager().getDecomposedLoc(Loc);
+ bool Invalid = false;
+ llvm::StringRef Buffer
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return createCXString("");
+
+ return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2]));
+}
+
+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;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ 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
+ bool Invalid = false;
+ llvm::StringRef Buffer
+ = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid);
+ if (Invalid)
+ return;
+
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens until we hit the end of the range.
+ const char *EffectiveBufferEnd = Buffer.data() + 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 keyword.
+ std::pair<FileID, unsigned> LocInfo
+ = SourceMgr.getDecomposedLoc(Tok.getLocation());
+ bool Invalid = false;
+ llvm::StringRef Buf
+ = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return;
+
+ const char *StartPos = Buf.data() + 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 if (clang_isPreprocessing(cursor.kind)) {
+ // We can always annotate a preprocessing directive/macro instantiation.
+ } 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;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ // Determine the region of interest, which contains all of the tokens.
+ 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));
+
+ // A mapping from the source locations found when re-lexing or traversing the
+ // region of interest to the corresponding cursors.
+ AnnotateTokensData Annotated;
+
+ // Relex the tokens within the source range to look for preprocessing
+ // directives.
+ SourceManager &SourceMgr = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> BeginLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
+ std::pair<FileID, unsigned> EndLocInfo
+ = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+
+ llvm::StringRef Buffer;
+ bool Invalid = false;
+ if (BeginLocInfo.first == EndLocInfo.first &&
+ ((Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid)),true) &&
+ !Invalid) {
+ Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
+ CXXUnit->getASTContext().getLangOptions(),
+ Buffer.begin(), Buffer.data() + BeginLocInfo.second,
+ Buffer.end());
+ Lex.SetCommentRetentionState(true);
+
+ // Lex tokens in raw mode until we hit the end of the range, to avoid
+ // entering #includes or expanding macros.
+ while (true) {
+ Token Tok;
+ Lex.LexFromRawLexer(Tok);
+
+ reprocess:
+ if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
+ // We have found a preprocessing directive. Gobble it up so that we
+ // don't see it while preprocessing these tokens later, but keep track of
+ // all of the token locations inside this preprocessing directive so that
+ // we can annotate them appropriately.
+ //
+ // FIXME: Some simple tests here could identify macro definitions and
+ // #undefs, to provide specific cursor kinds for those.
+ std::vector<SourceLocation> Locations;
+ do {
+ Locations.push_back(Tok.getLocation());
+ Lex.LexFromRawLexer(Tok);
+ } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
+
+ using namespace cxcursor;
+ CXCursor Cursor
+ = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
+ Locations.back()),
+ CXXUnit);
+ for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
+ Annotated[Locations[I].getRawEncoding()] = Cursor;
+ }
+
+ if (Tok.isAtStartOfLine())
+ goto reprocess;
+
+ continue;
+ }
+
+ if (Tok.is(tok::eof))
+ break;
+ }
+ }
+
+ // Annotate all of the source locations in the region of interest that map to
+ // a specific cursor.
+ 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"
+
+//===----------------------------------------------------------------------===//
+// Operations for querying linkage of a cursor.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
+ if (!clang_isDeclaration(cursor.kind))
+ return CXLinkage_Invalid;
+
+ Decl *D = cxcursor::getCursorDecl(cursor);
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
+ switch (ND->getLinkage()) {
+ case NoLinkage: return CXLinkage_NoLinkage;
+ case InternalLinkage: return CXLinkage_Internal;
+ case UniqueExternalLinkage: return CXLinkage_UniqueExternal;
+ case ExternalLinkage: return CXLinkage_External;
+ };
+
+ return CXLinkage_Invalid;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// Operations for querying language of a cursor.
+//===----------------------------------------------------------------------===//
+
+static CXLanguageKind getDeclLanguage(const Decl *D) {
+ switch (D->getKind()) {
+ default:
+ break;
+ case Decl::ImplicitParam:
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCClass:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::ObjCForwardProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCInterface:
+ case Decl::ObjCIvar:
+ case Decl::ObjCMethod:
+ case Decl::ObjCProperty:
+ case Decl::ObjCPropertyImpl:
+ case Decl::ObjCProtocol:
+ return CXLanguage_ObjC;
+ case Decl::CXXConstructor:
+ case Decl::CXXConversion:
+ case Decl::CXXDestructor:
+ case Decl::CXXMethod:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplate:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::FunctionTemplate:
+ case Decl::LinkageSpec:
+ case Decl::Namespace:
+ case Decl::NamespaceAlias:
+ case Decl::NonTypeTemplateParm:
+ case Decl::StaticAssert:
+ case Decl::TemplateTemplateParm:
+ case Decl::TemplateTypeParm:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::UnresolvedUsingValue:
+ case Decl::Using:
+ case Decl::UsingDirective:
+ case Decl::UsingShadow:
+ return CXLanguage_CPlusPlus;
+ }
+
+ return CXLanguage_C;
+}
+
+extern "C" {
+CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
+ if (clang_isDeclaration(cursor.kind))
+ return getDeclLanguage(cxcursor::getCursorDecl(cursor));
+
+ return CXLanguage_Invalid;
+}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXString Operations.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+const char *clang_getCString(CXString string) {
+ return string.Spelling;
+}
+
+void clang_disposeString(CXString string) {
+ if (string.MustFreeString && string.Spelling)
+ free((void*)string.Spelling);
+}
+
+} // end: extern "C"
+
+namespace clang { namespace cxstring {
+CXString createCXString(const char *String, bool DupString){
+ CXString Str;
+ if (DupString) {
+ Str.Spelling = strdup(String);
+ Str.MustFreeString = 1;
+ } else {
+ Str.Spelling = String;
+ Str.MustFreeString = 0;
+ }
+ return Str;
+}
+
+CXString 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;
+}
+}}
+
+//===----------------------------------------------------------------------===//
+// Misc. utility functions.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXString clang_getClangVersion() {
+ return createCXString(getClangFullVersion());
+}
+
+} // end: extern "C"
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
new file mode 100644
index 000000000000..a21614c74735
--- /dev/null
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -0,0 +1,512 @@
+//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library hooks for
+// code completion.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CIndexDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Program.h"
+
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+using namespace clang;
+using namespace clang::cxstring;
+
+extern "C" {
+
+enum CXCompletionChunkKind
+clang_getCompletionChunkKind(CXCompletionString completion_string,
+ unsigned chunk_number) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr || chunk_number >= CCStr->size())
+ return CXCompletionChunk_Text;
+
+ switch ((*CCStr)[chunk_number].Kind) {
+ case CodeCompletionString::CK_TypedText:
+ return CXCompletionChunk_TypedText;
+ case CodeCompletionString::CK_Text:
+ return CXCompletionChunk_Text;
+ case CodeCompletionString::CK_Optional:
+ return CXCompletionChunk_Optional;
+ case CodeCompletionString::CK_Placeholder:
+ return CXCompletionChunk_Placeholder;
+ case CodeCompletionString::CK_Informative:
+ return CXCompletionChunk_Informative;
+ case CodeCompletionString::CK_ResultType:
+ return CXCompletionChunk_ResultType;
+ case CodeCompletionString::CK_CurrentParameter:
+ return CXCompletionChunk_CurrentParameter;
+ case CodeCompletionString::CK_LeftParen:
+ return CXCompletionChunk_LeftParen;
+ case CodeCompletionString::CK_RightParen:
+ return CXCompletionChunk_RightParen;
+ case CodeCompletionString::CK_LeftBracket:
+ return CXCompletionChunk_LeftBracket;
+ case CodeCompletionString::CK_RightBracket:
+ return CXCompletionChunk_RightBracket;
+ case CodeCompletionString::CK_LeftBrace:
+ return CXCompletionChunk_LeftBrace;
+ case CodeCompletionString::CK_RightBrace:
+ return CXCompletionChunk_RightBrace;
+ case CodeCompletionString::CK_LeftAngle:
+ return CXCompletionChunk_LeftAngle;
+ case CodeCompletionString::CK_RightAngle:
+ return CXCompletionChunk_RightAngle;
+ case CodeCompletionString::CK_Comma:
+ return CXCompletionChunk_Comma;
+ case CodeCompletionString::CK_Colon:
+ return CXCompletionChunk_Colon;
+ case CodeCompletionString::CK_SemiColon:
+ return CXCompletionChunk_SemiColon;
+ case CodeCompletionString::CK_Equal:
+ return CXCompletionChunk_Equal;
+ case CodeCompletionString::CK_HorizontalSpace:
+ return CXCompletionChunk_HorizontalSpace;
+ case CodeCompletionString::CK_VerticalSpace:
+ return CXCompletionChunk_VerticalSpace;
+ }
+
+ // Should be unreachable, but let's be careful.
+ return CXCompletionChunk_Text;
+}
+
+CXString clang_getCompletionChunkText(CXCompletionString completion_string,
+ unsigned chunk_number) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr || chunk_number >= CCStr->size())
+ return createCXString(0);
+
+ switch ((*CCStr)[chunk_number].Kind) {
+ case CodeCompletionString::CK_TypedText:
+ case CodeCompletionString::CK_Text:
+ case CodeCompletionString::CK_Placeholder:
+ case CodeCompletionString::CK_CurrentParameter:
+ case CodeCompletionString::CK_Informative:
+ case CodeCompletionString::CK_LeftParen:
+ case CodeCompletionString::CK_RightParen:
+ case CodeCompletionString::CK_LeftBracket:
+ case CodeCompletionString::CK_RightBracket:
+ case CodeCompletionString::CK_LeftBrace:
+ case CodeCompletionString::CK_RightBrace:
+ case CodeCompletionString::CK_LeftAngle:
+ case CodeCompletionString::CK_RightAngle:
+ case CodeCompletionString::CK_Comma:
+ case CodeCompletionString::CK_ResultType:
+ case CodeCompletionString::CK_Colon:
+ case CodeCompletionString::CK_SemiColon:
+ case CodeCompletionString::CK_Equal:
+ case CodeCompletionString::CK_HorizontalSpace:
+ case CodeCompletionString::CK_VerticalSpace:
+ return createCXString((*CCStr)[chunk_number].Text, false);
+
+ case CodeCompletionString::CK_Optional:
+ // Note: treated as an empty text block.
+ return createCXString("");
+ }
+
+ // Should be unreachable, but let's be careful.
+ return createCXString(0);
+}
+
+
+CXCompletionString
+clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
+ unsigned chunk_number) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr || chunk_number >= CCStr->size())
+ return 0;
+
+ switch ((*CCStr)[chunk_number].Kind) {
+ case CodeCompletionString::CK_TypedText:
+ case CodeCompletionString::CK_Text:
+ case CodeCompletionString::CK_Placeholder:
+ case CodeCompletionString::CK_CurrentParameter:
+ case CodeCompletionString::CK_Informative:
+ case CodeCompletionString::CK_LeftParen:
+ case CodeCompletionString::CK_RightParen:
+ case CodeCompletionString::CK_LeftBracket:
+ case CodeCompletionString::CK_RightBracket:
+ case CodeCompletionString::CK_LeftBrace:
+ case CodeCompletionString::CK_RightBrace:
+ case CodeCompletionString::CK_LeftAngle:
+ case CodeCompletionString::CK_RightAngle:
+ case CodeCompletionString::CK_Comma:
+ case CodeCompletionString::CK_ResultType:
+ case CodeCompletionString::CK_Colon:
+ case CodeCompletionString::CK_SemiColon:
+ case CodeCompletionString::CK_Equal:
+ case CodeCompletionString::CK_HorizontalSpace:
+ case CodeCompletionString::CK_VerticalSpace:
+ return 0;
+
+ case CodeCompletionString::CK_Optional:
+ // Note: treated as an empty text block.
+ return (*CCStr)[chunk_number].Optional;
+ }
+
+ // Should be unreachable, but let's be careful.
+ return 0;
+}
+
+unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ return CCStr? CCStr->size() : 0;
+}
+
+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;
+}
+
+/// \brief The CXCodeCompleteResults structure we allocate internally;
+/// the client only sees the initial CXCodeCompleteResults structure.
+struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
+ AllocatedCXCodeCompleteResults();
+ ~AllocatedCXCodeCompleteResults();
+
+ /// \brief The memory buffer from which we parsed the results. We
+ /// retain this buffer because the completion strings point into it.
+ llvm::MemoryBuffer *Buffer;
+
+ /// \brief Diagnostics produced while performing code completion.
+ llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
+
+ /// \brief Diag object
+ Diagnostic Diag;
+
+ /// \brief Language options used to adjust source locations.
+ LangOptions LangOpts;
+
+ /// \brief Source manager, used for diagnostics.
+ SourceManager SourceMgr;
+
+ /// \brief File manager, used for diagnostics.
+ FileManager FileMgr;
+
+ /// \brief Temporary files that should be removed once we have finished
+ /// with the code-completion results.
+ std::vector<llvm::sys::Path> TemporaryFiles;
+};
+
+AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
+ : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { }
+
+AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
+ for (unsigned I = 0, N = NumResults; I != N; ++I)
+ delete (CodeCompletionString *)Results[I].CompletionString;
+ delete [] Results;
+ delete Buffer;
+
+ for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
+ TemporaryFiles[I].eraseFromDisk();
+}
+
+CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
+ const char *source_filename,
+ 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) {
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
+ const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
+#endif
+#endif
+
+ // The indexer, which is mainly used to determine where diagnostics go.
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
+ Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
+
+ // The set of temporary files that we've built.
+ std::vector<llvm::sys::Path> TemporaryFiles;
+
+ // Build up the arguments for invoking 'clang'.
+ std::vector<const char *> argv;
+
+ // First add the complete path to the 'clang' executable.
+ llvm::sys::Path ClangPath = CXXIdx->getClangPath();
+ argv.push_back(ClangPath.c_str());
+
+ // Add the '-fsyntax-only' argument so that we only perform a basic
+ // syntax check of the code.
+ argv.push_back("-fsyntax-only");
+
+ // Add the appropriate '-code-completion-at=file:line:column' argument
+ // to perform code completion, with an "-Xclang" preceding it.
+ std::string code_complete_at;
+ code_complete_at += complete_filename;
+ code_complete_at += ":";
+ code_complete_at += llvm::utostr(complete_line);
+ code_complete_at += ":";
+ code_complete_at += llvm::utostr(complete_column);
+ argv.push_back("-Xclang");
+ argv.push_back("-code-completion-at");
+ argv.push_back("-Xclang");
+ argv.push_back(code_complete_at.c_str());
+ argv.push_back("-Xclang");
+ 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))
+ return 0;
+
+ // The pointers into the elements of RemapArgs are stable because we
+ // won't be adding anything to RemapArgs after this point.
+ for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
+ argv.push_back(RemapArgs[i].c_str());
+
+ // Add the source file name (FIXME: later, we'll want to build temporary
+ // file from the buffer, or just feed the source text via standard input).
+ if (source_filename)
+ argv.push_back(source_filename);
+
+ // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
+ for (int i = 0; i < num_command_line_args; ++i)
+ if (const char *arg = command_line_args[i]) {
+ if (strcmp(arg, "-o") == 0) {
+ ++i; // Also skip the matching argument.
+ continue;
+ }
+ if (strcmp(arg, "-emit-ast") == 0 ||
+ strcmp(arg, "-c") == 0 ||
+ strcmp(arg, "-fsyntax-only") == 0) {
+ continue;
+ }
+
+ // Keep the argument.
+ argv.push_back(arg);
+ }
+
+ // Add the null terminator.
+ argv.push_back(NULL);
+
+ // 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,
+ &DiagnosticsFile, 0 };
+ llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
+ /* redirects */ &Redirects[0],
+ /* secondsToWait */ 0,
+ /* memoryLimits */ 0, &ErrMsg);
+
+ if (!ErrMsg.empty()) {
+ std::string AllArgs;
+ for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
+ I != E; ++I) {
+ AllArgs += ' ';
+ if (*I)
+ AllArgs += *I;
+ }
+
+ Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
+ }
+
+ // Parse the resulting source file to find code-completion results.
+ using llvm::MemoryBuffer;
+ using llvm::StringRef;
+ AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
+ Results->Results = 0;
+ Results->NumResults = 0;
+ Results->Buffer = 0;
+ // FIXME: Set Results->LangOpts!
+ if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
+ llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
+ StringRef Buffer = F->getBuffer();
+ for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+ Str < StrEnd;) {
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
+ break;
+
+ CodeCompletionString *CCStr
+ = CodeCompletionString::Deserialize(Str, StrEnd);
+ if (!CCStr)
+ continue;
+
+ if (!CCStr->empty()) {
+ // Vend the code-completion result to the caller.
+ CXCompletionResult Result;
+ Result.CursorKind = (CXCursorKind)KindValue;
+ Result.CompletionString = CCStr;
+ CompletionResults.push_back(Result);
+ }
+ };
+
+ // Allocate the results.
+ Results->Results = new CXCompletionResult [CompletionResults.size()];
+ Results->NumResults = CompletionResults.size();
+ memcpy(Results->Results, CompletionResults.data(),
+ CompletionResults.size() * sizeof(CXCompletionResult));
+ Results->Buffer = F;
+ }
+
+ LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
+ Results->FileMgr, Results->SourceMgr,
+ Results->Diagnostics);
+
+ // Make sure we delete temporary files when the code-completion results are
+ // destroyed.
+ Results->TemporaryFiles.swap(TemporaryFiles);
+
+#ifdef UDP_CODE_COMPLETION_LOGGER
+#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
+ const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
+ llvm::SmallString<256> LogResult;
+ llvm::raw_svector_ostream os(LogResult);
+
+ // Figure out the language and whether or not it uses PCH.
+ const char *lang = 0;
+ bool usesPCH = false;
+
+ for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
+ I != E; ++I) {
+ if (*I == 0)
+ continue;
+ if (strcmp(*I, "-x") == 0) {
+ if (I + 1 != E) {
+ lang = *(++I);
+ continue;
+ }
+ }
+ else if (strcmp(*I, "-include") == 0) {
+ if (I+1 != E) {
+ const char *arg = *(++I);
+ llvm::SmallString<512> pchName;
+ {
+ llvm::raw_svector_ostream os(pchName);
+ os << arg << ".pth";
+ }
+ pchName.push_back('\0');
+ struct stat stat_results;
+ if (stat(pchName.data(), &stat_results) == 0)
+ usesPCH = true;
+ continue;
+ }
+ }
+ }
+
+ os << "{ ";
+ os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
+ os << ", \"numRes\": " << Results->NumResults;
+ os << ", \"diags\": " << Results->Diagnostics.size();
+ os << ", \"pch\": " << (usesPCH ? "true" : "false");
+ os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
+ const char *name = getlogin();
+ os << ", \"user\": \"" << (name ? name : "unknown") << '"';
+ os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
+ os << " }";
+
+ llvm::StringRef res = os.str();
+ if (res.size() > 0) {
+ do {
+ // Setup the UDP socket.
+ struct sockaddr_in servaddr;
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
+ if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
+ &servaddr.sin_addr) <= 0)
+ break;
+
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0)
+ break;
+
+ sendto(sockfd, res.data(), res.size(), 0,
+ (struct sockaddr *)&servaddr, sizeof(servaddr));
+ close(sockfd);
+ }
+ while (false);
+ }
+#endif
+#endif
+ return Results;
+}
+
+void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
+ if (!ResultsIn)
+ return;
+
+ AllocatedCXCodeCompleteResults *Results
+ = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+ delete Results;
+}
+
+unsigned
+clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
+ AllocatedCXCodeCompleteResults *Results
+ = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+ if (!Results)
+ return 0;
+
+ return Results->Diagnostics.size();
+}
+
+CXDiagnostic
+clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
+ unsigned Index) {
+ AllocatedCXCodeCompleteResults *Results
+ = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+ if (!Results || Index >= Results->Diagnostics.size())
+ return 0;
+
+ return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
+}
+
+
+} // end extern "C"
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
new file mode 100644
index 000000000000..3db37b97da14
--- /dev/null
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -0,0 +1,285 @@
+/*===-- 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/ASTUnit.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxloc;
+using namespace clang::cxstring;
+using namespace llvm;
+
+//-----------------------------------------------------------------------------
+// C Interface Routines
+//-----------------------------------------------------------------------------
+extern "C" {
+
+unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
+ return CXXUnit? CXXUnit->stored_diag_size() : 0;
+}
+
+CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit);
+ if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
+ return 0;
+
+ return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
+ CXXUnit->getASTContext().getLangOptions());
+}
+
+void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
+ CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
+ delete Stored;
+}
+
+CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
+ if (!Diagnostic)
+ return createCXString("");
+
+ CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
+
+ // Ignore diagnostics that should be ignored.
+ if (Severity == CXDiagnostic_Ignored)
+ return createCXString("");
+
+ llvm::SmallString<256> Str;
+ llvm::raw_svector_ostream Out(Str);
+
+ if (Options & CXDiagnostic_DisplaySourceLocation) {
+ // Print source location (file:line), along with optional column
+ // and source ranges.
+ CXFile File;
+ unsigned Line, Column;
+ clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
+ &File, &Line, &Column, 0);
+ if (File) {
+ CXString FName = clang_getFileName(File);
+ Out << clang_getCString(FName) << ":" << Line << ":";
+ clang_disposeString(FName);
+ if (Options & CXDiagnostic_DisplayColumn)
+ Out << Column << ":";
+
+ if (Options & CXDiagnostic_DisplaySourceRanges) {
+ unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
+ bool PrintedRange = false;
+ for (unsigned I = 0; I != N; ++I) {
+ CXFile StartFile, EndFile;
+ CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
+
+ unsigned StartLine, StartColumn, EndLine, EndColumn;
+ clang_getInstantiationLocation(clang_getRangeStart(Range),
+ &StartFile, &StartLine, &StartColumn,
+ 0);
+ clang_getInstantiationLocation(clang_getRangeEnd(Range),
+ &EndFile, &EndLine, &EndColumn, 0);
+
+ if (StartFile != EndFile || StartFile != File)
+ continue;
+
+ Out << "{" << StartLine << ":" << StartColumn << "-"
+ << EndLine << ":" << EndColumn << "}";
+ PrintedRange = true;
+ }
+ if (PrintedRange)
+ Out << ":";
+ }
+ }
+
+ Out << " ";
+ }
+
+ /* Print warning/error/etc. */
+ switch (Severity) {
+ case CXDiagnostic_Ignored: assert(0 && "impossible"); break;
+ case CXDiagnostic_Note: Out << "note: "; break;
+ case CXDiagnostic_Warning: Out << "warning: "; break;
+ case CXDiagnostic_Error: Out << "error: "; break;
+ case CXDiagnostic_Fatal: Out << "fatal error: "; break;
+ }
+
+ CXString Text = clang_getDiagnosticSpelling(Diagnostic);
+ if (clang_getCString(Text))
+ Out << clang_getCString(Text);
+ else
+ Out << "<no diagnostic text>";
+ clang_disposeString(Text);
+ return createCXString(Out.str(), true);
+}
+
+unsigned clang_defaultDiagnosticDisplayOptions() {
+ return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
+}
+
+enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return CXDiagnostic_Ignored;
+
+ switch (StoredDiag->Diag.getLevel()) {
+ 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->Diag.getLocation().isInvalid())
+ return clang_getNullLocation();
+
+ return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ StoredDiag->Diag.getLocation());
+}
+
+CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return createCXString("");
+
+ return createCXString(StoredDiag->Diag.getMessage(), false);
+}
+
+unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
+ return 0;
+
+ return StoredDiag->Diag.range_size();
+}
+
+CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
+ StoredDiag->Diag.getLocation().isInvalid())
+ return clang_getNullRange();
+
+ return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ StoredDiag->Diag.range_begin()[Range]);
+}
+
+unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
+ CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
+ if (!StoredDiag)
+ return 0;
+
+ return StoredDiag->Diag.fixit_size();
+}
+
+CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
+ CXSourceRange *ReplacementRange) {
+ CXStoredDiagnostic *StoredDiag
+ = static_cast<CXStoredDiagnostic *>(Diagnostic);
+ if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
+ StoredDiag->Diag.getLocation().isInvalid()) {
+ if (ReplacementRange)
+ *ReplacementRange = clang_getNullRange();
+
+ return createCXString("");
+ }
+
+ const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
+ if (ReplacementRange) {
+ if (Hint.RemoveRange.isInvalid()) {
+ // Create an empty range that refers to a single source
+ // location (which is the insertion point).
+ CXSourceRange Range = {
+ { (void *)&StoredDiag->Diag.getLocation().getManager(),
+ (void *)&StoredDiag->LangOpts },
+ Hint.InsertionLoc.getRawEncoding(),
+ Hint.InsertionLoc.getRawEncoding()
+ };
+
+ *ReplacementRange = Range;
+ } else {
+ // Create a range that covers the entire replacement (or
+ // removal) range, adjusting the end of the range to point to
+ // the end of the token.
+ *ReplacementRange
+ = translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
+ StoredDiag->LangOpts,
+ Hint.RemoveRange);
+ }
+ }
+
+ return createCXString(Hint.CodeToInsert);
+}
+
+} // end extern "C"
+
+void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ SmallVectorImpl<StoredDiagnostic> &Diags) {
+ using llvm::MemoryBuffer;
+ using llvm::StringRef;
+ MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
+ if (!F)
+ return;
+
+ // Enter the unsaved files into the file manager.
+ 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) {
+ // FIXME: Hard to localize when we have no diagnostics engine!
+ Diags.push_back(StoredDiagnostic(Diagnostic::Fatal,
+ (Twine("could not remap from missing file ") +
+ unsaved_files[I].Filename).str()));
+ delete F;
+ return;
+ }
+
+ MemoryBuffer *Buffer
+ = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
+ unsaved_files[I].Contents + unsaved_files[I].Length);
+ if (!Buffer) {
+ delete F;
+ return;
+ }
+
+ SourceMgr.overrideFileContents(File, Buffer);
+ SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ }
+
+ // 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) {
+ StoredDiagnostic Stored = StoredDiagnostic::Deserialize(FileMgr, SourceMgr,
+ Memory, MemoryEnd);
+ if (!Stored)
+ break;
+
+ Diags.push_back(Stored);
+ }
+ delete F;
+}
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
new file mode 100644
index 000000000000..919c21cfdbe4
--- /dev/null
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -0,0 +1,53 @@
+/*===-- 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
+
+struct CXUnsavedFile;
+
+namespace llvm {
+template<typename T> class SmallVectorImpl;
+namespace sys { class Path; }
+}
+
+namespace clang {
+
+class Diagnostic;
+class FileManager;
+class LangOptions;
+class Preprocessor;
+class StoredDiagnostic;
+class SourceManager;
+
+/// \brief The storage behind a CXDiagnostic
+struct CXStoredDiagnostic {
+ const StoredDiagnostic &Diag;
+ const LangOptions &LangOpts;
+
+ CXStoredDiagnostic(const StoredDiagnostic &Diag,
+ const LangOptions &LangOpts)
+ : Diag(Diag), LangOpts(LangOpts) { }
+};
+
+/// \brief Given the path to a file that contains binary, serialized
+/// diagnostics produced by Clang, load those diagnostics.
+void LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ llvm::SmallVectorImpl<StoredDiagnostic> &Diags);
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
new file mode 100644
index 000000000000..e86323956f91
--- /dev/null
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -0,0 +1,67 @@
+//===- 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 "clang/Frontend/ASTUnit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+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/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
new file mode 100644
index 000000000000..f3c74e85316f
--- /dev/null
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -0,0 +1,477 @@
+//===- CIndexUSR.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 implements the generation and use of USRs from CXEntities.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "CXCursor.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// USR generation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class USRGenerator : public DeclVisitor<USRGenerator> {
+ llvm::raw_ostream &Out;
+ bool IgnoreResults;
+ ASTUnit *AU;
+public:
+ USRGenerator(ASTUnit *au, llvm::raw_ostream &out)
+ : Out(out), IgnoreResults(false), AU(au) {}
+
+ bool ignoreResults() const { return IgnoreResults; }
+
+ // Visitation methods from generating USRs from AST elements.
+ void VisitDeclContext(DeclContext *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitObjCClassDecl(ObjCClassDecl *CD);
+ void VisitObjCContainerDecl(ObjCContainerDecl *CD);
+ void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P);
+ void VisitObjCMethodDecl(ObjCMethodDecl *MD);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitVarDecl(VarDecl *D);
+
+ /// Generate the string component containing the location of the
+ /// declaration.
+ void GenLoc(const Decl *D);
+
+ /// String generation methods used both by the visitation methods
+ /// and from other clients that want to directly generate USRs. These
+ /// methods do not construct complete USRs (which incorporate the parents
+ /// of an AST element), but only the fragments concerning the AST element
+ /// itself.
+
+ /// Generate a USR fragment for a named declaration. This does
+ /// not include the USR component for the parent.
+ void GenNamedDecl(llvm::StringRef name);
+
+ /// Generate a USR for an Objective-C class.
+ void GenObjCClass(llvm::StringRef cls);
+ /// Generate a USR for an Objective-C class category.
+ void GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat);
+ /// Generate a USR fragment for an Objective-C instance variable. The
+ /// complete USR can be created by concatenating the USR for the
+ /// encompassing class with this USR fragment.
+ void GenObjCIvar(llvm::StringRef ivar);
+ /// Generate a USR fragment for an Objective-C method.
+ void GenObjCMethod(llvm::StringRef sel, bool isInstanceMethod);
+ /// Generate a USR fragment for an Objective-C property.
+ void GenObjCProperty(llvm::StringRef prop);
+ /// Generate a USR for an Objective-C protocol.
+ void GenObjCProtocol(llvm::StringRef prot);
+};
+
+class StringUSRGenerator {
+private:
+ llvm::SmallString<1024> StrBuf;
+ llvm::raw_svector_ostream Out;
+ USRGenerator UG;
+public:
+ StringUSRGenerator(const CXCursor *C = 0)
+ : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) {
+ // Add the USR space prefix.
+ Out << "c:";
+ }
+
+ llvm::StringRef str() {
+ return Out.str();
+ }
+
+ USRGenerator* operator->() { return &UG; }
+
+ template <typename T>
+ llvm::raw_svector_ostream &operator<<(const T &x) {
+ Out << x;
+ return Out;
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Generating USRs from ASTS.
+//===----------------------------------------------------------------------===//
+
+void USRGenerator::VisitDeclContext(DeclContext *DC) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
+ Visit(D);
+}
+
+void USRGenerator::VisitFieldDecl(FieldDecl *D) {
+ const std::string &s = D->getNameAsString();
+ if (s.empty()) {
+ // Bit fields can be anonymous.
+ IgnoreResults = true;
+ return;
+ }
+ VisitDeclContext(D->getDeclContext());
+ Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s;
+}
+
+void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
+ if (D->getLinkage() != ExternalLinkage) {
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ }
+ else
+ VisitDeclContext(D->getDeclContext());
+
+ Out << "@F@" << D;
+}
+
+void USRGenerator::VisitNamedDecl(NamedDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ const std::string &s = D->getNameAsString();
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ GenNamedDecl(s);
+}
+
+void USRGenerator::VisitVarDecl(VarDecl *D) {
+ // VarDecls can be declared 'extern' within a function or method body,
+ // but their enclosing DeclContext is the function, not the TU. We need
+ // to check the storage class to correctly generate the USR.
+ if (D->getLinkage() != ExternalLinkage) {
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ }
+
+ // Variables always have simple names.
+ llvm::StringRef s = D->getName();
+
+ // The string can be empty if the declaration has no name; e.g., it is
+ // the ParmDecl with no name for declaration of a function pointer type, e.g.:
+ // void (*f)(void *);
+ // In this case, don't generate a USR.
+ if (s.empty())
+ IgnoreResults = true;
+ else
+ GenNamedDecl(s);
+}
+
+void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@N@" << D;
+}
+
+void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ Visit(cast<Decl>(D->getDeclContext()));
+ GenObjCMethod(DeclarationName(D->getSelector()).getAsString(),
+ D->isInstanceMethod());
+}
+
+void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
+ // FIXME: @class declarations can refer to multiple classes. We need
+ // to be able to traverse these.
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ // FIXME: @protocol declarations can refer to multiple protocols. We need
+ // to be able to traverse these.
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ switch (D->getKind()) {
+ default:
+ assert(false && "Invalid ObjC container.");
+ case Decl::ObjCInterface:
+ case Decl::ObjCImplementation:
+ GenObjCClass(D->getName());
+ break;
+ case Decl::ObjCCategory: {
+ ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
+ ObjCInterfaceDecl *ID = CD->getClassInterface();
+ if (!ID) {
+ // Handle invalid code where the @interface might not
+ // have been specified.
+ // FIXME: We should be able to generate this USR even if the
+ // @interface isn't available.
+ IgnoreResults = true;
+ return;
+ }
+ GenObjCCategory(ID->getName(), CD->getName());
+ break;
+ }
+ case Decl::ObjCProtocol:
+ GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
+ break;
+ }
+}
+
+void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ Visit(cast<Decl>(D->getDeclContext()));
+ GenObjCProperty(D->getName());
+}
+
+void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
+ VisitObjCPropertyDecl(PD);
+ return;
+ }
+
+ IgnoreResults = true;
+}
+
+void USRGenerator::VisitTagDecl(TagDecl *D) {
+ D = D->getCanonicalDecl();
+ VisitDeclContext(D->getDeclContext());
+ switch (D->getTagKind()) {
+ case TagDecl::TK_struct: Out << "@S"; break;
+ case TagDecl::TK_class: Out << "@C"; break;
+ case TagDecl::TK_union: Out << "@U"; break;
+ case TagDecl::TK_enum: Out << "@E"; break;
+ }
+
+ const std::string &s = D->getNameAsString();
+ const TypedefDecl *TD = 0;
+ if (s.empty()) {
+ TD = D->getTypedefForAnonDecl();
+ Out << (TD ? 'A' : 'a');
+ }
+
+ // Add the location of the tag decl to handle resolution across
+ // translation units.
+ if (D->getLinkage() == NoLinkage) {
+ Out << '@';
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ }
+
+ if (s.empty()) {
+ if (TD)
+ Out << '@' << TD;
+ }
+ else
+ Out << '@' << s;
+}
+
+void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+ DeclContext *DC = D->getDeclContext();
+ if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
+ Visit(DCN);
+ Out << "@T@";
+ if (D->getLinkage() == NoLinkage) {
+ GenLoc(D);
+ if (IgnoreResults)
+ return;
+ Out << '@';
+ }
+ Out << D->getName();
+}
+
+void USRGenerator::GenLoc(const Decl *D) {
+ const SourceManager &SM = AU->getSourceManager();
+ SourceLocation L = D->getLocStart();
+ if (L.isInvalid()) {
+ IgnoreResults = true;
+ return;
+ }
+ L = SM.getInstantiationLoc(L);
+ const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
+ const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+ if (FE) {
+ llvm::sys::Path P(FE->getName());
+ Out << P.getLast();
+ }
+ else {
+ // This case really isn't interesting.
+ IgnoreResults = true;
+ return;
+ }
+ Out << '@'
+ << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':'
+ << SM.getColumnNumber(Decomposed.first, Decomposed.second);
+}
+
+//===----------------------------------------------------------------------===//
+// General purpose USR generation methods.
+//===----------------------------------------------------------------------===//
+
+void USRGenerator::GenNamedDecl(llvm::StringRef name) {
+ Out << "@" << name;
+}
+
+void USRGenerator::GenObjCClass(llvm::StringRef cls) {
+ Out << "objc(cs)" << cls;
+}
+
+void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
+ Out << "objc(cy)" << cls << '@' << cat;
+}
+
+void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
+ GenNamedDecl(ivar);
+}
+
+void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
+ Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
+}
+
+void USRGenerator::GenObjCProperty(llvm::StringRef prop) {
+ Out << "(py)" << prop;
+}
+
+void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
+ Out << "objc(pl)" << prot;
+}
+
+//===----------------------------------------------------------------------===//
+// API hooks.
+//===----------------------------------------------------------------------===//
+
+static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
+ return s.startswith("c:") ? s.substr(2) : "";
+}
+
+static CXString getDeclCursorUSR(const CXCursor &C) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ // Don't generate USRs for things with invalid locations.
+ if (!D || D->getLocStart().isInvalid())
+ return createCXString("");
+
+ // Check if the cursor has 'NoLinkage'.
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ switch (ND->getLinkage()) {
+ case ExternalLinkage:
+ // Generate USRs for all entities with external linkage.
+ break;
+ case NoLinkage:
+ // We allow enums, typedefs, and structs that have no linkage to
+ // have USRs that are anchored to the file they were defined in
+ // (e.g., the header). This is a little gross, but in principal
+ // enums/anonymous structs/etc. defined in a common header file
+ // are referred to across multiple translation units.
+ if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
+ isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) ||
+ isa<VarDecl>(ND))
+ break;
+ // Fall-through.
+ case InternalLinkage:
+ if (isa<FunctionDecl>(ND))
+ break;
+ case UniqueExternalLinkage:
+ return createCXString("");
+ }
+
+ StringUSRGenerator SUG(&C);
+ SUG->Visit(D);
+
+ if (SUG->ignoreResults())
+ return createCXString("");
+
+ // For development testing.
+ // assert(SUG.str().size() > 2);
+
+ // Return a copy of the string that must be disposed by the caller.
+ return createCXString(SUG.str(), true);
+}
+
+extern "C" {
+
+CXString clang_getCursorUSR(CXCursor C) {
+ const CXCursorKind &K = clang_getCursorKind(C);
+
+ if (clang_isDeclaration(K))
+ return getDeclCursorUSR(C);
+
+ if (K == CXCursor_MacroDefinition) {
+ StringUSRGenerator SUG(&C);
+ SUG << "macro@"
+ << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
+ return createCXString(SUG.str(), true);
+ }
+
+ return createCXString("");
+}
+
+CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
+ SUG->GenObjCIvar(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCMethod(const char *name,
+ unsigned isInstanceMethod,
+ CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
+ SUG->GenObjCMethod(name, isInstanceMethod);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCClass(const char *name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCClass(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProtocol(const char *name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCProtocol(name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCCategory(const char *class_name,
+ const char *category_name) {
+ StringUSRGenerator SUG;
+ SUG->GenObjCCategory(class_name, category_name);
+ return createCXString(SUG.str(), true);
+}
+
+CXString clang_constructUSR_ObjCProperty(const char *property,
+ CXString classUSR) {
+ StringUSRGenerator SUG;
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
+ SUG->GenObjCProperty(property);
+ return createCXString(SUG.str(), true);
+}
+
+} // end extern "C"
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
new file mode 100644
index 000000000000..d5131ff6d869
--- /dev/null
+++ b/tools/libclang/CIndexer.cpp
@@ -0,0 +1,154 @@
+//===- CIndex.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 implements the Clang-C Source Indexing library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Program.h"
+
+#include <cstdio>
+#include <vector>
+#include <sstream>
+
+#ifdef LLVM_ON_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+using namespace clang;
+
+const llvm::sys::Path& CIndexer::getClangPath() {
+ // Did we already compute the path?
+ if (!ClangPath.empty())
+ return ClangPath;
+
+ // Find the location where this library lives (libCIndex.dylib).
+#ifdef LLVM_ON_WIN32
+ MEMORY_BASIC_INFORMATION mbi;
+ char path[MAX_PATH];
+ VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
+ sizeof(mbi));
+ GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
+
+ llvm::sys::Path CIndexPath(path);
+
+ CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("clang");
+ CIndexPath.appendSuffix("exe");
+ CIndexPath.makeAbsolute();
+#else
+ // This silly cast below avoids a C++ warning.
+ Dl_info info;
+ if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
+ assert(0 && "Call to dladdr() failed");
+
+ llvm::sys::Path CIndexPath(info.dli_fname);
+
+ // We now have the CIndex directory, locate clang relative to it.
+ CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("..");
+ CIndexPath.appendComponent("bin");
+ CIndexPath.appendComponent("clang");
+#endif
+
+ // Cache our result.
+ ClangPath = CIndexPath;
+ return ClangPath;
+}
+
+std::string CIndexer::getClangResourcesPath() {
+ llvm::sys::Path P = getClangPath();
+
+ if (!P.empty()) {
+ P.eraseComponent(); // Remove /clang from foo/bin/clang
+ P.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ }
+
+ 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) {
+ // Write the contents of this unsaved file into the temporary file.
+ 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())
+ return true;
+
+ OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
+ OS.close();
+ if (OS.has_error()) {
+ SavedFile.eraseFromDisk();
+ return true;
+ }
+
+ // Remap the file.
+ std::string RemapArg = unsaved_files[i].Filename;
+ RemapArg += ';';
+ RemapArg += SavedFile.str();
+ RemapArgs.push_back("-Xclang");
+ RemapArgs.push_back("-remap-file");
+ RemapArgs.push_back("-Xclang");
+ RemapArgs.push_back(RemapArg);
+ TemporaryFiles.push_back(SavedFile);
+ }
+
+ return false;
+}
+
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
new file mode 100644
index 000000000000..31bf779ea4a5
--- /dev/null
+++ b/tools/libclang/CIndexer.h
@@ -0,0 +1,78 @@
+//===- CIndexer.h - 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 CIndexer, a subclass of Indexer that provides extra
+// functionality needed by the CIndex library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CINDEXER_H
+#define LLVM_CLANG_CINDEXER_H
+
+#include "clang-c/Index.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/System/Path.h"
+#include <vector>
+
+namespace clang {
+namespace cxstring {
+ CXString createCXString(const char *String, bool DupString = false);
+ CXString createCXString(llvm::StringRef String, bool DupString = true);
+}
+}
+
+class CIndexer {
+ bool UseExternalASTGeneration;
+ bool OnlyLocalDecls;
+ bool DisplayDiagnostics;
+
+ llvm::sys::Path ClangPath;
+
+public:
+ CIndexer()
+ : UseExternalASTGeneration(false), OnlyLocalDecls(false),
+ DisplayDiagnostics(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
+ /// declarations.
+ 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;
+ }
+
+ /// \brief Get the path of the clang binary.
+ const llvm::sys::Path& getClangPath();
+
+ /// \brief Get the path of the clang resource files.
+ std::string getClangResourcesPath();
+};
+
+namespace clang {
+ /**
+ * \brief Given a set of "unsaved" files, create temporary files and
+ * construct the clang -cc1 argument list needed to perform the remapping.
+ *
+ * \returns true if an error occurred.
+ */
+ bool RemapFiles(unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ std::vector<std::string> &RemapArgs,
+ std::vector<llvm::sys::Path> &TemporaryFiles);
+}
+
+#endif
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
new file mode 100644
index 000000000000..d3de94a7a561
--- /dev/null
+++ b/tools/libclang/CMakeLists.txt
@@ -0,0 +1,57 @@
+set(SHARED_LIBRARY TRUE)
+
+set(LLVM_NO_RTTI 1)
+
+set(LLVM_USED_LIBS
+ clangFrontend
+ clangDriver
+ clangSema
+ clangAnalysis
+ clangAST
+ clangParse
+ clangLex
+ clangBasic)
+
+set( LLVM_LINK_COMPONENTS
+ bitreader
+ mc
+ core
+ )
+
+add_clang_library(libclang
+ CIndex.cpp
+ CIndexCodeCompletion.cpp
+ CIndexDiagnostic.cpp
+ CIndexInclusionStack.cpp
+ CIndexUSRs.cpp
+ CIndexer.cpp
+ CXCursor.cpp
+ ../../include/clang-c/Index.h
+)
+set_target_properties(libclang PROPERTIES OUTPUT_NAME clang)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ # FIXME: Deal with LLVM_SUBMIT_VERSION?
+
+ # FIXME: This uses a special darwin-specific exports file in order to
+ # get underscore-prefixed names. It would be better to have build rules
+ # which know how to produce a darwin-suitable exports file from the
+ # regular exports file.
+ set_target_properties(libclang
+ PROPERTIES
+ LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/libclang.darwin.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000"
+ INSTALL_NAME_DIR "@executable_path/../lib"
+ )
+endif()
+
+if(MSVC)
+ # windows.h doesn't compile with /Za
+ get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS)
+ string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+ set_target_properties(libclang PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
+endif(MSVC)
+
+set_target_properties(libclang
+ PROPERTIES
+ LINKER_LANGUAGE CXX
+ DEFINE_SYMBOL _CINDEX_LIB_)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
new file mode 100644
index 000000000000..c8eb4823779b
--- /dev/null
+++ b/tools/libclang/CXCursor.cpp
@@ -0,0 +1,370 @@
+//===- CXCursor.cpp - Routines for manipulating CXCursors -----------------===//
+//
+// 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 CXCursors. It should be the
+// only file that has internal knowledge of the encoding of the data in
+// CXCursor.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CXCursor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+
+CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
+ assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid);
+ CXCursor C = { K, { 0, 0, 0 } };
+ return C;
+}
+
+static CXCursorKind GetCursorKind(Decl *D) {
+ assert(D && "Invalid arguments!");
+ switch (D->getKind()) {
+ case Decl::Enum: return CXCursor_EnumDecl;
+ case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
+ case Decl::Field: return CXCursor_FieldDecl;
+ case Decl::Function:
+ return CXCursor_FunctionDecl;
+ case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
+ case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl;
+ case Decl::ObjCClass:
+ // FIXME
+ return CXCursor_UnexposedDecl;
+ case Decl::ObjCForwardProtocol:
+ // FIXME
+ return CXCursor_UnexposedDecl;
+ case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl;
+ case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
+ case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl;
+ case Decl::ObjCMethod:
+ return cast<ObjCMethodDecl>(D)->isInstanceMethod()
+ ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl;
+ case Decl::CXXMethod: return CXCursor_CXXMethod;
+ case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl;
+ case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
+ case Decl::ParmVar: return CXCursor_ParmDecl;
+ case Decl::Typedef: return CXCursor_TypedefDecl;
+ case Decl::Var: return CXCursor_VarDecl;
+ default:
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ switch (TD->getTagKind()) {
+ case TagDecl::TK_struct: return CXCursor_StructDecl;
+ case TagDecl::TK_class: return CXCursor_ClassDecl;
+ case TagDecl::TK_union: return CXCursor_UnionDecl;
+ case TagDecl::TK_enum: return CXCursor_EnumDecl;
+ }
+ }
+
+ return CXCursor_UnexposedDecl;
+ }
+
+ llvm_unreachable("Invalid Decl");
+ return CXCursor_NotImplemented;
+}
+
+static CXCursorKind GetCursorKind(const Attr *A) {
+ assert(A && "Invalid arguments!");
+ switch (A->getKind()) {
+ default: break;
+ case Attr::IBActionKind: return CXCursor_IBActionAttr;
+ case Attr::IBOutletKind: return CXCursor_IBOutletAttr;
+ }
+
+ return CXCursor_UnexposedAttr;
+}
+
+CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent, ASTUnit *TU) {
+ assert(A && Parent && TU && "Invalid arguments!");
+ CXCursor C = { GetCursorKind(A), { Parent, (void*)A, TU } };
+ return C;
+}
+
+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()) {
+ case Stmt::NoStmtClass:
+ break;
+
+ case Stmt::NullStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::IfStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::ReturnStmtClass:
+ case Stmt::DeclStmtClass:
+ case Stmt::SwitchCaseClass:
+ case Stmt::AsmStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtThrowStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXTryStmtClass:
+ K = CXCursor_UnexposedStmt;
+ break;
+
+ case Stmt::PredefinedExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::StringLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::ParenExprClass:
+ case Stmt::UnaryOperatorClass:
+ case Stmt::OffsetOfExprClass:
+ case Stmt::SizeOfAlignOfExprClass:
+ case Stmt::ArraySubscriptExprClass:
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ case Stmt::ConditionalOperatorClass:
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CompoundLiteralExprClass:
+ case Stmt::ExtVectorElementExprClass:
+ case Stmt::InitListExprClass:
+ case Stmt::DesignatedInitExprClass:
+ case Stmt::ImplicitValueInitExprClass:
+ case Stmt::ParenListExprClass:
+ case Stmt::VAArgExprClass:
+ case Stmt::AddrLabelExprClass:
+ case Stmt::StmtExprClass:
+ case Stmt::TypesCompatibleExprClass:
+ case Stmt::ChooseExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::CXXTypeidExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXThisExprClass:
+ case Stmt::CXXThrowExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXZeroInitValueExprClass:
+ case Stmt::CXXNewExprClass:
+ case Stmt::CXXDeleteExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
+ case Stmt::UnresolvedLookupExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
+ case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXBindReferenceExprClass:
+ case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::UnresolvedMemberExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCEncodeExprClass:
+ case Stmt::ObjCSelectorExprClass:
+ case Stmt::ObjCProtocolExprClass:
+ case Stmt::ObjCImplicitSetterGetterRefExprClass:
+ case Stmt::ObjCSuperExprClass:
+ case Stmt::ObjCIsaExprClass:
+ case Stmt::ShuffleVectorExprClass:
+ case Stmt::BlockExprClass:
+ K = CXCursor_UnexposedExpr;
+ break;
+ case Stmt::DeclRefExprClass:
+ case Stmt::BlockDeclRefExprClass:
+ // FIXME: UnresolvedLookupExpr?
+ // FIXME: DependentScopeDeclRefExpr?
+ K = CXCursor_DeclRefExpr;
+ break;
+
+ case Stmt::MemberExprClass:
+ case Stmt::ObjCIvarRefExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ // FIXME: UnresolvedMemberExpr?
+ // FIXME: CXXDependentScopeMemberExpr?
+ K = CXCursor_MemberRefExpr;
+ break;
+
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass:
+ case Stmt::CXXMemberCallExprClass:
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXTemporaryObjectExprClass:
+ // FIXME: CXXUnresolvedConstructExpr
+ // FIXME: ObjCImplicitSetterGetterRefExpr?
+ K = CXCursor_CallExpr;
+ break;
+
+ case Stmt::ObjCMessageExprClass:
+ K = CXCursor_ObjCMessageExpr;
+ break;
+ }
+
+ CXCursor C = { K, { Parent, S, TU } };
+ return C;
+}
+
+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;
+}
+
+std::pair<ObjCInterfaceDecl *, SourceLocation>
+cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
+ assert(C.kind == CXCursor_ObjCSuperClassRef);
+ return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+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;
+}
+
+std::pair<ObjCProtocolDecl *, SourceLocation>
+cxcursor::getCursorObjCProtocolRef(CXCursor C) {
+ assert(C.kind == CXCursor_ObjCProtocolRef);
+ return std::make_pair(static_cast<ObjCProtocolDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
+ SourceLocation Loc,
+ ASTUnit *TU) {
+ // 'Class' can be null for invalid code.
+ if (!Class)
+ return MakeCXCursorInvalid(CXCursor_InvalidCode);
+ assert(TU && "Invalid arguments!");
+ void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
+ return C;
+}
+
+std::pair<ObjCInterfaceDecl *, SourceLocation>
+cxcursor::getCursorObjCClassRef(CXCursor C) {
+ assert(C.kind == CXCursor_ObjCClassRef);
+ return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+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;
+}
+
+std::pair<TypeDecl *, SourceLocation>
+cxcursor::getCursorTypeRef(CXCursor C) {
+ assert(C.kind == CXCursor_TypeRef);
+ return std::make_pair(static_cast<TypeDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
+ ASTUnit *TU) {
+ CXCursor C = { CXCursor_PreprocessingDirective,
+ { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
+ reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
+ TU }
+ };
+ return C;
+}
+
+SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) {
+ assert(C.kind == CXCursor_PreprocessingDirective);
+ return SourceRange(SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t> (C.data[0])),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t> (C.data[1])));
+}
+
+CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI, ASTUnit *TU) {
+ CXCursor C = { CXCursor_MacroDefinition, { MI, 0, TU } };
+ return C;
+}
+
+MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
+ assert(C.kind == CXCursor_MacroDefinition);
+ return static_cast<MacroDefinition *>(C.data[0]);
+}
+
+CXCursor cxcursor::MakeMacroInstantiationCursor(MacroInstantiation *MI,
+ ASTUnit *TU) {
+ CXCursor C = { CXCursor_MacroInstantiation, { MI, 0, TU } };
+ return C;
+}
+
+MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) {
+ assert(C.kind == CXCursor_MacroInstantiation);
+ return static_cast<MacroInstantiation *>(C.data[0]);
+}
+
+Decl *cxcursor::getCursorDecl(CXCursor Cursor) {
+ return (Decl *)Cursor.data[0];
+}
+
+Expr *cxcursor::getCursorExpr(CXCursor Cursor) {
+ return dyn_cast_or_null<Expr>(getCursorStmt(Cursor));
+}
+
+Stmt *cxcursor::getCursorStmt(CXCursor Cursor) {
+ if (Cursor.kind == CXCursor_ObjCSuperClassRef ||
+ Cursor.kind == CXCursor_ObjCProtocolRef ||
+ Cursor.kind == CXCursor_ObjCClassRef)
+ return 0;
+
+ return (Stmt *)Cursor.data[1];
+}
+
+ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
+ return getCursorASTUnit(Cursor)->getASTContext();
+}
+
+ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) {
+ return static_cast<ASTUnit *>(Cursor.data[2]);
+}
+
+bool cxcursor::operator==(CXCursor X, CXCursor Y) {
+ return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] &&
+ X.data[2] == Y.data[2];
+}
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
new file mode 100644
index 000000000000..1664f5a9ced2
--- /dev/null
+++ b/tools/libclang/CXCursor.h
@@ -0,0 +1,112 @@
+//===- CXCursor.h - Routines for manipulating CXCursors -------------------===//
+//
+// 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 CXCursors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CXCURSOR_H
+#define LLVM_CLANG_CXCURSOR_H
+
+#include "clang-c/Index.h"
+#include "clang/Basic/SourceLocation.h"
+#include <utility>
+
+namespace clang {
+
+class ASTContext;
+class ASTUnit;
+class Attr;
+class Decl;
+class Expr;
+class MacroDefinition;
+class MacroInstantiation;
+class NamedDecl;
+class ObjCInterfaceDecl;
+class ObjCProtocolDecl;
+class Stmt;
+class TypeDecl;
+
+namespace cxcursor {
+
+CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent, ASTUnit *TU);
+CXCursor MakeCXCursor(clang::Decl *D, ASTUnit *TU);
+CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, ASTUnit *TU);
+CXCursor MakeCXCursorInvalid(CXCursorKind K);
+
+/// \brief Create an Objective-C superclass reference at the given location.
+CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
+ SourceLocation Loc,
+ ASTUnit *TU);
+
+/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references
+/// and optionally the location where the reference occurred.
+std::pair<ObjCInterfaceDecl *, SourceLocation>
+ getCursorObjCSuperClassRef(CXCursor C);
+
+/// \brief Create an Objective-C protocol reference at the given location.
+CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc,
+ ASTUnit *TU);
+
+/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references
+/// and optionally the location where the reference occurred.
+std::pair<ObjCProtocolDecl *, SourceLocation>
+ getCursorObjCProtocolRef(CXCursor C);
+
+/// \brief Create an Objective-C class reference at the given location.
+CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc,
+ ASTUnit *TU);
+
+/// \brief Unpack an ObjCClassRef cursor into the class it references
+/// and optionally the location where the reference occurred.
+std::pair<ObjCInterfaceDecl *, SourceLocation>
+ getCursorObjCClassRef(CXCursor C);
+
+/// \brief Create a type reference at the given location.
+CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU);
+
+/// \brief Unpack a TypeRef cursor into the class it references
+/// and optionally the location where the reference occurred.
+std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
+
+/// \brief Create a preprocessing directive cursor.
+CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU);
+
+/// \brief Unpack a given preprocessing directive to retrieve its source range.
+SourceRange getCursorPreprocessingDirective(CXCursor C);
+
+/// \brief Create a macro definition cursor.
+CXCursor MakeMacroDefinitionCursor(MacroDefinition *, ASTUnit *TU);
+
+/// \brief Unpack a given macro definition cursor to retrieve its
+/// source range.
+MacroDefinition *getCursorMacroDefinition(CXCursor C);
+
+/// \brief Create a macro instantiation cursor.
+CXCursor MakeMacroInstantiationCursor(MacroInstantiation *, ASTUnit *TU);
+
+/// \brief Unpack a given macro instantiation cursor to retrieve its
+/// source range.
+MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
+
+Decl *getCursorDecl(CXCursor Cursor);
+Expr *getCursorExpr(CXCursor Cursor);
+Stmt *getCursorStmt(CXCursor Cursor);
+ASTContext &getCursorContext(CXCursor Cursor);
+ASTUnit *getCursorASTUnit(CXCursor Cursor);
+
+bool operator==(CXCursor X, CXCursor Y);
+
+inline bool operator!=(CXCursor X, CXCursor Y) {
+ return !(X == Y);
+}
+
+}} // end namespace: clang::cxcursor
+
+#endif
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
new file mode 100644
index 000000000000..66566c126891
--- /dev/null
+++ b/tools/libclang/CXSourceLocation.h
@@ -0,0 +1,75 @@
+//===- 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/LangOptions.h"
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+
+class SourceManager;
+
+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/libclang/Makefile b/tools/libclang/Makefile
new file mode 100644
index 000000000000..a7877bf8e16b
--- /dev/null
+++ b/tools/libclang/Makefile
@@ -0,0 +1,55 @@
+##===- tools/libclang/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME = clang
+
+EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/libclang.exports
+
+CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+# 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 LINK_COMPONENTS before including Makefile.rules
+include $(LEVEL)/Makefile.config
+
+LINK_LIBS_IN_SHARED = 1
+SHARED_LIBRARY = 1
+
+LINK_COMPONENTS := bitreader mc core
+USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \
+ clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a
+
+include $(LEVEL)/Makefile.common
+
+##===----------------------------------------------------------------------===##
+# FIXME: This is copied from the 'lto' makefile. Should we share this?
+##===----------------------------------------------------------------------===##
+
+ifeq ($(HOST_OS),Darwin)
+ # set dylib internal version number to llvmCore submission number
+ ifdef LLVM_SUBMIT_VERSION
+ LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \
+ -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \
+ -Wl,-compatibility_version -Wl,1
+ endif
+ # extra options to override libtool defaults
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -avoid-version \
+ -Wl,-dead_strip \
+ -Wl,-seg1addr -Wl,0xE0000000
+
+ # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
+ DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
+ ifneq ($(DARWIN_VERS),8)
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -no-undefined -Wl,-install_name \
+ -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ endif
+endif
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
new file mode 100644
index 000000000000..b36116805311
--- /dev/null
+++ b/tools/libclang/libclang.darwin.exports
@@ -0,0 +1,81 @@
+_clang_annotateTokens
+_clang_codeComplete
+_clang_codeCompleteGetDiagnostic
+_clang_codeCompleteGetNumDiagnostics
+_clang_constructUSR_ObjCCategory
+_clang_constructUSR_ObjCClass
+_clang_constructUSR_ObjCIvar
+_clang_constructUSR_ObjCMethod
+_clang_constructUSR_ObjCProperty
+_clang_constructUSR_ObjCProtocol
+_clang_createIndex
+_clang_createTranslationUnit
+_clang_createTranslationUnitFromSourceFile
+_clang_defaultDiagnosticDisplayOptions
+_clang_disposeCodeCompleteResults
+_clang_disposeDiagnostic
+_clang_disposeIndex
+_clang_disposeString
+_clang_disposeTokens
+_clang_disposeTranslationUnit
+_clang_enableStackTraces
+_clang_equalCursors
+_clang_equalLocations
+_clang_formatDiagnostic
+_clang_getCString
+_clang_getClangVersion
+_clang_getCompletionChunkCompletionString
+_clang_getCompletionChunkKind
+_clang_getCompletionChunkText
+_clang_getCursor
+_clang_getCursorDefinition
+_clang_getCursorExtent
+_clang_getCursorKind
+_clang_getCursorKindSpelling
+_clang_getCursorLanguage
+_clang_getCursorLinkage
+_clang_getCursorLocation
+_clang_getCursorReferenced
+_clang_getCursorSpelling
+_clang_getCursorUSR
+_clang_getDefinitionSpellingAndExtent
+_clang_getDiagnostic
+_clang_getDiagnosticFixIt
+_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_getNumDiagnostics
+_clang_getRange
+_clang_getRangeEnd
+_clang_getRangeStart
+_clang_getTokenExtent
+_clang_getTokenKind
+_clang_getTokenLocation
+_clang_getTokenSpelling
+_clang_getTranslationUnitCursor
+_clang_getTranslationUnitSpelling
+_clang_isCursorDefinition
+_clang_isDeclaration
+_clang_isExpression
+_clang_isInvalid
+_clang_isPreprocessing
+_clang_isReference
+_clang_isStatement
+_clang_isTranslationUnit
+_clang_isUnexposed
+_clang_setUseExternalASTGeneration
+_clang_tokenize
+_clang_visitChildren
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
new file mode 100644
index 000000000000..991bb067f7d0
--- /dev/null
+++ b/tools/libclang/libclang.exports
@@ -0,0 +1,81 @@
+clang_annotateTokens
+clang_codeComplete
+clang_codeCompleteGetDiagnostic
+clang_codeCompleteGetNumDiagnostics
+clang_constructUSR_ObjCCategory
+clang_constructUSR_ObjCClass
+clang_constructUSR_ObjCIvar
+clang_constructUSR_ObjCMethod
+clang_constructUSR_ObjCProperty
+clang_constructUSR_ObjCProtocol
+clang_createIndex
+clang_createTranslationUnit
+clang_createTranslationUnitFromSourceFile
+clang_defaultDiagnosticDisplayOptions
+clang_disposeCodeCompleteResults
+clang_disposeDiagnostic
+clang_disposeIndex
+clang_disposeString
+clang_disposeTokens
+clang_disposeTranslationUnit
+clang_enableStackTraces
+clang_equalCursors
+clang_equalLocations
+clang_formatDiagnostic
+clang_getCString
+clang_getClangVersion
+clang_getCompletionChunkCompletionString
+clang_getCompletionChunkKind
+clang_getCompletionChunkText
+clang_getCursor
+clang_getCursorDefinition
+clang_getCursorExtent
+clang_getCursorKind
+clang_getCursorKindSpelling
+clang_getCursorLanguage
+clang_getCursorLinkage
+clang_getCursorLocation
+clang_getCursorReferenced
+clang_getCursorSpelling
+clang_getCursorUSR
+clang_getDefinitionSpellingAndExtent
+clang_getDiagnostic
+clang_getDiagnosticFixIt
+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_getNumDiagnostics
+clang_getRange
+clang_getRangeEnd
+clang_getRangeStart
+clang_getTokenExtent
+clang_getTokenKind
+clang_getTokenLocation
+clang_getTokenSpelling
+clang_getTranslationUnitCursor
+clang_getTranslationUnitSpelling
+clang_isCursorDefinition
+clang_isDeclaration
+clang_isExpression
+clang_isInvalid
+clang_isPreprocessing
+clang_isReference
+clang_isStatement
+clang_isTranslationUnit
+clang_isUnexposed
+clang_setUseExternalASTGeneration
+clang_tokenize
+clang_visitChildren
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index daf5f7f9ef48..391ea57faa23 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -139,12 +139,7 @@ sub GetCCArgs {
# Strip the newline and initial whitspace
chomp $line;
$line =~ s/^\s+//;
-
- my @items = quotewords('\s+', 1, $line);
- for (my $i = 0 ; $ i < scalar(@items); ++$i) {
- $items[$i] =~ s/^\"//;
- $items[$i] =~ s/\"$//;
- }
+ my @items = quotewords('\s+', 0, $line);
my $cmd = shift @items;
die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/));
return \@items;
diff --git a/utils/CIndex/completion_logger_server.py b/utils/CIndex/completion_logger_server.py
new file mode 100755
index 000000000000..0652b1f4a8ee
--- /dev/null
+++ b/utils/CIndex/completion_logger_server.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+import sys
+from socket import *
+from time import strftime
+import datetime
+
+def main():
+ if len(sys.argv) < 4:
+ print "completion_logger_server.py <listen address> <listen port> <log file>"
+ exit(1)
+
+ host = sys.argv[1]
+ port = int(sys.argv[2])
+ buf = 1024 * 8
+ addr = (host,port)
+
+ # Create socket and bind to address
+ UDPSock = socket(AF_INET,SOCK_DGRAM)
+ UDPSock.bind(addr)
+
+ print "Listing on {0}:{1} and logging to '{2}'".format(host, port, sys.argv[3])
+
+ # Open the logging file.
+ f = open(sys.argv[3], "a")
+
+ # Receive messages
+ while 1:
+ data,addr = UDPSock.recvfrom(buf)
+ if not data:
+ break
+ else:
+ f.write("{ ");
+ f.write("\"time\": \"{0}\"".format(datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')))
+ f.write(", \"sender\": \"{0}\" ".format(addr[0]))
+ f.write(", \"data\": ")
+ f.write(data)
+ f.write(" }\n")
+ f.flush()
+
+ # Close socket
+ UDPSock.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 621b2f0da646..413130609217 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://checker.minormatter.com/checker-238.tar.bz2">checker-238.tar.bz2</a></b> (built April 1, 2010)
+<b><a href="http://checker.minormatter.com/checker-240.tar.bz2">checker-240.tar.bz2</a></b> (built April 11, 2010)
diff --git a/www/clang_video-05-25-2007.html b/www/clang_video-05-25-2007.html
index ade0269f4688..a85cadcb1d03 100644
--- a/www/clang_video-05-25-2007.html
+++ b/www/clang_video-05-25-2007.html
@@ -24,4 +24,4 @@
</ul>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/www/clang_video-07-25-2007.html b/www/clang_video-07-25-2007.html
index d2225896c50b..179e499651a4 100644
--- a/www/clang_video-07-25-2007.html
+++ b/www/clang_video-07-25-2007.html
@@ -27,4 +27,4 @@
<i>Google Tech Talk</i>, Mountain View, CA, July 2007.
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/www/cxx_compatibility.html b/www/cxx_compatibility.html
index e5fd63ef9c97..bd48c6c09d38 100644
--- a/www/cxx_compatibility.html
+++ b/www/cxx_compatibility.html
@@ -25,6 +25,7 @@
<li><a href="#init_static_const">Initialization of non-integral static const data members within a class definition</a></li>
<li><a href="#dep_lookup">Unqualified lookup in templates</a></li>
<li><a href="#dep_lookup_bases">Unqualified lookup into dependent bases of class templates</a></li>
+<li><a href="#bad_templates">Templates with no valid instantiations</a></li>
<li><a href="#default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</a></li>
</ul>
@@ -203,6 +204,53 @@ if <tt>DoThis</tt> is virtual, calling it this way will bypass virtual
dispatch!
<!-- ======================================================================= -->
+<h2 id="bad_templates">Templates with no valid instantiations</h2>
+<!-- ======================================================================= -->
+
+The following code contains a typo: the programmer
+meant <tt>init()</tt> but wrote <tt>innit()</tt> instead.
+
+<pre>
+ template &lt;class T&gt; class Processor {
+ ...
+ void init();
+ ...
+ };
+ ...
+ template &lt;class T&gt; void process() {
+ Processor&lt;T&gt; processor;
+ processor.innit(); // <-- should be 'init()'
+ ...
+ }
+</pre>
+
+Unfortunately, we can't flag this mistake as soon as we see it: inside
+a template, we're not allowed to make assumptions about "dependent
+types" like <tt>Processor&lt;T&gt;</tt>. Suppose that later on in
+this file the programmer adds an explicit specialization
+of <tt>Processor</tt>, like so:
+
+<pre>
+ template &lt;&gt; class Processor&lt;char*&gt; {
+ void innit();
+ };
+</pre>
+
+Now the program will work &mdash; as long as the programmer only ever
+instantiates <tt>process()</tt> with <tt>T = char*</tt>! This is why
+it's hard, and sometimes impossible, to diagnose mistakes in a
+template definition before it's instantiated.
+
+<p>The standard says that a template with no valid instantiations is
+ill-formed. Clang tries to do as much checking as possible at
+definition-time instead of instantiation-time: not only does this
+produce clearer diagnostics, but it also substantially improves
+compile times when using pre-compiled headers. The downside to this
+philosophy is that Clang sometimes fails to process files because they
+contain broken templates that are no longer used. The solution is
+simple: since the code is unused, just remove it.
+
+<!-- ======================================================================= -->
<h2 id="default_init_const">Default initialization of const variable of a class type requires user-defined default constructor</h2>
<!-- ======================================================================= -->
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 0da84c2048b5..9ba3200faba8 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -24,7 +24,7 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2010-02-09 17:50:54 +0100 (Tue, 09 Feb 2010) $</p>
+<p>Last updated: $Date: 2010-04-12 18:01:38 +0200 (Mon, 12 Apr 2010) $</p>
<h1>Clang C++ Status</h1>
@@ -34,34 +34,9 @@
<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 currently implements nearly all of the ISO C++ 1998 standard (including the defects addressed in the ISO C++ 2003 standard). 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>
+ <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
diff --git a/www/menu.css b/www/menu.css
index 6e96a457ab53..4a887b1907a3 100644
--- a/www/menu.css
+++ b/www/menu.css
@@ -36,4 +36,4 @@
}
#menu a:visited {
color:rgb(100,50,100);
-} \ No newline at end of file
+}