aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-04-02 08:55:10 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-04-02 08:55:10 +0000
commit11d2b2d2bb706fca0656f2760839721bb7f6cb6f (patch)
treed374cdca417e76f1bf101f139dba2db1d10ee8f7
parentc0c7bca4e5b8d12699dc93a0da49e9e4bb79671b (diff)
downloadsrc-11d2b2d2bb706fca0656f2760839721bb7f6cb6f.tar.gz
src-11d2b2d2bb706fca0656f2760839721bb7f6cb6f.zip
Update clang to r100181.
Notes
Notes: svn path=/vendor/clang/dist/; revision=206084
-rw-r--r--CMakeLists.txt6
-rw-r--r--clang.xcodeproj/project.pbxproj42
-rw-r--r--examples/clang-interpreter/main.cpp3
-rw-r--r--include/clang/AST/ASTContext.h48
-rw-r--r--include/clang/AST/CXXInheritance.h132
-rw-r--r--include/clang/AST/CanonicalType.h11
-rw-r--r--include/clang/AST/Decl.h57
-rw-r--r--include/clang/AST/DeclBase.h43
-rw-r--r--include/clang/AST/DeclCXX.h35
-rw-r--r--include/clang/AST/DeclContextInternals.h24
-rw-r--r--include/clang/AST/DeclFriend.h6
-rw-r--r--include/clang/AST/DeclTemplate.h6
-rw-r--r--include/clang/AST/DeclarationName.h2
-rw-r--r--include/clang/AST/DependentDiagnostic.h183
-rw-r--r--include/clang/AST/Expr.h51
-rw-r--r--include/clang/AST/ExprCXX.h4
-rw-r--r--include/clang/AST/Type.h235
-rw-r--r--include/clang/AST/TypeLoc.h6
-rw-r--r--include/clang/AST/TypeNodes.def2
-rw-r--r--include/clang/Analysis/AnalysisContext.h31
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h45
-rw-r--r--include/clang/Basic/Builtins.def15
-rw-r--r--include/clang/Basic/BuiltinsX86.def8
-rw-r--r--include/clang/Basic/CMakeLists.txt8
-rw-r--r--include/clang/Basic/Diagnostic.h160
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticGroups.td5
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td22
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td82
-rw-r--r--include/clang/Basic/PartialDiagnostic.h177
-rw-r--r--include/clang/Basic/SourceLocation.h1
-rw-r--r--include/clang/Checker/BugReporter/BugReporter.h7
-rw-r--r--include/clang/Checker/BugReporter/BugType.h7
-rw-r--r--include/clang/Checker/BugReporter/PathDiagnostic.h18
-rw-r--r--include/clang/Checker/DomainSpecific/CocoaConventions.h1
-rw-r--r--include/clang/Checker/PathSensitive/BasicValueFactory.h1
-rw-r--r--include/clang/Checker/PathSensitive/Checker.h8
-rw-r--r--include/clang/Checker/PathSensitive/Environment.h5
-rw-r--r--include/clang/Checker/PathSensitive/ExplodedGraph.h4
-rw-r--r--include/clang/Checker/PathSensitive/GRBlockCounter.h9
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h10
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h24
-rw-r--r--include/clang/Checker/PathSensitive/GRSimpleAPICheck.h9
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h34
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h3
-rw-r--r--include/clang/Checker/PathSensitive/GRTransferFuncs.h10
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h10
-rw-r--r--include/clang/Checker/PathSensitive/Store.h3
-rw-r--r--include/clang/Checker/PathSensitive/SymbolManager.h10
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h1
-rw-r--r--include/clang/Driver/CC1Options.td3
-rw-r--r--include/clang/Driver/CMakeLists.txt4
-rw-r--r--include/clang/Driver/Driver.h9
-rw-r--r--include/clang/Driver/Options.td3
-rw-r--r--include/clang/Frontend/HeaderSearchOptions.h6
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h2
-rw-r--r--include/clang/Frontend/TypeXML.def2
-rw-r--r--include/clang/Lex/PPCallbacks.h11
-rw-r--r--include/clang/Lex/Preprocessor.h4
-rw-r--r--include/clang/Lex/PreprocessorLexer.h1
-rw-r--r--include/clang/Parse/Action.h3
-rw-r--r--lib/AST/ASTContext.cpp194
-rw-r--r--lib/AST/ASTImporter.cpp22
-rw-r--r--lib/AST/CMakeLists.txt4
-rw-r--r--lib/AST/CXXInheritance.cpp237
-rw-r--r--lib/AST/Decl.cpp6
-rw-r--r--lib/AST/DeclBase.cpp96
-rw-r--r--lib/AST/DeclCXX.cpp133
-rw-r--r--lib/AST/Expr.cpp62
-rw-r--r--lib/AST/Type.cpp36
-rw-r--r--lib/AST/TypePrinter.cpp22
-rw-r--r--lib/Analysis/AnalysisContext.cpp28
-rw-r--r--lib/Analysis/CFG.cpp2
-rw-r--r--lib/Analysis/PrintfFormatString.cpp2
-rw-r--r--lib/Basic/Diagnostic.cpp85
-rw-r--r--lib/Basic/SourceManager.cpp20
-rw-r--r--lib/Basic/Targets.cpp1
-rw-r--r--lib/Checker/AdjustedReturnValueChecker.cpp4
-rw-r--r--lib/Checker/AggExprVisitor.cpp55
-rw-r--r--lib/Checker/ArrayBoundChecker.cpp4
-rw-r--r--lib/Checker/AttrNonNullChecker.cpp4
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp3
-rw-r--r--lib/Checker/BugReporter.cpp6
-rw-r--r--lib/Checker/BugReporterVisitors.cpp1
-rw-r--r--lib/Checker/CFRefCount.cpp3
-rw-r--r--lib/Checker/CMakeLists.txt17
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp6
-rw-r--r--lib/Checker/CastToStructChecker.cpp1
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp40
-rw-r--r--lib/Checker/DereferenceChecker.cpp59
-rw-r--r--lib/Checker/DivZeroChecker.cpp3
-rw-r--r--lib/Checker/Environment.cpp5
-rw-r--r--lib/Checker/FixedAddressChecker.cpp3
-rw-r--r--lib/Checker/GRBlockCounter.cpp43
-rw-r--r--lib/Checker/GRCoreEngine.cpp10
-rw-r--r--lib/Checker/GRExprEngine.cpp139
-rw-r--r--lib/Checker/GRState.cpp14
-rw-r--r--lib/Checker/MacOSXAPIChecker.cpp2
-rw-r--r--lib/Checker/MallocChecker.cpp1
-rw-r--r--lib/Checker/MemRegion.cpp4
-rw-r--r--lib/Checker/NSErrorChecker.cpp2
-rw-r--r--lib/Checker/NoReturnFunctionChecker.cpp82
-rw-r--r--lib/Checker/PathDiagnostic.cpp4
-rw-r--r--lib/Checker/PointerArithChecker.cpp3
-rw-r--r--lib/Checker/PointerSubChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp108
-rw-r--r--lib/Checker/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/Checker/ReturnStackAddressChecker.cpp2
-rw-r--r--lib/Checker/ReturnUndefChecker.cpp5
-rw-r--r--lib/Checker/SymbolManager.cpp2
-rw-r--r--lib/Checker/UndefBranchChecker.cpp1
-rw-r--r--lib/Checker/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--lib/Checker/UndefResultChecker.cpp2
-rw-r--r--lib/Checker/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/Checker/UndefinedAssignmentChecker.cpp40
-rw-r--r--lib/Checker/UnixAPIChecker.cpp5
-rw-r--r--lib/Checker/VLASizeChecker.cpp2
-rw-r--r--lib/CodeGen/CGBlocks.cpp20
-rw-r--r--lib/CodeGen/CGBlocks.h1
-rw-r--r--lib/CodeGen/CGBuiltin.cpp17
-rw-r--r--lib/CodeGen/CGCXX.cpp315
-rw-r--r--lib/CodeGen/CGCall.cpp48
-rw-r--r--lib/CodeGen/CGCall.h15
-rw-r--r--lib/CodeGen/CGClass.cpp327
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp72
-rw-r--r--lib/CodeGen/CGDebugInfo.h5
-rw-r--r--lib/CodeGen/CGExpr.cpp15
-rw-r--r--lib/CodeGen/CGExprAgg.cpp7
-rw-r--r--lib/CodeGen/CGExprCXX.cpp48
-rw-r--r--lib/CodeGen/CGExprComplex.cpp30
-rw-r--r--lib/CodeGen/CGExprConstant.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp9
-rw-r--r--lib/CodeGen/CGObjC.cpp27
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp6
-rw-r--r--lib/CodeGen/CGObjCMac.cpp23
-rw-r--r--lib/CodeGen/CGObjCRuntime.h1
-rw-r--r--lib/CodeGen/CGRTTI.cpp156
-rw-r--r--lib/CodeGen/CGRecordLayout.h95
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp176
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h142
-rw-r--r--lib/CodeGen/CGStmt.cpp3
-rw-r--r--lib/CodeGen/CGTemporaries.cpp15
-rw-r--r--lib/CodeGen/CGVTT.cpp608
-rw-r--r--lib/CodeGen/CGVtable.cpp2089
-rw-r--r--lib/CodeGen/CGVtable.h257
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp8
-rw-r--r--lib/CodeGen/CodeGenFunction.h70
-rw-r--r--lib/CodeGen/CodeGenModule.cpp32
-rw-r--r--lib/CodeGen/CodeGenModule.h37
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp48
-rw-r--r--lib/CodeGen/CodeGenTypes.h82
-rw-r--r--lib/CodeGen/Mangle.cpp98
-rw-r--r--lib/CodeGen/Mangle.h16
-rw-r--r--lib/Driver/CMakeLists.txt2
-rw-r--r--lib/Driver/Driver.cpp26
-rw-r--r--lib/Driver/HostInfo.cpp10
-rw-r--r--lib/Driver/Tools.cpp65
-rw-r--r--lib/Frontend/ASTUnit.cpp2
-rw-r--r--lib/Frontend/CompilerInstance.cpp4
-rw-r--r--lib/Frontend/CompilerInvocation.cpp3
-rw-r--r--lib/Frontend/DependencyFile.cpp9
-rw-r--r--lib/Frontend/FixItRewriter.cpp14
-rw-r--r--lib/Frontend/FrontendAction.cpp4
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp3
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp11
-rw-r--r--lib/Frontend/PCHReader.cpp34
-rw-r--r--lib/Frontend/PCHWriter.cpp15
-rw-r--r--lib/Frontend/RewriteObjC.cpp51
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp14
-rw-r--r--lib/Headers/emmintrin.h426
-rw-r--r--lib/Headers/mm_malloc.h9
-rw-r--r--lib/Headers/mmintrin.h134
-rw-r--r--lib/Headers/pmmintrin.h26
-rw-r--r--lib/Headers/smmintrin.h128
-rw-r--r--lib/Headers/tmmintrin.h60
-rw-r--r--lib/Headers/wmmintrin.h67
-rw-r--r--lib/Headers/xmmintrin.h240
-rw-r--r--lib/Lex/Lexer.cpp3
-rw-r--r--lib/Lex/PPDirectives.cpp6
-rw-r--r--lib/Lex/PPLexerChange.cpp1
-rw-r--r--lib/Lex/PPMacroExpansion.cpp11
-rw-r--r--lib/Lex/Preprocessor.cpp5
-rw-r--r--lib/Lex/TokenConcatenation.cpp2
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Parse/DeclSpec.cpp4
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp25
-rw-r--r--lib/Parse/ParseDecl.cpp10
-rw-r--r--lib/Parse/ParseDeclCXX.cpp11
-rw-r--r--lib/Parse/ParseExprCXX.cpp4
-rw-r--r--lib/Parse/ParseInit.cpp7
-rw-r--r--lib/Parse/ParseObjc.cpp13
-rw-r--r--lib/Parse/ParseStmt.cpp8
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/Parser.cpp10
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp110
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h42
-rw-r--r--lib/Sema/Lookup.h6
-rw-r--r--lib/Sema/Sema.cpp27
-rw-r--r--lib/Sema/Sema.h162
-rw-r--r--lib/Sema/SemaAccess.cpp760
-rw-r--r--lib/Sema/SemaCXXCast.cpp58
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp8
-rw-r--r--lib/Sema/SemaChecking.cpp64
-rw-r--r--lib/Sema/SemaDecl.cpp391
-rw-r--r--lib/Sema/SemaDeclAttr.cpp31
-rw-r--r--lib/Sema/SemaDeclCXX.cpp704
-rw-r--r--lib/Sema/SemaDeclObjC.cpp48
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp154
-rw-r--r--lib/Sema/SemaExpr.cpp243
-rw-r--r--lib/Sema/SemaExprCXX.cpp249
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp86
-rw-r--r--lib/Sema/SemaInit.h10
-rw-r--r--lib/Sema/SemaLookup.cpp21
-rw-r--r--lib/Sema/SemaObjCProperty.cpp29
-rw-r--r--lib/Sema/SemaOverload.cpp130
-rw-r--r--lib/Sema/SemaStmt.cpp57
-rw-r--r--lib/Sema/SemaTemplate.cpp672
-rw-r--r--lib/Sema/SemaTemplate.h34
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp273
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp131
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp316
-rw-r--r--lib/Sema/SemaType.cpp84
-rw-r--r--lib/Sema/TreeTransform.h126
-rw-r--r--test/Analysis/PR3991.m20
-rw-r--r--test/Analysis/inline.c2
-rw-r--r--test/Analysis/misc-ps-region-store.m45
-rw-r--r--test/Analysis/no-outofbounds.c3
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/outofbound.c23
-rw-r--r--test/Analysis/plist-output.m40
-rw-r--r--test/Analysis/pr4209.m8
-rw-r--r--test/Analysis/retain-release-region-store.m16
-rw-r--r--test/Analysis/retain-release.m9
-rw-r--r--test/Analysis/uninit-vals-ps-region.m7
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp12
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp13
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp9
-rw-r--r--test/CXX/class.access/class.access.base/p5.cpp75
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp43
-rw-r--r--test/CXX/class.access/p4.cpp69
-rw-r--r--test/CXX/class.derived/class.abstract/p4.cpp80
-rw-r--r--test/CXX/class.derived/class.abstract/p5.cpp23
-rw-r--r--test/CXX/class.derived/class.virtual/p2.cpp37
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp43
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp14
-rw-r--r--test/CXX/stmt.stmt/stmt.select/p3.cpp11
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp4
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp80
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp131
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp26
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp31
-rw-r--r--test/CXX/temp/temp.res/temp.local/p1.cpp3
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp2
-rw-r--r--test/CodeGen/atomic.c6
-rw-r--r--test/CodeGen/mangle.c4
-rw-r--r--test/CodeGen/palignr.c2
-rw-r--r--test/CodeGen/regparm.c11
-rw-r--r--test/CodeGen/restrict.c26
-rw-r--r--test/CodeGenCXX/constructor-init.cpp21
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp54
-rw-r--r--test/CodeGenCXX/member-expressions.cpp40
-rw-r--r--test/CodeGenCXX/multi-dim-operator-new.cpp49
-rw-r--r--test/CodeGenCXX/references.cpp8
-rw-r--r--test/CodeGenCXX/rtti-fundamental.cpp71
-rw-r--r--test/CodeGenCXX/rtti-linkage.cpp1
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp76
-rw-r--r--test/CodeGenCXX/temporaries.cpp13
-rw-r--r--test/CodeGenCXX/thunks.cpp137
-rw-r--r--test/CodeGenCXX/virt.cpp52
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp23
-rw-r--r--test/CodeGenCXX/vtable-layout-abi-examples.cpp1
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp49
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp20
-rw-r--r--test/CodeGenObjC/complex-property.m32
-rw-r--r--test/CodeGenObjC/objc2-nonfragile-abi-impl.m15
-rw-r--r--test/Driver/nostdincxx.cpp4
-rw-r--r--test/FixIt/fixit.cpp3
-rw-r--r--test/Headers/c89.c10
-rw-r--r--test/Headers/x86-intrinsics-headers.c (renamed from test/Sema/x86-intrinsics-headers.c)0
-rw-r--r--test/Index/Inputs/remap-complete-to.c7
-rw-r--r--test/Index/cindex-on-invalid.m7
-rw-r--r--test/Index/print-usrs.c17
-rw-r--r--test/Index/recover-bad-code-rdar_7487294.c1
-rw-r--r--test/Index/remap-complete.c7
-rw-r--r--test/PCH/changed-files.c36
-rw-r--r--test/Parser/cxx-default-args.cpp9
-rw-r--r--test/Parser/objc-messaging-neg-1.m6
-rw-r--r--test/Parser/statements.c5
-rw-r--r--test/Preprocessor/dependencies-and-pp.c26
-rw-r--r--test/Preprocessor/macro_disable.c34
-rw-r--r--test/Preprocessor/macro_disable2.c8
-rw-r--r--test/Preprocessor/macro_disable3.c10
-rw-r--r--test/Preprocessor/macro_disable4.c6
-rw-r--r--test/Preprocessor/output_paste_avoid.c4
-rw-r--r--test/Sema/attr-format.c (renamed from test/Sema/format-attribute.c)46
-rw-r--r--test/Sema/attr-sentinel.c (renamed from test/Sema/function-sentinel-attr.c)24
-rw-r--r--test/Sema/attr-unused.c17
-rw-r--r--test/Sema/format-attr-pr4470.c12
-rw-r--r--test/Sema/format-attribute-printf0.c26
-rw-r--r--test/Sema/format-strings.c13
-rw-r--r--test/Sema/function-pointer-sentinel-attribute.c20
-rw-r--r--test/Sema/init.c3
-rw-r--r--test/Sema/nested-redef.c3
-rw-r--r--test/Sema/return.c17
-rw-r--r--test/Sema/struct-packed-align.c8
-rw-r--r--test/Sema/warn-gnu-designators.c2
-rw-r--r--test/Sema/warn-shadow.c5
-rw-r--r--test/SemaCXX/PR6618.cpp13
-rw-r--r--test/SemaCXX/class-base-member-init.cpp44
-rw-r--r--test/SemaCXX/class-layout.cpp7
-rw-r--r--test/SemaCXX/conditional-expr.cpp18
-rw-r--r--test/SemaCXX/destructor.cpp5
-rw-r--r--test/SemaCXX/exception-spec.cpp6
-rw-r--r--test/SemaCXX/invalid-member-expr.cpp18
-rw-r--r--test/SemaCXX/namespace-alias.cpp10
-rw-r--r--test/SemaCXX/namespace.cpp22
-rw-r--r--test/SemaCXX/nested-name-spec.cpp2
-rw-r--r--test/SemaCXX/new-delete-predefined-decl-2.cpp13
-rw-r--r--test/SemaCXX/qual-id-test.cpp9
-rw-r--r--test/SemaCXX/static-cast.cpp4
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp12
-rw-r--r--test/SemaObjC/block-type-safety.m8
-rw-r--r--test/SemaObjC/category-1.m6
-rw-r--r--test/SemaObjC/compare-qualified-id.m7
-rw-r--r--test/SemaObjC/comptypes-7.m5
-rw-r--r--test/SemaObjC/conditional-expr.m4
-rw-r--r--test/SemaObjC/gcc-cast-ext.m6
-rw-r--r--test/SemaObjC/ivar-in-class-extension-error.m15
-rw-r--r--test/SemaObjC/ivar-in-implementations.m23
-rw-r--r--test/SemaObjC/ivar-sem-check-1.m3
-rw-r--r--test/SemaObjC/method-arg-decay.m10
-rw-r--r--test/SemaObjC/method-undef-category-warn-1.m22
-rw-r--r--test/SemaObjC/method-undef-extension-warn-1.m10
-rw-r--r--test/SemaObjC/method-undefined-warn-1.m16
-rw-r--r--test/SemaObjC/method-warn-unused-attribute.m12
-rw-r--r--test/SemaObjC/no-protocol-option-tests.m32
-rw-r--r--test/SemaObjC/nsobject-attribute.m6
-rw-r--r--test/SemaObjC/property-expression-error.m5
-rw-r--r--test/SemaObjC/property-in-class-extension.m15
-rw-r--r--test/SemaObjC/property-ivar-mismatch.m4
-rw-r--r--test/SemaObjC/property.m4
-rw-r--r--test/SemaObjC/undef-protocol-methods-1.m34
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp2
-rw-r--r--test/SemaTemplate/friend-template.cpp8
-rw-r--r--test/SemaTemplate/instantiate-declref.cpp2
-rw-r--r--test/SemaTemplate/instantiate-elab-type-specifier.cpp13
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp13
-rw-r--r--test/SemaTemplate/instantiate-function-params.cpp57
-rw-r--r--test/SemaTemplate/instantiate-init.cpp18
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp30
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp6
-rw-r--r--test/SemaTemplate/instantiation-default-2.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp33
-rw-r--r--tools/CIndex/CIndex.cpp7
-rw-r--r--tools/CIndex/CIndexDiagnostic.cpp3
-rw-r--r--tools/CIndex/CIndexUSRs.cpp21
-rw-r--r--tools/CIndex/CMakeLists.txt4
-rw-r--r--tools/c-index-test/c-index-test.c191
-rw-r--r--tools/driver/Makefile8
-rw-r--r--tools/driver/cc1_main.cpp53
-rw-r--r--tools/driver/driver.cpp28
-rwxr-xr-xtools/scan-build/scan-build11
-rw-r--r--utils/VtableTest/Makefile9
-rwxr-xr-xutils/VtableTest/check-ztt8
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/get_started.html2
367 files changed, 11197 insertions, 6519 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e84d94a3b64..2001c7125d9a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,6 +92,12 @@ install(DIRECTORY include/
PATTERN ".svn" EXCLUDE
)
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
+ DESTINATION include
+ FILES_MATCHING
+ PATTERN "*.inc"
+ )
+
add_definitions( -D_GNU_SOURCE )
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 7bf633532d2a..efdc3b325193 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -12,7 +12,6 @@
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 */; };
- 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */; };
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */; };
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */; };
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */; };
@@ -70,6 +69,8 @@
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 */; };
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; };
3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; };
@@ -149,6 +150,11 @@
90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */; };
90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6DB5103D977E005F5B73 /* index-test.cpp */; };
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; };
+ BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */; };
+ BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */; };
+ BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3F811595A01001C2D68 /* SemaType.cpp */; };
+ BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */; };
+ BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */; };
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
@@ -365,7 +371,6 @@
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; };
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = "<group>"; };
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = "<group>"; };
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = "<group>"; };
1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = "<group>"; };
1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = lib/Frontend/DiagChecker.cpp; sourceTree = "<group>"; };
@@ -446,8 +451,9 @@
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>"; };
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; };
352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
@@ -618,6 +624,15 @@
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisBasedWarnings.h; path = lib/Sema/AnalysisBasedWarnings.h; sourceTree = "<group>"; };
+ BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisBasedWarnings.cpp; path = lib/Sema/AnalysisBasedWarnings.cpp; sourceTree = "<group>"; };
+ BF89C3E311595835001C2D68 /* Lookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Lookup.h; path = lib/Sema/Lookup.h; sourceTree = "<group>"; };
+ BF89C3E411595855001C2D68 /* SemaInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaInit.h; path = lib/Sema/SemaInit.h; sourceTree = "<group>"; };
+ BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetAttributesSema.h; path = lib/Sema/TargetAttributesSema.h; sourceTree = "<group>"; };
+ BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaObjCProperty.cpp; path = lib/Sema/SemaObjCProperty.cpp; sourceTree = "<group>"; };
+ BF89C3F811595A01001C2D68 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; sourceTree = "<group>"; };
+ BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; };
+ BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExceptionSpec.cpp; path = lib/Sema/SemaExceptionSpec.cpp; sourceTree = "<group>"; };
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -948,10 +963,11 @@
352246E00F5C6BC000D0D279 /* Frontend */ = {
isa = PBXGroup;
children = (
+ 1AFDD8701161085D00AE030A /* ASTMerge.cpp */,
9012911C1048068D0083456D /* ASTUnit.cpp */,
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
- 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
+ 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */,
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */,
1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */,
1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */,
@@ -1257,29 +1273,36 @@
DE67E7070C020EAB00F66BC5 /* Sema */ = {
isa = PBXGroup;
children = (
+ BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */,
+ BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */,
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
+ BF89C3E311595835001C2D68 /* Lookup.h */,
DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */,
DE67E7140C020EDF00F66BC5 /* Sema.h */,
DE67E7160C020EE400F66BC5 /* Sema.cpp */,
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */,
DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */,
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
+ BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */,
35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */,
DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */,
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
+ BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */,
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
+ BF89C3E411595855001C2D68 /* SemaInit.h */,
3599299A0DE2425300A8A33E /* SemaInit.cpp */,
357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
+ BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */,
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
@@ -1288,7 +1311,9 @@
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
+ BF89C3F811595A01001C2D68 /* SemaType.cpp */,
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
+ BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */,
);
name = Sema;
sourceTree = "<group>";
@@ -1334,7 +1359,6 @@
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
- 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */,
1A6C01F6108128710072DEE4 /* CGRTTI.cpp */,
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */,
@@ -1930,7 +1954,6 @@
DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */,
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */,
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */,
- 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */,
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */,
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */,
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */,
@@ -1997,6 +2020,13 @@
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 */,
+ BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */,
+ BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */,
+ 1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */,
+ 1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index b739b7156bb1..4eaa1dddc5e4 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -71,7 +71,8 @@ int main(int argc, const char **argv, char * const *envp) {
Diagnostic Diags(&DiagClient);
Driver TheDriver(Path.getBasename(), Path.getDirname(),
llvm::sys::getHostTriple(),
- "a.out", /*IsProduction=*/false, Diags);
+ "a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
+ Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index e77dcf86cca6..c41857ec0200 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -17,6 +17,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
@@ -57,6 +58,7 @@ namespace clang {
class ObjCIvarRefExpr;
class ObjCPropertyDecl;
class RecordDecl;
+ class StoredDeclsMap;
class TagDecl;
class TemplateTypeParmDecl;
class TranslationUnitDecl;
@@ -115,7 +117,7 @@ class ASTContext {
llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes;
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
- llvm::FoldingSet<TypenameType> TypenameTypes;
+ llvm::FoldingSet<DependentNameType> DependentNameTypes;
llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
@@ -264,6 +266,9 @@ class ASTContext {
llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc;
+ /// \brief Allocator for partial diagnostics.
+ PartialDiagnostic::StorageAllocator DiagAllocator;
+
public:
const TargetInfo &Target;
IdentifierTable &Idents;
@@ -289,6 +294,11 @@ public:
if (FreeMemory)
MallocAlloc.Deallocate(Ptr);
}
+
+ PartialDiagnostic::StorageAllocator &getDiagAllocator() {
+ return DiagAllocator;
+ }
+
const LangOptions& getLangOptions() const { return LangOpts; }
FullSourceLoc getFullLoc(SourceLocation Loc) const {
@@ -437,6 +447,11 @@ public:
/// allowable type.
QualType getCallConvType(QualType T, CallingConv CallConv);
+ /// getRegParmType - Sets the specified regparm attribute to
+ /// the given type, which must be a FunctionType or a pointer to an
+ /// allowable type.
+ QualType getRegParmType(QualType T, unsigned RegParm);
+
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType getComplexType(QualType T);
@@ -554,8 +569,12 @@ public:
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
- QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false,
- CallingConv CallConv = CC_Default);
+ QualType getFunctionNoProtoType(QualType ResultTy,
+ const FunctionType::ExtInfo &Info);
+
+ QualType getFunctionNoProtoType(QualType ResultTy) {
+ return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo());
+ }
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
@@ -564,8 +583,7 @@ public:
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec,
unsigned NumExs, const QualType *ExArray,
- bool NoReturn,
- CallingConv CallConv);
+ const FunctionType::ExtInfo &Info);
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
@@ -612,12 +630,14 @@ public:
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
QualType NamedType);
- QualType getTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon = QualType());
- QualType getTypenameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon = QualType());
QualType getElaboratedType(QualType UnderlyingType,
ElaboratedType::TagKind Tag);
@@ -937,8 +957,7 @@ public:
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
void CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
- unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
- unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
+ unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI);
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
@@ -1273,9 +1292,8 @@ private:
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
// but we include it here so that ASTContext can quickly deallocate them.
- std::vector<void*> SDMs;
+ llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
friend class DeclContext;
- void *CreateStoredDeclsMap();
void ReleaseDeclContextMaps();
};
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index c89e5e4b167a..edd633e8e140 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -19,6 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include <list>
#include <map>
@@ -227,6 +228,137 @@ public:
/// object.
void swap(CXXBasePaths &Other);
};
+
+/// \brief Uniquely identifies a virtual method within a class
+/// hierarchy by the method itself and a class subobject number.
+struct UniqueVirtualMethod {
+ UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
+
+ UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
+ const CXXRecordDecl *InVirtualSubobject)
+ : Method(Method), Subobject(Subobject),
+ InVirtualSubobject(InVirtualSubobject) { }
+
+ /// \brief The overriding virtual method.
+ CXXMethodDecl *Method;
+
+ /// \brief The subobject in which the overriding virtual method
+ /// resides.
+ unsigned Subobject;
+
+ /// \brief The virtual base class subobject of which this overridden
+ /// virtual method is a part. Note that this records the closest
+ /// derived virtual base class subobject.
+ const CXXRecordDecl *InVirtualSubobject;
+
+ friend bool operator==(const UniqueVirtualMethod &X,
+ const UniqueVirtualMethod &Y) {
+ return X.Method == Y.Method && X.Subobject == Y.Subobject &&
+ X.InVirtualSubobject == Y.InVirtualSubobject;
+ }
+
+ friend bool operator!=(const UniqueVirtualMethod &X,
+ const UniqueVirtualMethod &Y) {
+ return !(X == Y);
+ }
+};
+
+/// \brief The set of methods that override a given virtual method in
+/// each subobject where it occurs.
+///
+/// The first part of the pair is the subobject in which the
+/// overridden virtual function occurs, while the second part of the
+/// pair is the virtual method that overrides it (including the
+/// subobject in which that virtual function occurs).
+class OverridingMethods {
+ llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ Overrides;
+
+public:
+ // Iterate over the set of subobjects that have overriding methods.
+ typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ ::iterator iterator;
+ typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ ::const_iterator const_iterator;
+ iterator begin() { return Overrides.begin(); }
+ const_iterator begin() const { return Overrides.begin(); }
+ iterator end() { return Overrides.end(); }
+ const_iterator end() const { return Overrides.end(); }
+ unsigned size() const { return Overrides.size(); }
+
+ // Iterate over the set of overriding virtual methods in a given
+ // subobject.
+ typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ overriding_iterator;
+ typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
+ overriding_const_iterator;
+
+ // Add a new overriding method for a particular subobject.
+ void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
+
+ // Add all of the overriding methods from "other" into overrides for
+ // this method. Used when merging the overrides from multiple base
+ // class subobjects.
+ void add(const OverridingMethods &Other);
+
+ // Replace all overriding virtual methods in all subobjects with the
+ // given virtual method.
+ void replaceAll(UniqueVirtualMethod Overriding);
+};
+
+/// \brief A mapping from each virtual member function to its set of
+/// final overriders.
+///
+/// Within a class hierarchy for a given derived class, each virtual
+/// member function in that hierarchy has one or more "final
+/// overriders" (C++ [class.virtual]p2). A final overrider for a
+/// virtual function "f" is the virtual function that will actually be
+/// invoked when dispatching a call to "f" through the
+/// vtable. Well-formed classes have a single final overrider for each
+/// virtual function; in abstract classes, the final overrider for at
+/// least one virtual function is a pure virtual function. Due to
+/// multiple, virtual inheritance, it is possible for a class to have
+/// more than one final overrider. Athough this is an error (per C++
+/// [class.virtual]p2), it is not considered an error here: the final
+/// overrider map can represent multiple final overriders for a
+/// method, and it is up to the client to determine whether they are
+/// problem. For example, the following class \c D has two final
+/// overriders for the virtual function \c A::f(), one in \c C and one
+/// in \c D:
+///
+/// \code
+/// struct A { virtual void f(); };
+/// struct B : virtual A { virtual void f(); };
+/// struct C : virtual A { virtual void f(); };
+/// struct D : B, C { };
+/// \endcode
+///
+/// This data structure contaings a mapping from every virtual
+/// function *that does not override an existing virtual function* and
+/// in every subobject where that virtual function occurs to the set
+/// of virtual functions that override it. Thus, the same virtual
+/// function \c A::f can actually occur in multiple subobjects of type
+/// \c A due to multiple inheritance, and may be overriden by
+/// different virtual functions in each, as in the following example:
+///
+/// \code
+/// struct A { virtual void f(); };
+/// struct B : A { virtual void f(); };
+/// struct C : A { virtual void f(); };
+/// struct D : B, C { };
+/// \endcode
+///
+/// Unlike in the previous example, where the virtual functions \c
+/// B::f and \c C::f both overrode \c A::f in the same subobject of
+/// type \c A, in this example the two virtual functions both override
+/// \c A::f but in *different* subobjects of type A. This is
+/// represented by numbering the subobjects in which the overridden
+/// and the overriding virtual member functions are located. Subobject
+/// 0 represents the virtua base class subobject of that type, while
+/// subobject numbers greater than 0 refer to non-virtual base class
+/// subobjects of that type.
+class CXXFinalOverriderMap
+ : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
} // end namespace clang
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 1f459b08ca78..b2a87f617063 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -165,6 +165,8 @@ public:
// (dynamic) type.
static CanQual<T> CreateUnsafe(QualType Other);
+ void dump() const { Stored.dump(); }
+
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(getAsOpaquePtr());
}
@@ -562,24 +564,21 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
template<>
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
};
template<>
struct CanProxyAdaptor<FunctionNoProtoType>
: public CanProxyBase<FunctionNoProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
};
template<>
struct CanProxyAdaptor<FunctionProtoType>
: public CanProxyBase<FunctionProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
CanQualType getArgType(unsigned i) const {
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index e23811d8f9c0..2cdb98351394 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -224,18 +224,26 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
// NextNamespace points to the next extended declaration.
// OrigNamespace points to the original namespace declaration.
// OrigNamespace of the first namespace decl points to itself.
- NamespaceDecl *OrigNamespace, *NextNamespace;
+ NamespaceDecl *NextNamespace;
- // The (most recently entered) anonymous namespace inside this
- // namespace.
- NamespaceDecl *AnonymousNamespace;
+ /// \brief A pointer to either the original namespace definition for
+ /// this namespace (if the boolean value is false) or the anonymous
+ /// namespace that lives just inside this namespace (if the boolean
+ /// value is true).
+ ///
+ /// We can combine these two notions because the anonymous namespace
+ /// must only be stored in one of the namespace declarations (so all
+ /// of the namespace declarations can find it). We therefore choose
+ /// the original namespace declaration, since all of the namespace
+ /// declarations have a link directly to it; the original namespace
+ /// declaration itself only needs to know that it is the original
+ /// namespace declaration (which the boolean indicates).
+ llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
- : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
- OrigNamespace = this;
- NextNamespace = 0;
- AnonymousNamespace = 0;
- }
+ : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
+ NextNamespace(0), OrigOrAnonNamespace(0, true) { }
+
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id);
@@ -258,22 +266,33 @@ public:
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
NamespaceDecl *getOriginalNamespace() const {
- return OrigNamespace;
+ if (OrigOrAnonNamespace.getInt())
+ return const_cast<NamespaceDecl *>(this);
+
+ return OrigOrAnonNamespace.getPointer();
+ }
+
+ void setOriginalNamespace(NamespaceDecl *ND) {
+ if (ND != this) {
+ OrigOrAnonNamespace.setPointer(ND);
+ OrigOrAnonNamespace.setInt(false);
+ }
}
- void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
NamespaceDecl *getAnonymousNamespace() const {
- return AnonymousNamespace;
+ return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
}
void setAnonymousNamespace(NamespaceDecl *D) {
assert(!D || D->isAnonymousNamespace());
assert(!D || D->getParent() == this);
- AnonymousNamespace = D;
+ getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
}
- virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
- const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
+ virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
+ const NamespaceDecl *getCanonicalDecl() const {
+ return getOriginalNamespace();
+ }
virtual SourceRange getSourceRange() const {
return SourceRange(getLocation(), RBracLoc);
@@ -1819,12 +1838,12 @@ class RecordDecl : public TagDecl {
/// If so, this cannot be contained in arrays or other structs as a member.
bool HasFlexibleArrayMember : 1;
- /// AnonymousStructOrUnion - Whether this is the type of an
- /// anonymous struct or union.
+ /// AnonymousStructOrUnion - Whether this is the type of an anonymous struct
+ /// or union.
bool AnonymousStructOrUnion : 1;
- /// HasObjectMember - This is true if this struct has at least one
- /// member containing an object
+ /// HasObjectMember - This is true if this struct has at least one member
+ /// containing an object.
bool HasObjectMember : 1;
protected:
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 6f8284458f2b..d5913e236c2c 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -41,6 +41,8 @@ class LinkageSpecDecl;
class BlockDecl;
class DeclarationName;
class CompoundStmt;
+class StoredDeclsMap;
+class DependentDiagnostic;
}
namespace llvm {
@@ -450,15 +452,23 @@ public:
/// same entity may not (and probably don't) share this property.
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
unsigned OldNS = IdentifierNamespace;
- assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
- OldNS == (IDNS_Tag | IDNS_Ordinary))
- && "unsupported namespace for undeclared friend");
- if (!PreviouslyDeclared) IdentifierNamespace = 0;
-
- if (OldNS == IDNS_Tag)
+ assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes neither ordinary nor tag");
+ assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes other than ordinary or tag");
+
+ IdentifierNamespace = 0;
+ if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- else
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
+ }
+
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+ }
}
enum FriendObjectKind {
@@ -545,9 +555,9 @@ class DeclContext {
mutable bool ExternalVisibleStorage : 1;
/// \brief Pointer to the data structure used to lookup declarations
- /// within this context, which is a DenseMap<DeclarationName,
- /// StoredDeclsList>.
- mutable void* LookupPtr;
+ /// within this context (or a DependentStoredDeclsMap if this is a
+ /// dependent context).
+ mutable StoredDeclsMap *LookupPtr;
/// FirstDecl - The first declaration stored within this declaration
/// context.
@@ -674,6 +684,9 @@ public:
/// "primary" DeclContext structure, which will contain the
/// information needed to perform name lookup into this context.
DeclContext *getPrimaryContext();
+ const DeclContext *getPrimaryContext() const {
+ return const_cast<DeclContext*>(this)->getPrimaryContext();
+ }
/// getLookupContext - Retrieve the innermost non-transparent
/// context of this context, which corresponds to the innermost
@@ -976,10 +989,15 @@ public:
return getUsingDirectives().second;
}
+ // These are all defined in DependentDiagnostic.h.
+ class ddiag_iterator;
+ inline ddiag_iterator ddiag_begin() const;
+ inline ddiag_iterator ddiag_end() const;
+
// Low-level accessors
/// \brief Retrieve the internal representation of the lookup structure.
- void* getLookupPtr() const { return LookupPtr; }
+ StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
/// \brief Whether this DeclContext has external storage containing
/// additional declarations that are lexically in this context.
@@ -1013,6 +1031,9 @@ private:
void LoadLexicalDeclsFromExternalStorage() const;
void LoadVisibleDeclsFromExternalStorage() const;
+ friend class DependentDiagnostic;
+ StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
+
void buildLookup(DeclContext *DCtx);
void makeDeclVisibleInContextImpl(NamedDecl *D);
};
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 6b04ed54109a..23769af46b36 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -33,6 +33,7 @@ class CXXDestructorDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class CXXMemberLookupCriteria;
+class CXXFinalOverriderMap;
class FriendDecl;
/// \brief Represents any kind of function declaration, whether it is a
@@ -328,6 +329,10 @@ class CXXRecordDecl : public RecordDecl {
/// instantiated or specialized.
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
+
+#ifndef NDEBUG
+ void CheckConversionFunction(NamedDecl *D);
+#endif
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -549,17 +554,26 @@ public:
return getConversionFunctions()->replace(Old, New);
}
+ /// Removes a conversion function from this class. The conversion
+ /// function must currently be a member of this class. Furthermore,
+ /// this class must currently be in the process of being defined.
+ void removeConversion(const NamedDecl *Old);
+
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
const UnresolvedSetImpl *getVisibleConversionFunctions();
- /// addConversionFunction - Add a new conversion function to the
- /// list of conversion functions.
- void addConversionFunction(CXXConversionDecl *ConvDecl);
+ /// addConversionFunction - Registers a conversion function which
+ /// this class declares directly.
+ void addConversionFunction(NamedDecl *Decl) {
+#ifndef NDEBUG
+ CheckConversionFunction(Decl);
+#endif
- /// \brief Add a new conversion function template to the list of conversion
- /// functions.
- void addConversionFunction(FunctionTemplateDecl *ConvDecl);
+ // We intentionally don't use the decl's access here because it
+ // hasn't been set yet. That's really just a misdesign in Sema.
+ data().Conversions.addDecl(Decl);
+ }
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
@@ -879,7 +893,12 @@ public:
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *UserData);
-
+
+ /// \brief Retrieve the final overriders for each virtual member
+ /// function in the class hierarchy where this class is the
+ /// most-derived class in the class hierarchy.
+ void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const;
+
/// viewInheritance - Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
@@ -935,7 +954,7 @@ public:
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
}
-
+
/// \brief Determine whether this is a usual deallocation function
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
/// delete or delete[] operator with a particular signature.
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 32405ee81260..16cb491344bc 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -24,6 +24,8 @@
namespace clang {
+class DependentDiagnostic;
+
/// StoredDeclsList - This is an array of decls optimized a common case of only
/// containing one entry.
struct StoredDeclsList {
@@ -258,8 +260,28 @@ public:
}
};
-typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
+class StoredDeclsMap
+ : public llvm::DenseMap<DeclarationName, StoredDeclsList> {
+
+public:
+ static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
+
+private:
+ friend class ASTContext; // walks the chain deleting these
+ friend class DeclContext;
+ llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
+};
+class DependentStoredDeclsMap : public StoredDeclsMap {
+public:
+ DependentStoredDeclsMap() : FirstDiagnostic(0) {}
+
+private:
+ friend class DependentDiagnostic;
+ friend class DeclContext; // iterates over diagnostics
+
+ DependentDiagnostic *FirstDiagnostic;
+};
} // end namespace clang
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 5022ad018f4f..99ef738980cc 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -36,7 +36,7 @@ namespace clang {
/// The semantic context of a friend decl is its declaring class.
class FriendDecl : public Decl {
public:
- typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+ typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
private:
// The declaration that's a friend of this class.
@@ -73,8 +73,8 @@ public:
/// possibly dependent) type, return the type; otherwise
/// return null. This is used only for C++0x's unelaborated
/// friend type declarations.
- Type *getFriendType() const {
- return Friend.dyn_cast<Type*>();
+ TypeSourceInfo *getFriendType() const {
+ return Friend.dyn_cast<TypeSourceInfo*>();
}
/// If this friend declaration doesn't name an unelaborated
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 560ce46ede7c..8d1a4caccb23 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -1238,7 +1238,7 @@ public:
/// template <typename U> friend class Foo<T>::Nested; // friend template
class FriendTemplateDecl : public Decl {
public:
- typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+ typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
private:
// The number of template parameters; always non-zero.
@@ -1277,8 +1277,8 @@ public:
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
/// type; otherwise return null.
- Type *getFriendType() const {
- return Friend.dyn_cast<Type*>();
+ TypeSourceInfo *getFriendType() const {
+ return Friend.dyn_cast<TypeSourceInfo*>();
}
/// If this friend declaration names a templated function (or
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 2254724410d0..6225069c602f 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -378,7 +378,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
Diagnostic::ak_declarationname);
return PD;
}
-
+
} // end namespace clang
namespace llvm {
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
new file mode 100644
index 000000000000..1954a282e802
--- /dev/null
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -0,0 +1,183 @@
+//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines interfaces for diagnostics which may or may
+// fire based on how a template is instantiated.
+//
+// At the moment, the only consumer of this interface is access
+// control.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
+#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
+
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclContextInternals.h"
+
+namespace clang {
+
+class ASTContext;
+class CXXRecordDecl;
+class NamedDecl;
+
+/// A dependently-generated diagnostic.
+class DependentDiagnostic {
+public:
+ enum AccessNonce { Access = 0 };
+
+ static DependentDiagnostic *Create(ASTContext &Context,
+ DeclContext *Parent,
+ AccessNonce _,
+ SourceLocation Loc,
+ bool IsMemberAccess,
+ AccessSpecifier AS,
+ NamedDecl *TargetDecl,
+ CXXRecordDecl *NamingClass,
+ const PartialDiagnostic &PDiag) {
+ DependentDiagnostic *DD = Create(Context, Parent, PDiag);
+ DD->AccessData.Loc = Loc.getRawEncoding();
+ DD->AccessData.IsMember = IsMemberAccess;
+ DD->AccessData.Access = AS;
+ DD->AccessData.TargetDecl = TargetDecl;
+ DD->AccessData.NamingClass = NamingClass;
+ return DD;
+ }
+
+ unsigned getKind() const {
+ return Access;
+ }
+
+ bool isAccessToMember() const {
+ assert(getKind() == Access);
+ return AccessData.IsMember;
+ }
+
+ AccessSpecifier getAccess() const {
+ assert(getKind() == Access);
+ return AccessSpecifier(AccessData.Access);
+ }
+
+ SourceLocation getAccessLoc() const {
+ assert(getKind() == Access);
+ return SourceLocation::getFromRawEncoding(AccessData.Loc);
+ }
+
+ NamedDecl *getAccessTarget() const {
+ assert(getKind() == Access);
+ return AccessData.TargetDecl;
+ }
+
+ NamedDecl *getAccessNamingClass() const {
+ assert(getKind() == Access);
+ return AccessData.NamingClass;
+ }
+
+ const PartialDiagnostic &getDiagnostic() const {
+ return Diag;
+ }
+
+private:
+ DependentDiagnostic(const PartialDiagnostic &PDiag,
+ PartialDiagnostic::Storage *Storage)
+ : Diag(PDiag, Storage) {}
+
+ static DependentDiagnostic *Create(ASTContext &Context,
+ DeclContext *Parent,
+ const PartialDiagnostic &PDiag);
+
+ friend class DependentStoredDeclsMap;
+ friend class DeclContext::ddiag_iterator;
+ DependentDiagnostic *NextDiagnostic;
+
+ PartialDiagnostic Diag;
+
+ union {
+ struct {
+ unsigned Loc;
+ unsigned Access : 2;
+ unsigned IsMember : 1;
+ NamedDecl *TargetDecl;
+ CXXRecordDecl *NamingClass;
+ } AccessData;
+ };
+};
+
+///
+
+/// An iterator over the dependent diagnostics in a dependent context.
+class DeclContext::ddiag_iterator {
+public:
+ ddiag_iterator() : Ptr(0) {}
+ explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
+
+ typedef DependentDiagnostic *value_type;
+ typedef DependentDiagnostic *reference;
+ typedef DependentDiagnostic *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ reference operator*() const { return Ptr; }
+
+ ddiag_iterator &operator++() {
+ assert(Ptr && "attempt to increment past end of diag list");
+ Ptr = Ptr->NextDiagnostic;
+ return *this;
+ }
+
+ ddiag_iterator operator++(int) {
+ ddiag_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ bool operator==(ddiag_iterator Other) const {
+ return Ptr == Other.Ptr;
+ }
+
+ bool operator!=(ddiag_iterator Other) const {
+ return Ptr != Other.Ptr;
+ }
+
+ ddiag_iterator &operator+=(difference_type N) {
+ assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
+ while (N--)
+ ++*this;
+ return *this;
+ }
+
+ ddiag_iterator operator+(difference_type N) const {
+ ddiag_iterator tmp = *this;
+ tmp += N;
+ return tmp;
+ }
+
+private:
+ DependentDiagnostic *Ptr;
+};
+
+inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
+ assert(isDependentContext()
+ && "cannot iterate dependent diagnostics of non-dependent context");
+ const DependentStoredDeclsMap *Map
+ = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
+
+ if (!Map) return ddiag_iterator();
+ return ddiag_iterator(Map->FirstDiagnostic);
+}
+
+inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const {
+ return ddiag_iterator();
+}
+
+}
+
+#endif
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 6b14e47cbef5..507a61c6d7a6 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -1263,6 +1263,11 @@ public:
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
///
class MemberExpr : public Expr {
+ /// Extra data stored in some member expressions.
+ struct MemberNameQualifier : public NameQualifier {
+ NamedDecl *FoundDecl;
+ };
+
/// Base - the expression for the base pointer or structure references. In
/// X.F, this is "X".
Stmt *Base;
@@ -1278,27 +1283,26 @@ class MemberExpr : public Expr {
bool IsArrow : 1;
/// \brief True if this member expression used a nested-name-specifier to
- /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier
+ /// refer to the member, e.g., "x->Base::f", or found its member via a using
+ /// declaration. When true, a MemberNameQualifier
/// structure is allocated immediately after the MemberExpr.
- bool HasQualifier : 1;
+ bool HasQualifierOrFoundDecl : 1;
/// \brief True if this member expression specified a template argument list
/// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
/// structure (and its TemplateArguments) are allocated immediately after
/// the MemberExpr or, if the member expression also has a qualifier, after
- /// the NameQualifier structure.
+ /// the MemberNameQualifier structure.
bool HasExplicitTemplateArgumentList : 1;
/// \brief Retrieve the qualifier that preceded the member name, if any.
- NameQualifier *getMemberQualifier() {
- if (!HasQualifier)
- return 0;
-
- return reinterpret_cast<NameQualifier *> (this + 1);
+ MemberNameQualifier *getMemberQualifier() {
+ assert(HasQualifierOrFoundDecl);
+ return reinterpret_cast<MemberNameQualifier *> (this + 1);
}
/// \brief Retrieve the qualifier that preceded the member name, if any.
- const NameQualifier *getMemberQualifier() const {
+ const MemberNameQualifier *getMemberQualifier() const {
return const_cast<MemberExpr *>(this)->getMemberQualifier();
}
@@ -1308,7 +1312,7 @@ class MemberExpr : public Expr {
if (!HasExplicitTemplateArgumentList)
return 0;
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
return reinterpret_cast<ExplicitTemplateArgumentList *>(
@@ -1321,26 +1325,22 @@ class MemberExpr : public Expr {
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList();
}
- MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
- SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l,
- const TemplateArgumentListInfo *targs, QualType ty);
-
public:
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
SourceLocation l, QualType ty)
: Expr(MemberExprClass, ty,
base->isTypeDependent(), base->isValueDependent()),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
+ HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
/// \brief Build an empty member reference expression.
explicit MemberExpr(EmptyShell Empty)
- : Expr(MemberExprClass, Empty), HasQualifier(false),
+ : Expr(MemberExprClass, Empty), HasQualifierOrFoundDecl(false),
HasExplicitTemplateArgumentList(false) { }
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, SourceRange qualrange,
- ValueDecl *memberdecl,
+ ValueDecl *memberdecl, NamedDecl *founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty);
@@ -1355,16 +1355,23 @@ public:
ValueDecl *getMemberDecl() const { return MemberDecl; }
void setMemberDecl(ValueDecl *D) { MemberDecl = D; }
+ /// \brief Retrieves the declaration found by lookup.
+ NamedDecl *getFoundDecl() const {
+ if (!HasQualifierOrFoundDecl)
+ return getMemberDecl();
+ return getMemberQualifier()->FoundDecl;
+ }
+
/// \brief Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo.
- bool hasQualifier() const { return HasQualifier; }
+ bool hasQualifier() const { return getQualifier() != 0; }
/// \brief If the member name was qualified, retrieves the source range of
/// the nested-name-specifier that precedes the member name. Otherwise,
/// returns an empty source range.
SourceRange getQualifierRange() const {
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return SourceRange();
return getMemberQualifier()->Range;
@@ -1374,7 +1381,7 @@ public:
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
NestedNameSpecifier *getQualifier() const {
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return 0;
return getMemberQualifier()->NNS;
@@ -1545,6 +1552,10 @@ public:
/// CK_DerivedToBase - Derived to base class casts.
CK_DerivedToBase,
+ /// CK_UncheckedDerivedToBase - Derived to base class casts that
+ /// assume that the derived pointer is not null.
+ CK_UncheckedDerivedToBase,
+
/// CK_Dynamic - Dynamic cast.
CK_Dynamic,
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index d1351b8b1447..6e2e832e3542 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1095,8 +1095,8 @@ public:
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
false, 0, false,
- false, 0, 0, false,
- CC_Default)),
+ false, 0, 0,
+ FunctionType::ExtInfo())),
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 111be5562199..72793651c4be 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -17,6 +17,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Linkage.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
@@ -678,14 +679,6 @@ public:
return getObjCGCAttr() == Qualifiers::Strong;
}
- /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
- /// false otherwise.
- bool getNoReturnAttr() const;
-
- /// getCallConv - Returns the calling convention of the type if the type
- /// is a function type, CC_Default otherwise.
- CallingConv getCallConv() const;
-
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -902,6 +895,9 @@ public:
bool isDependentType() const { return Dependent; }
bool isOverloadableType() const;
+ /// \brief Determine wither this type is a C++ elaborated-type-specifier.
+ bool isElaboratedTypeSpecifier() const;
+
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
@@ -1747,25 +1743,101 @@ class FunctionType : public Type {
/// NoReturn - Indicates if the function type is attribute noreturn.
unsigned NoReturn : 1;
+ /// RegParm - How many arguments to pass inreg.
+ unsigned RegParm : 3;
+
/// CallConv - The calling convention used by the function.
unsigned CallConv : 2;
// The type returned by the function.
QualType ResultType;
+
+ public:
+ // This class is used for passing arround the information needed to
+ // construct a call. It is not actually used for storage, just for
+ // factoring together common arguments.
+ // If you add a field (say Foo), other than the obvious places (both, constructors,
+ // compile failures), what you need to update is
+ // * Operetor==
+ // * getFoo
+ // * withFoo
+ // * functionType. Add Foo, getFoo.
+ // * ASTContext::getFooType
+ // * ASTContext::mergeFunctionTypes
+ // * FunctionNoProtoType::Profile
+ // * FunctionProtoType::Profile
+ // * TypePrinter::PrintFunctionProto
+ // * PCH read and write
+ // * Codegen
+
+ class ExtInfo {
+ public:
+ // Constructor with no defaults. Use this when you know that you
+ // have all the elements (when reading a PCH file for example).
+ ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) :
+ NoReturn(noReturn), RegParm(regParm), CC(cc) {}
+
+ // Constructor with all defaults. Use when for example creating a
+ // function know to use defaults.
+ ExtInfo() : NoReturn(false), RegParm(0), CC(CC_Default) {}
+
+ bool getNoReturn() const { return NoReturn; }
+ unsigned getRegParm() const { return RegParm; }
+ CallingConv getCC() const { return CC; }
+
+ bool operator==(const ExtInfo &Other) const {
+ return getNoReturn() == Other.getNoReturn() &&
+ getRegParm() == Other.getRegParm() &&
+ getCC() == Other.getCC();
+ }
+ bool operator!=(const ExtInfo &Other) const {
+ return !(*this == Other);
+ }
+
+ // Note that we don't have setters. That is by design, use
+ // the following with methods instead of mutating these objects.
+
+ ExtInfo withNoReturn(bool noReturn) const {
+ return ExtInfo(noReturn, getRegParm(), getCC());
+ }
+
+ ExtInfo withRegParm(unsigned RegParm) const {
+ return ExtInfo(getNoReturn(), RegParm, getCC());
+ }
+
+ ExtInfo withCallingConv(CallingConv cc) const {
+ return ExtInfo(getNoReturn(), getRegParm(), cc);
+ }
+
+ private:
+ // True if we have __attribute__((noreturn))
+ bool NoReturn;
+ // The value passed to __attribute__((regparm(x)))
+ unsigned RegParm;
+ // The calling convention as specified via
+ // __attribute__((cdecl|stdcall||fastcall))
+ CallingConv CC;
+ };
+
protected:
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
unsigned typeQuals, QualType Canonical, bool Dependent,
- bool noReturn = false, CallingConv callConv = CC_Default)
+ const ExtInfo &Info)
: Type(tc, Canonical, Dependent),
- SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn),
- CallConv(callConv), ResultType(res) {}
+ SubClassData(SubclassInfo), TypeQuals(typeQuals),
+ NoReturn(Info.getNoReturn()),
+ RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {}
bool getSubClassData() const { return SubClassData; }
unsigned getTypeQuals() const { return TypeQuals; }
public:
QualType getResultType() const { return ResultType; }
+ unsigned getRegParmType() const { return RegParm; }
bool getNoReturnAttr() const { return NoReturn; }
CallingConv getCallConv() const { return (CallingConv)CallConv; }
+ ExtInfo getExtInfo() const {
+ return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv);
+ }
static llvm::StringRef getNameForCallConv(CallingConv CC);
@@ -1780,9 +1852,9 @@ public:
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical,
- bool NoReturn = false, CallingConv CallConv = CC_Default)
+ const ExtInfo &Info)
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
- /*Dependent=*/false, NoReturn, CallConv) {}
+ /*Dependent=*/false, Info) {}
friend class ASTContext; // ASTContext creates these.
public:
// No additional state past what FunctionType provides.
@@ -1791,12 +1863,13 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), getNoReturnAttr(), getCallConv());
+ Profile(ID, getResultType(), getExtInfo());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
- bool NoReturn, CallingConv CallConv) {
- ID.AddInteger(CallConv);
- ID.AddInteger(NoReturn);
+ const ExtInfo &Info) {
+ ID.AddInteger(Info.getCC());
+ ID.AddInteger(Info.getRegParm());
+ ID.AddInteger(Info.getNoReturn());
ID.AddPointer(ResultType.getAsOpaquePtr());
}
@@ -1827,12 +1900,12 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
- unsigned numExs, QualType Canonical, bool NoReturn,
- CallingConv CallConv)
+ unsigned numExs, QualType Canonical,
+ const ExtInfo &Info)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
(Result->isDependentType() ||
- hasAnyDependentType(ArgArray, numArgs)), NoReturn,
- CallConv),
+ hasAnyDependentType(ArgArray, numArgs)),
+ Info),
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs) {
// Fill in the trailing argument array.
@@ -1918,7 +1991,7 @@ public:
bool isVariadic, unsigned TypeQuals,
bool hasExceptionSpec, bool anyExceptionSpec,
unsigned NumExceptions, exception_iterator Exs,
- bool NoReturn, CallingConv CallConv);
+ const ExtInfo &ExtInfo);
};
@@ -2481,6 +2554,24 @@ public:
static bool classof(const InjectedClassNameType *T) { return true; }
};
+/// \brief The elaboration keyword that precedes a qualified type name or
+/// introduces an elaborated-type-specifier.
+enum ElaboratedTypeKeyword {
+ /// \brief No keyword precedes the qualified type name.
+ ETK_None,
+ /// \brief The "typename" keyword precedes the qualified type name, e.g.,
+ /// \c typename T::type.
+ ETK_Typename,
+ /// \brief The "class" keyword introduces the elaborated-type-specifier.
+ ETK_Class,
+ /// \brief The "struct" keyword introduces the elaborated-type-specifier.
+ ETK_Struct,
+ /// \brief The "union" keyword introduces the elaborated-type-specifier.
+ ETK_Union,
+ /// \brief The "enum" keyword introduces the elaborated-type-specifier.
+ ETK_Enum
+};
+
/// \brief Represents a type that was referred to via a qualified
/// name, e.g., N::M::type.
///
@@ -2531,19 +2622,19 @@ public:
static bool classof(const QualifiedNameType *T) { return true; }
};
-/// \brief Represents a 'typename' specifier that names a type within
-/// a dependent type, e.g., "typename T::type".
+/// \brief Represents a qualified type name for which the type name is
+/// dependent.
///
-/// TypenameType has a very similar structure to QualifiedNameType,
-/// which also involves a nested-name-specifier following by a type,
-/// and (FIXME!) both can even be prefixed by the 'typename'
-/// keyword. However, the two types serve very different roles:
-/// QualifiedNameType is a non-semantic type that serves only as sugar
-/// to show how a particular type was written in the source
-/// code. TypenameType, on the other hand, only occurs when the
-/// nested-name-specifier is dependent, such that we cannot resolve
-/// the actual type until after instantiation.
-class TypenameType : public Type, public llvm::FoldingSetNode {
+/// DependentNameType represents a class of dependent types that involve a
+/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
+/// name of a type. The DependentNameType may start with a "typename" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a
+/// dependent elaborated-type-specifier), or nothing (in contexts where we
+/// know that we must be referring to a type, e.g., in a base class specifier).
+class DependentNameType : public Type, public llvm::FoldingSetNode {
+ /// \brief The keyword used to elaborate this type.
+ ElaboratedTypeKeyword Keyword;
+
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
@@ -2553,23 +2644,28 @@ class TypenameType : public Type, public llvm::FoldingSetNode {
/// \brief The type that this typename specifier refers to.
NameType Name;
- TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
- QualType CanonType)
- : Type(Typename, CanonType, true), NNS(NNS), Name(Name) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Name) {
assert(NNS->isDependent() &&
- "TypenameType requires a dependent nested-name-specifier");
+ "DependentNameType requires a dependent nested-name-specifier");
}
- TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
- QualType CanonType)
- : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *Ty, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Ty) {
assert(NNS->isDependent() &&
- "TypenameType requires a dependent nested-name-specifier");
+ "DependentNameType requires a dependent nested-name-specifier");
}
friend class ASTContext; // ASTContext creates these
public:
+ /// \brief Retrieve the keyword used to elaborate this type.
+ ElaboratedTypeKeyword getKeyword() const { return Keyword; }
+
/// \brief Retrieve the qualification on this type.
NestedNameSpecifier *getQualifier() const { return NNS; }
@@ -2593,19 +2689,20 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, NNS, Name);
+ Profile(ID, Keyword, NNS, Name);
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- NameType Name) {
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, NameType Name) {
+ ID.AddInteger(Keyword);
ID.AddPointer(NNS);
ID.AddPointer(Name.getOpaqueValue());
}
static bool classof(const Type *T) {
- return T->getTypeClass() == Typename;
+ return T->getTypeClass() == DependentName;
}
- static bool classof(const TypenameType *T) { return true; }
+ static bool classof(const DependentNameType *T) { return true; }
};
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
@@ -2936,37 +3033,18 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
return Qualifiers::GCNone;
}
- /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
- /// false otherwise.
-inline bool QualType::getNoReturnAttr() const {
- QualType CT = getTypePtr()->getCanonicalTypeInternal();
- if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) {
+inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
+ if (const PointerType *PT = t.getAs<PointerType>()) {
if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>())
- return FT->getNoReturnAttr();
- } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
- return FT->getNoReturnAttr();
+ return FT->getExtInfo();
+ } else if (const FunctionType *FT = t.getAs<FunctionType>())
+ return FT->getExtInfo();
- return false;
+ return FunctionType::ExtInfo();
}
-/// getCallConv - Returns the calling convention of the type if the type
-/// is a function type, CC_Default otherwise.
-inline CallingConv QualType::getCallConv() const {
- if (const PointerType *PT = getTypePtr()->getAs<PointerType>())
- return PT->getPointeeType().getCallConv();
- else if (const ReferenceType *RT = getTypePtr()->getAs<ReferenceType>())
- return RT->getPointeeType().getCallConv();
- else if (const MemberPointerType *MPT =
- getTypePtr()->getAs<MemberPointerType>())
- return MPT->getPointeeType().getCallConv();
- else if (const BlockPointerType *BPT =
- getTypePtr()->getAs<BlockPointerType>()) {
- if (const FunctionType *FT = BPT->getPointeeType()->getAs<FunctionType>())
- return FT->getCallConv();
- } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
- return FT->getCallConv();
-
- return CC_Default;
+inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
+ return getFunctionExtInfo(*t);
}
/// isMoreQualifiedThan - Determine whether this type is more
@@ -3152,6 +3230,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return DB;
}
+/// Insertion operator for partial diagnostics. This allows sending QualType's
+/// into a diagnostic with <<.
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ QualType T) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
+ Diagnostic::ak_qualtype);
+ return PD;
+}
+
// Helper class template that is used by Type::getAs to ensure that one does
// not try to look through a qualified type to get to an array type.
template<typename T,
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 27659bd02f97..a51da7474d37 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1242,9 +1242,9 @@ class QualifiedNameTypeLoc :
};
// FIXME: locations for the typename keyword and nested name specifier.
-class TypenameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TypenameTypeLoc,
- TypenameType> {
+class DependentNameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
+ DependentNameTypeLoc,
+ DependentNameType> {
};
}
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index e75202e50abf..7e8b73c7a5f9 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -92,7 +92,7 @@ NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
NON_CANONICAL_TYPE(QualifiedName, Type)
NON_CANONICAL_TYPE(InjectedClassName, Type)
-DEPENDENT_TYPE(Typename, Type)
+DEPENDENT_TYPE(DependentName, Type)
TYPE(ObjCInterface, Type)
TYPE(ObjCObjectPointer, Type)
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index bde441741227..9ebd93b75b38 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -33,7 +33,7 @@ class ParentMap;
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
-
+
/// AnalysisContext contains the context data for the function or method under
/// analysis.
class AnalysisContext {
@@ -41,6 +41,7 @@ class AnalysisContext {
// AnalysisContext owns the following data.
CFG *cfg;
+ bool builtCFG;
LiveVariables *liveness;
ParentMap *PM;
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
@@ -48,8 +49,8 @@ class AnalysisContext {
bool AddEHEdges;
public:
AnalysisContext(const Decl *d, bool addehedges = false)
- : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0),
- AddEHEdges(addehedges) {}
+ : D(d), cfg(0), builtCFG(false), liveness(0), PM(0),
+ ReferencedBlockVars(0), AddEHEdges(addehedges) {}
~AnalysisContext();
@@ -69,7 +70,7 @@ public:
std::pair<referenced_decls_iterator, referenced_decls_iterator>
getReferencedBlockVars(const BlockDecl *BD);
-
+
/// Return the ImplicitParamDecl* associated with 'self' if this
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
@@ -82,7 +83,7 @@ public:
~AnalysisContextManager();
AnalysisContext *getContext(const Decl *D);
-
+
// Discard all previously created AnalysisContexts.
void clear();
};
@@ -103,7 +104,7 @@ protected:
public:
virtual ~LocationContext();
-
+
ContextKind getKind() const { return Kind; }
AnalysisContext *getAnalysisContext() const { return Ctx; }
@@ -120,14 +121,14 @@ public:
return getAnalysisContext()->getLiveVariables();
}
- ParentMap &getParentMap() const {
+ ParentMap &getParentMap() const {
return getAnalysisContext()->getParentMap();
}
const ImplicitParamDecl *getSelfDecl() const {
return Ctx->getSelfDecl();
}
-
+
const StackFrameContext *getCurrentStackFrame() const;
const StackFrameContext *
getStackFrameForDeclContext(const DeclContext *DC) const;
@@ -157,7 +158,7 @@ class StackFrameContext : public LocationContext {
friend class LocationContextManager;
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s, const CFGBlock *blk, unsigned idx)
- : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
+ : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
Index(idx) {}
public:
@@ -170,9 +171,9 @@ public:
unsigned getIndex() const { return Index; }
void Profile(llvm::FoldingSetNodeID &ID);
-
+
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s,
+ const LocationContext *parent, const Stmt *s,
const CFGBlock *blk, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
ID.AddPointer(blk);
@@ -186,7 +187,7 @@ public:
class ScopeContext : public LocationContext {
const Stmt *Enter;
-
+
friend class LocationContextManager;
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s)
@@ -229,7 +230,7 @@ public:
const LocationContext *parent, const BlockDecl *bd) {
ProfileCommon(ID, Block, ctx, parent, bd);
}
-
+
static bool classof(const LocationContext* Ctx) {
return Ctx->getKind() == Block;
}
@@ -239,7 +240,7 @@ class LocationContextManager {
llvm::FoldingSet<LocationContext> Contexts;
public:
~LocationContextManager();
-
+
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s, const CFGBlock *blk,
@@ -248,7 +249,7 @@ public:
const ScopeContext *getScope(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s);
-
+
/// Discard all previously created LocationContext objects.
void clear();
private:
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index cbf7010bfdb5..3c762011a657 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -17,7 +17,8 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "functional" // STL
namespace clang {
@@ -28,23 +29,30 @@ namespace clang {
//===----------------------------------------------------------------------===//
class DataflowWorkListTy {
- typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
- BlockSet wlist;
+ llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
+ llvm::SmallVector<const CFGBlock *, 10> BlockQueue;
public:
/// enqueue - Add a block to the worklist. Blocks already on the
/// worklist are not added a second time.
- void enqueue(const CFGBlock* B) { wlist.insert(B); }
+ void enqueue(const CFGBlock* B) {
+ unsigned char &x = BlockSet[B];
+ if (x == 1)
+ return;
+ x = 1;
+ BlockQueue.push_back(B);
+ }
/// dequeue - Remove a block from the worklist.
const CFGBlock* dequeue() {
- assert (!wlist.empty());
- const CFGBlock* B = *wlist.begin();
- wlist.erase(B);
+ assert(!BlockQueue.empty());
+ const CFGBlock *B = BlockQueue.back();
+ BlockQueue.pop_back();
+ BlockSet[B] = 0;
return B;
}
/// isEmpty - Return true if the worklist is empty.
- bool isEmpty() const { return wlist.empty(); }
+ bool isEmpty() const { return BlockQueue.empty(); }
};
//===----------------------------------------------------------------------===//
@@ -188,10 +196,7 @@ private:
/// SolveDataflowEquations - Perform the actual worklist algorithm
/// to compute dataflow values.
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
- // Enqueue all blocks to ensure the dataflow values are computed
- // for every block. Not all blocks are guaranteed to reach the exit block.
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
- WorkList.enqueue(&**I);
+ EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
@@ -201,6 +206,22 @@ private:
}
}
+ void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) {
+ // Enqueue all blocks to ensure the dataflow values are computed
+ // for every block. Not all blocks are guaranteed to reach the exit block.
+ for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
+ WorkList.enqueue(&**I);
+ }
+
+ void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) {
+ // Enqueue all blocks to ensure the dataflow values are computed
+ // for every block. Not all blocks are guaranteed to reach the exit block.
+ // Enqueue in reverse order since that will more likely match with
+ // the order they should ideally processed by the dataflow algorithm.
+ for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I)
+ WorkList.enqueue(&**I);
+ }
+
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
ValTy& V = TF.getVal();
TF.SetTopValue(V);
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 3afdaf5b0eb1..453f660c360a 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -397,13 +397,6 @@ BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n")
BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n")
BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n")
-BUILTIN(__sync_fetch_and_nand, "v.", "")
-BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n")
-BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n")
-BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n")
-BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n")
-BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n")
-
BUILTIN(__sync_add_and_fetch, "v.", "")
BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n")
@@ -440,14 +433,6 @@ BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n")
BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n")
BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n")
-BUILTIN(__sync_nand_and_fetch, "v.", "")
-BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n")
-BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n")
-BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n")
-BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n")
-BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
-
-
BUILTIN(__sync_bool_compare_and_swap, "v.", "")
BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n")
BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n")
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 00b076aa1004..5c75d3799bcb 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -317,4 +317,12 @@ BUILTIN(__builtin_ia32_crc32qi, "iic", "")
BUILTIN(__builtin_ia32_crc32hi, "iis", "")
BUILTIN(__builtin_ia32_crc32si, "iii", "")
BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
+
+// AES
+BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLii", "")
#undef BUILTIN
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
index 9e643bb3c2c1..c2a4e1364a9e 100644
--- a/include/clang/Basic/CMakeLists.txt
+++ b/include/clang/Basic/CMakeLists.txt
@@ -1,8 +1,8 @@
macro(clang_diag_gen component)
- tablegen(Diagnostic${component}Kinds.inc
- -gen-clang-diags-defs -clang-component=${component})
+ tablegen(Diagnostic${component}Kinds.inc
+ -gen-clang-diags-defs -clang-component=${component})
add_custom_target(ClangDiagnostic${component}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Diagnostic${component}Kinds.inc)
+ DEPENDS Diagnostic${component}Kinds.inc)
endmacro(clang_diag_gen)
set(LLVM_TARGET_DEFINITIONS Diagnostic.td)
@@ -17,4 +17,4 @@ clang_diag_gen(Sema)
tablegen(DiagnosticGroups.inc
-gen-clang-diag-groups)
add_custom_target(ClangDiagnosticGroups
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/DiagnosticGroups.inc)
+ DEPENDS DiagnosticGroups.inc)
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index d6c8797fc901..643868506d8f 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -95,7 +95,7 @@ namespace clang {
/// should also provide full recovery from such errors, such that
/// suppressing the diagnostic output can still result in successful
/// compilation.
-class CodeModificationHint {
+class FixItHint {
public:
/// \brief Tokens that should be removed to correct the error.
SourceRange RemoveRange;
@@ -110,7 +110,7 @@ public:
/// \brief Empty code modification hint, indicating that no code
/// modification is known.
- CodeModificationHint() : RemoveRange(), InsertionLoc() { }
+ FixItHint() : RemoveRange(), InsertionLoc() { }
bool isNull() const {
return !RemoveRange.isValid() && !InsertionLoc.isValid();
@@ -118,9 +118,9 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
- static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
- llvm::StringRef Code) {
- CodeModificationHint Hint;
+ static FixItHint CreateInsertion(SourceLocation InsertionLoc,
+ llvm::StringRef Code) {
+ FixItHint Hint;
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert = Code;
return Hint;
@@ -128,17 +128,17 @@ public:
/// \brief Create a code modification hint that removes the given
/// source range.
- static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
- CodeModificationHint Hint;
+ static FixItHint CreateRemoval(SourceRange RemoveRange) {
+ FixItHint Hint;
Hint.RemoveRange = RemoveRange;
return Hint;
}
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
- static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
- llvm::StringRef Code) {
- CodeModificationHint Hint;
+ static FixItHint CreateReplacement(SourceRange RemoveRange,
+ llvm::StringRef Code) {
+ FixItHint Hint;
Hint.RemoveRange = RemoveRange;
Hint.InsertionLoc = RemoveRange.getBegin();
Hint.CodeToInsert = Code;
@@ -234,6 +234,18 @@ private:
void *Cookie);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
+
+ /// \brief ID of the "delayed" diagnostic, which is a (typically
+ /// fatal) diagnostic that had to be delayed because it was found
+ /// while emitting another diagnostic.
+ unsigned DelayedDiagID;
+
+ /// \brief First string argument for the delayed diagnostic.
+ std::string DelayedDiagArg1;
+
+ /// \brief Second string argument for the delayed diagnostic.
+ std::string DelayedDiagArg2;
+
public:
explicit Diagnostic(DiagnosticClient *client = 0);
~Diagnostic();
@@ -377,6 +389,28 @@ public:
/// the diagnostic, this returns null.
static const char *getWarningOptionForDiag(unsigned DiagID);
+ /// \brief Enumeration describing how the the emission of a diagnostic should
+ /// be treated when it occurs during C++ template argument deduction.
+ enum SFINAEResponse {
+ /// \brief The diagnostic should not be reported, but it should cause
+ /// template argument deduction to fail.
+ ///
+ /// The vast majority of errors that occur during template argument
+ /// deduction fall into this category.
+ SFINAE_SubstitutionFailure,
+
+ /// \brief The diagnostic should be suppressed entirely.
+ ///
+ /// Warnings generally fall into this category.
+ SFINAE_Suppress,
+
+ /// \brief The diagnostic should be reported.
+ ///
+ /// The diagnostic should be reported. Various fatal errors (e.g.,
+ /// template instantiation depth exceeded) fall into this category.
+ SFINAE_Report
+ };
+
/// \brief Determines whether the given built-in diagnostic ID is
/// for an error that is suppressed if it occurs during C++ template
/// argument deduction.
@@ -385,7 +419,7 @@ public:
/// deduction fails but no diagnostic is emitted. Certain classes of
/// errors, such as those errors that involve C++ access control,
/// are not SFINAE errors.
- static bool isBuiltinSFINAEDiag(unsigned DiagID);
+ static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
@@ -400,10 +434,41 @@ public:
inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
inline DiagnosticBuilder Report(unsigned DiagID);
+ /// \brief Determine whethere there is already a diagnostic in flight.
+ bool isDiagnosticInFlight() const { return CurDiagID != ~0U; }
+
+ /// \brief Set the "delayed" diagnostic that will be emitted once
+ /// the current diagnostic completes.
+ ///
+ /// If a diagnostic is already in-flight but the front end must
+ /// report a problem (e.g., with an inconsistent file system
+ /// state), this routine sets a "delayed" diagnostic that will be
+ /// emitted after the current diagnostic completes. This should
+ /// only be used for fatal errors detected at inconvenient
+ /// times. If emitting a delayed diagnostic causes a second delayed
+ /// diagnostic to be introduced, that second delayed diagnostic
+ /// will be ignored.
+ ///
+ /// \param DiagID The ID of the diagnostic being delayed.
+ ///
+ /// \param Arg1 A string argument that will be provided to the
+ /// diagnostic. A copy of this string will be stored in the
+ /// Diagnostic object itself.
+ ///
+ /// \param Arg2 A string argument that will be provided to the
+ /// diagnostic. A copy of this string will be stored in the
+ /// Diagnostic object itself.
+ void SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1 = "",
+ llvm::StringRef Arg2 = "");
+
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
private:
+ /// \brief Report the delayed diagnostic.
+ void ReportDelayed();
+
+
/// 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.
@@ -454,8 +519,8 @@ private:
/// NumRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
/// \brief The number of code modifications hints in the
- /// CodeModificationHints array.
- unsigned char NumCodeModificationHints;
+ /// FixItHints array.
+ unsigned char NumFixItHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
@@ -477,11 +542,11 @@ private:
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
- enum { MaxCodeModificationHints = 3 };
+ enum { MaxFixItHints = 3 };
- /// CodeModificationHints - If valid, provides a hint with some code
+ /// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
- CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
+ FixItHint FixItHints[MaxFixItHints];
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
@@ -508,13 +573,12 @@ private:
/// for example.
class DiagnosticBuilder {
mutable Diagnostic *DiagObj;
- mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
+ mutable unsigned NumArgs, NumRanges, NumFixItHints;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
friend class Diagnostic;
explicit DiagnosticBuilder(Diagnostic *diagObj)
- : DiagObj(diagObj), NumArgs(0), NumRanges(0),
- NumCodeModificationHints(0) {}
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the
@@ -524,7 +588,7 @@ public:
D.DiagObj = 0;
NumArgs = D.NumArgs;
NumRanges = D.NumRanges;
- NumCodeModificationHints = D.NumCodeModificationHints;
+ NumFixItHints = D.NumFixItHints;
}
/// \brief Simple enumeration value used to give a name to the
@@ -534,7 +598,7 @@ public:
/// \brief Create an empty DiagnosticBuilder object that represents
/// no actual diagnostic.
explicit DiagnosticBuilder(SuppressKind)
- : DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
+ : DiagObj(0), NumArgs(0), NumRanges(0), NumFixItHints(0) { }
/// \brief Force the diagnostic builder to emit the diagnostic now.
///
@@ -543,29 +607,7 @@ public:
///
/// \returns true if a diagnostic was emitted, false if the
/// diagnostic was suppressed.
- bool Emit() {
- // If DiagObj is null, then its soul was stolen by the copy ctor
- // or the user called Emit().
- if (DiagObj == 0) return false;
-
- // When emitting diagnostics, we set the final argument count into
- // the Diagnostic object.
- DiagObj->NumDiagArgs = NumArgs;
- DiagObj->NumDiagRanges = NumRanges;
- DiagObj->NumCodeModificationHints = NumCodeModificationHints;
-
- // Process the diagnostic, sending the accumulated information to the
- // DiagnosticClient.
- bool Emitted = DiagObj->ProcessDiag();
-
- // Clear out the current diagnostic object.
- DiagObj->Clear();
-
- // This diagnostic is dead.
- DiagObj = 0;
-
- return Emitted;
- }
+ bool Emit();
/// Destructor - The dtor emits the diagnostic if it hasn't already
/// been emitted.
@@ -605,14 +647,14 @@ public:
DiagObj->DiagRanges[NumRanges++] = R;
}
- void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ void AddFixItHint(const FixItHint &Hint) const {
if (Hint.isNull())
return;
- assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
- "Too many code modification hints!");
+ assert(NumFixItHints < Diagnostic::MaxFixItHints &&
+ "Too many fix-it hints!");
if (DiagObj)
- DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
+ DiagObj->FixItHints[NumFixItHints++] = Hint;
}
};
@@ -673,8 +715,8 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- const CodeModificationHint &Hint) {
- DB.AddCodeModificationHint(Hint);
+ const FixItHint &Hint) {
+ DB.AddFixItHint(Hint);
return DB;
}
@@ -770,17 +812,17 @@ public:
return DiagObj->DiagRanges[Idx];
}
- unsigned getNumCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints;
+ unsigned getNumFixItHints() const {
+ return DiagObj->NumFixItHints;
}
- const CodeModificationHint &getCodeModificationHint(unsigned Idx) const {
- return DiagObj->CodeModificationHints[Idx];
+ const FixItHint &getFixItHint(unsigned Idx) const {
+ return DiagObj->FixItHints[Idx];
}
- const CodeModificationHint *getCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints?
- &DiagObj->CodeModificationHints[0] : 0;
+ const FixItHint *getFixItHints() const {
+ return DiagObj->NumFixItHints?
+ &DiagObj->FixItHints[0] : 0;
}
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
@@ -803,7 +845,7 @@ class StoredDiagnostic {
FullSourceLoc Loc;
std::string Message;
std::vector<SourceRange> Ranges;
- std::vector<CodeModificationHint> FixIts;
+ std::vector<FixItHint> FixIts;
public:
StoredDiagnostic();
@@ -823,7 +865,7 @@ public:
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
- typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator;
+ typedef std::vector<FixItHint>::const_iterator fixit_iterator;
fixit_iterator fixit_begin() const { return FixIts.begin(); }
fixit_iterator fixit_end() const { return FixIts.end(); }
unsigned fixit_size() const { return FixIts.size(); }
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 3a28282d5522..2e0b4bad6b5b 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -22,7 +22,7 @@ def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
- "-dependency-file requires at least one -MT option">;
+ "-dependency-file requires at least one -MT or -MQ option">;
def err_fe_incompatible_options : Error<
"'%0' cannot be used with '%1'">, DefaultFatal;
def err_fe_no_fixit_and_codegen : Error<
@@ -57,6 +57,9 @@ def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_error_at_end_block : Error<
"error at end of module block in PCH file: '%0'">, DefaultFatal;
+def err_fe_pch_file_modified : Error<
+ "file '%0' has been modified since the precompiled header was built">,
+ DefaultFatal;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
def err_fe_unable_to_open_logfile : Error<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 203ab1eed547..b0c016bbfd28 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -31,6 +31,7 @@ def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
def : DiagGroup<"ctor-dtor-privacy">;
def : DiagGroup<"declaration-after-statement">;
+def GNUDesignator : DiagGroup<"gnu-designator">;
def Deprecated : DiagGroup<"deprecated">;
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
@@ -115,6 +116,7 @@ def UnusedVariable : DiagGroup<"unused-variable">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
+def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
@@ -185,3 +187,6 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
// but which aren't on by default in GCC.
def NonGCC : DiagGroup<"non-gcc",
[SignCompare, Conversion, LiteralRange]>;
+
+// A warning group for warnings about GCC extensions.
+def GNU : DiagGroup<"gnu", [GNUDesignator]>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 9d001d48cc2a..facf15f52e85 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -50,22 +50,26 @@ def ext_enumerator_list_comma : Extension<
"feature">;
def ext_gnu_indirect_goto : Extension<
- "use of GNU indirect-goto extension">;
+ "use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<
- "use of GNU address-of-label extension">;
+ "use of GNU address-of-label extension">, InGroup<GNU>;
def ext_gnu_statement_expr : Extension<
- "use of GNU statement expression extension">;
+ "use of GNU statement expression extension">, InGroup<GNU>;
def ext_gnu_conditional_expr : Extension<
- "use of GNU ?: expression extension, eliding middle term">;
+ "use of GNU ?: expression extension, eliding middle term">, InGroup<GNU>;
def ext_gnu_empty_initializer : Extension<
- "use of GNU empty initializer extension">;
-def ext_gnu_array_range : Extension<"use of GNU array range extension">;
+ "use of GNU empty initializer extension">, InGroup<GNU>;
+def ext_gnu_array_range : Extension<"use of GNU array range extension">,
+ InGroup<GNUDesignator>;
def ext_gnu_missing_equal_designator : ExtWarn<
- "use of GNU 'missing =' extension in designator">;
+ "use of GNU 'missing =' extension in designator">,
+ InGroup<GNUDesignator>;
def err_expected_equal_designator : Error<"expected '=' or another designator">;
def ext_gnu_old_style_field_designator : ExtWarn<
- "use of GNU old-style field designator extension">;
-def ext_gnu_case_range : Extension<"use of GNU case range extension">;
+ "use of GNU old-style field designator extension">,
+ InGroup<GNUDesignator>;
+def ext_gnu_case_range : Extension<"use of GNU case range extension">,
+ InGroup<GNU>;
// Generic errors.
def err_parse_error : Error<"parse error">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 752be5df7a12..be00972dac5c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -68,7 +68,7 @@ def err_designator_into_flexible_array_member : Error<
def note_flexible_array_member : Note<
"initialized flexible array member %0 is here">;
def ext_flexible_array_init : Extension<
- "flexible array initialization is a GNU extension">;
+ "flexible array initialization is a GNU extension">, InGroup<GNU>;
// Declarations.
def ext_vla : Extension<
@@ -268,8 +268,6 @@ def err_duplicate_ivar_declaration : Error<
"instance variable is already declared">;
def warn_on_superclass_use : Warning<
"class implementation may not have super class">;
-def err_non_private_ivar_declaration : Error<
- "only private ivars may be declared in implementation">;
def err_conflicting_ivar_bitwidth : Error<
"instance variable %0 has conflicting bit-field width">;
def err_conflicting_ivar_name : Error<
@@ -277,7 +275,9 @@ def err_conflicting_ivar_name : Error<
def err_inconsistant_ivar_count : Error<
"inconsistent number of instance variables specified">;
def warn_incomplete_impl : Warning<"incomplete implementation">;
-def warn_undef_method_impl : Warning<"method definition for %0 not found">;
+def note_undef_method_impl : Note<"method definition for %0 not found">;
+def note_required_for_protocol_at :
+ Note<"required for direct or indirect protocol %0">;
def warn_conflicting_ret_types : Warning<
"conflicting return type in implementation of %0: %1 vs %2">;
@@ -350,7 +350,7 @@ def error_synthesized_ivar_yet_not_supported : Error<
" (need to declare %0 explicitly)">;
def error_property_ivar_type : Error<
- "type of property %0 does not match type of ivar %1">;
+ "type of property %0 (%1) does not match type of ivar %2 (%3)">;
def error_ivar_in_superclass_use : Error<
"property %0 attempting to use ivar %1 declared in super class %2">;
def error_weak_property : Error<
@@ -367,6 +367,8 @@ def warn_objc_property_attr_mutually_exclusive : Warning<
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
+def warn_unimplemented_protocol_method : Warning<
+ "method in protocol not implemented">, InGroup<Protocol>;
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
@@ -393,7 +395,11 @@ 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_multiple_final_overriders : Error<
+ "virtual function %q0 has more than one final overrider in %1">;
+def note_final_overrider : Note<"final overrider of %q0 in %1">;
+
def err_type_defined_in_type_specifier : Error<
"%0 can not be defined in a type specifier">;
def err_type_defined_in_result_type : Error<
@@ -432,6 +438,8 @@ def err_incompatible_exception_specs : Error<
"target exception specification is not superset of source">;
def err_deep_exception_specs_differ : Error<
"exception specifications of %select{return|argument}0 types differ">;
+def warn_missing_exception_specification : Warning<
+ "%0 is missing exception specification '%1'">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -532,6 +540,7 @@ def err_implicit_object_parameter_init : Error<
"of type %1">;
def note_field_decl : Note<"member is declared here">;
+def note_ivar_decl : Note<"ivar is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_member_synthesized_at : Note<
@@ -776,8 +785,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">;
-def warn_attribute_void_function : Warning<
- "attribute %0 cannot be applied to functions without return value">;
+def warn_attribute_void_function_method : Warning<
+ "attribute %0 cannot be applied to "
+ "%select{functions|Objective-C method}1 without return value">;
def warn_attribute_weak_on_field : Warning<
"__weak attribute cannot be specified on a field declaration">;
def warn_attribute_weak_on_local : Warning<
@@ -1199,26 +1209,40 @@ def err_template_arg_not_integral_or_enumeral : Error<
def err_template_arg_not_ice : Error<
"non-type template argument of type %0 is not an integral constant "
"expression">;
+def err_deduced_non_type_template_arg_type_mismatch : Error<
+ "deduced non-type template argument does not have the same type as the "
+ "its corresponding template parameter (%0 vs %1)">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
-def err_template_arg_negative : Error<
- "non-type template argument provides negative value '%0' for unsigned "
- "template parameter of type %1">;
-def err_template_arg_too_large : Error<
- "non-type template argument value '%0' is too large for template "
- "parameter of type %1">;
+def warn_template_arg_negative : Warning<
+ "non-type template argument with value '%0' converted to '%1' for unsigned "
+ "template parameter of type %2">;
+def warn_template_arg_too_large : Warning<
+ "non-type template argument value '%0' truncated to '%1' for "
+ "template parameter of type %2">;
def err_template_arg_no_ref_bind : Error<
"non-type template parameter of reference type %0 cannot bind to template "
"argument of type %1">;
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<
"non-type template argument does not directly refer to an object or "
"function">;
+def err_template_arg_not_address_of : Error<
+ "non-type template argument for template parameter of pointer type %0 must "
+ "have its address taken">;
+def err_template_arg_address_of_non_pointer : Error<
+ "address taken in non-type template argument for template parameter of "
+ "reference type %0">;
+def err_template_arg_reference_var : Error<
+ "non-type template argument of reference type %0 is not an object">;
def err_template_arg_field : Error<
"non-type template argument refers to non-static data member %0">;
def err_template_arg_method : Error<
@@ -1251,6 +1275,8 @@ def err_template_spec_decl_function_scope : Error<
"explicit specialization of %0 in function scope">;
def err_template_spec_decl_class_scope : Error<
"explicit specialization of %0 in class scope">;
+def err_template_spec_decl_friend : Error<
+ "cannot declare an explicit specialization in a friend">;
def err_template_spec_decl_out_of_scope_global : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
@@ -1372,13 +1398,13 @@ def note_default_function_arg_instantiation_here : Note<
"for '%0' required here">;
def note_explicit_template_arg_substitution_here : Note<
"while substituting explicitly-specified template arguments into function "
- "template %f, here">;
+ "template %0 %1">;
def note_function_template_deduction_instantiation_here : Note<
- "while substituting deduced template arguments into function template %0, "
- "here">;
+ "while substituting deduced template arguments into function template %0 "
+ "%1">;
def note_partial_spec_deduct_instantiation_here : Note<
"during template argument deduction for class template partial "
- "specialization %0, here">;
+ "specialization %0 %1">;
def note_prior_template_arg_substitution : Note<
"while substituting prior template arguments into %select{non-type|template}0"
" template parameter%1 %2">;
@@ -1537,7 +1563,8 @@ def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
-def err_misplaced_ivar : Error<"ivars may not be placed in categories">;
+def err_misplaced_ivar : Error<
+ "ivars may not be placed in %select{categories|class extension}0">;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
@@ -1575,6 +1602,8 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
"pointer to function type %0 may not be 'restrict' qualified">;
def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">;
+def err_typecheck_zero_array_size : Error<
+ "zero-length arrays are not permitted in C++">;
def err_at_least_one_initializer_needed_to_size_array : Error<
"at least one initializer value required to size array">;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
@@ -1664,7 +1693,7 @@ def err_field_declared_as_function : Error<"field %0 declared as a function">;
def err_field_incomplete : Error<"field has incomplete type %0">;
def ext_variable_sized_type_in_struct : ExtWarn<
"field %0 with variable sized type %1 not at the end of a struct or class is"
- " a GNU extension">;
+ " a GNU extension">, InGroup<GNU>;
def err_flexible_array_empty_struct : Error<
"flexible array %0 not allowed in otherwise empty struct">;
@@ -2164,7 +2193,7 @@ def err_invalid_declarator_global_scope : Error<
def err_invalid_declarator_in_function : Error<
"definition or redeclaration of %0 not allowed inside a function">;
def err_not_tag_in_scope : Error<
- "%0 does not name a tag member in the specified scope">;
+ "no %select{struct|union|class|enum}0 named %1 in %2">;
def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
@@ -2322,7 +2351,8 @@ def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn<
def err_typecheck_choose_expr_requires_constant : Error<
"'__builtin_choose_expr' requires a constant expression">;
def ext_typecheck_expression_not_constant_but_accepted : Extension<
- "expression is not a constant, but is accepted as one by GNU extensions">;
+ "expression is not a constant, but is accepted as one by GNU extensions">,
+ InGroup<GNU>;
def warn_unused_expr : Warning<"expression result unused">,
InGroup<UnusedValue>;
def warn_unused_property_expr : Warning<
@@ -2334,6 +2364,7 @@ def warn_unused_call : Warning<
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
+def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
// inline asm.
def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
@@ -2413,9 +2444,9 @@ def err_in_class_initializer_non_constant : Error<
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
- "anonymous unions are a GNU extension in C">;
+ "anonymous unions are a GNU extension in C">, InGroup<GNU>;
def ext_anonymous_struct : Extension<
- "anonymous structs are a GNU extension">;
+ "anonymous structs are a GNU extension">, InGroup<GNU>;
def err_anonymous_union_not_static : Error<
"anonymous unions at namespace or global scope must be declared 'static'">;
def err_anonymous_union_with_storage_spec : Error<
@@ -2584,6 +2615,9 @@ def warn_printf_missing_format_string : Warning<
def warn_printf_conversion_argument_type_mismatch : Warning<
"conversion specifies type %0 but the argument has type %1">,
InGroup<Format>;
+def warn_printf_positional_arg_exceeds_data_args : Warning <
+ "data argument position '%0' exceeds the number of data arguments (%1)">,
+ InGroup<Format>;
def warn_printf_zero_positional_specifier : Warning<
"position arguments in format strings start counting at 1 (not 0)">,
InGroup<Format>;
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index fb861dcf934d..89fae87ae8ef 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -15,19 +15,18 @@
#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
#define LLVM_CLANG_PARTIALDIAGNOSTIC_H
-#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/System/DataTypes.h"
+#include <cassert>
namespace clang {
-class DeclarationName;
-
class PartialDiagnostic {
+public:
struct Storage {
- Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) {
- }
+ Storage() : NumDiagArgs(0), NumDiagRanges(0), NumFixItHints(0) { }
enum {
/// MaxArguments - The maximum number of arguments we can hold. We
@@ -44,8 +43,8 @@ class PartialDiagnostic {
unsigned char NumDiagRanges;
/// \brief The number of code modifications hints in the
- /// CodeModificationHints array.
- unsigned char NumCodeModificationHints;
+ /// FixItHints array.
+ unsigned char NumFixItHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
@@ -62,13 +61,49 @@ class PartialDiagnostic {
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
- enum { MaxCodeModificationHints = 3 };
+ enum { MaxFixItHints = 3 };
- /// CodeModificationHints - If valid, provides a hint with some code
+ /// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
- CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
+ FixItHint FixItHints[MaxFixItHints];
};
+ /// \brief An allocator for Storage objects, which uses a small cache to
+ /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
+ class StorageAllocator {
+ static const unsigned NumCached = 4;
+ Storage Cached[NumCached];
+ Storage *FreeList[NumCached];
+ unsigned NumFreeListEntries;
+
+ public:
+ StorageAllocator();
+ ~StorageAllocator();
+
+ /// \brief Allocate new storage.
+ Storage *Allocate() {
+ if (NumFreeListEntries == 0)
+ return new Storage;
+
+ Storage *Result = FreeList[--NumFreeListEntries];
+ Result->NumDiagArgs = 0;
+ Result->NumDiagRanges = 0;
+ Result->NumFixItHints = 0;
+ return Result;
+ }
+
+ /// \brief Free the given storage object.
+ void Deallocate(Storage *S) {
+ if (S >= Cached && S <= Cached + NumCached) {
+ FreeList[NumFreeListEntries++] = S;
+ return;
+ }
+
+ delete S;
+ }
+ };
+
+private:
// NOTE: Sema assumes that PartialDiagnostic is location-invariant
// in the sense that its bits can be safely memcpy'ed and destructed
// in the new location.
@@ -76,22 +111,40 @@ class PartialDiagnostic {
/// DiagID - The diagnostic ID.
mutable unsigned DiagID;
- /// DiagStorare - Storge for args and ranges.
+ /// DiagStorage - Storage for args and ranges.
mutable Storage *DiagStorage;
- void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
- if (!DiagStorage)
+ /// \brief Allocator used to allocate storage for this diagnostic.
+ StorageAllocator *Allocator;
+
+ /// \brief Retrieve storage for this particular diagnostic.
+ Storage *getStorage() const {
+ if (DiagStorage)
+ return DiagStorage;
+
+ if (Allocator)
+ DiagStorage = Allocator->Allocate();
+ else {
+ assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
DiagStorage = new Storage;
+ }
+ return DiagStorage;
+ }
+
+ void freeStorage() {
+ if (!DiagStorage)
+ return;
- assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
- "Too many arguments to diagnostic!");
- DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
- DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+ if (Allocator)
+ Allocator->Deallocate(DiagStorage);
+ else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
+ delete DiagStorage;
+ DiagStorage = 0;
}
-
+
void AddSourceRange(const SourceRange &R) const {
if (!DiagStorage)
- DiagStorage = new Storage;
+ DiagStorage = getStorage();
assert(DiagStorage->NumDiagRanges <
llvm::array_lengthof(DiagStorage->DiagRanges) &&
@@ -99,53 +152,70 @@ class PartialDiagnostic {
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
}
- void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ void AddFixItHint(const FixItHint &Hint) const {
if (Hint.isNull())
return;
if (!DiagStorage)
- DiagStorage = new Storage;
+ DiagStorage = getStorage();
- assert(DiagStorage->NumCodeModificationHints <
- Storage::MaxCodeModificationHints &&
+ assert(DiagStorage->NumFixItHints < Storage::MaxFixItHints &&
"Too many code modification hints!");
- DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++]
+ DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
= Hint;
}
public:
- PartialDiagnostic(unsigned DiagID)
- : DiagID(DiagID), DiagStorage(0) { }
-
+ PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
+ : DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
+
PartialDiagnostic(const PartialDiagnostic &Other)
- : DiagID(Other.DiagID), DiagStorage(0)
+ : DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
{
- if (Other.DiagStorage)
- DiagStorage = new Storage(*Other.DiagStorage);
+ if (Other.DiagStorage) {
+ DiagStorage = getStorage();
+ *DiagStorage = *Other.DiagStorage;
+ }
}
+ PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
+ : DiagID(Other.DiagID), DiagStorage(DiagStorage),
+ Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
+ {
+ if (Other.DiagStorage)
+ *this->DiagStorage = *Other.DiagStorage;
+ }
+
PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
DiagID = Other.DiagID;
if (Other.DiagStorage) {
- if (DiagStorage)
- *DiagStorage = *Other.DiagStorage;
- else
- DiagStorage = new Storage(*Other.DiagStorage);
+ if (!DiagStorage)
+ DiagStorage = getStorage();
+
+ *DiagStorage = *Other.DiagStorage;
} else {
- delete DiagStorage;
- DiagStorage = 0;
+ freeStorage();
}
return *this;
}
~PartialDiagnostic() {
- delete DiagStorage;
+ freeStorage();
}
-
unsigned getDiagID() const { return DiagID; }
+ void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
+ if (!DiagStorage)
+ DiagStorage = getStorage();
+
+ assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
+ DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+ }
+
void Emit(const DiagnosticBuilder &DB) const {
if (!DiagStorage)
return;
@@ -161,17 +231,19 @@ public:
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
// Add all code modification hints
- for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i)
- DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]);
+ for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
+ DB.AddFixItHint(DiagStorage->FixItHints[i]);
}
- friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- QualType T) {
- PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
- Diagnostic::ak_qualtype);
- return PD;
+ /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
+ /// and removing all of its arguments, ranges, and fix-it hints.
+ void Reset(unsigned DiagID = 0) {
+ this->DiagID = DiagID;
+ freeStorage();
}
-
+
+ bool hasStorage() const { return DiagStorage != 0; }
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
PD.AddTaggedVal(I, Diagnostic::ak_uint);
@@ -197,20 +269,13 @@ public:
}
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- DeclarationName N);
-
- friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- const CodeModificationHint &Hint) {
- PD.AddCodeModificationHint(Hint);
+ const FixItHint &Hint) {
+ PD.AddFixItHint(Hint);
return PD;
}
};
-inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
- return PartialDiagnostic(DiagID);
-}
-
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const PartialDiagnostic &PD) {
PD.Emit(DB);
@@ -219,4 +284,4 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
} // end namespace clang
-#endif
+#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index f7ea331e1cc7..555e6f5a919a 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -28,7 +28,6 @@ namespace llvm {
namespace clang {
class SourceManager;
-class FileEntry;
/// FileID - This is an opaque identifier used by SourceManager which refers to
/// a source file (MemoryBuffer) along with its #include path and #line data.
diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h
index 2c15f2a40576..617034292638 100644
--- a/include/clang/Checker/BugReporter/BugReporter.h
+++ b/include/clang/Checker/BugReporter/BugReporter.h
@@ -15,17 +15,12 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Checker/BugReporter/BugType.h"
-#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallString.h"
#include <list>
namespace clang {
@@ -35,6 +30,8 @@ class PathDiagnosticPiece;
class PathDiagnosticClient;
class ASTContext;
class Diagnostic;
+class ExplodedNode;
+class ExplodedGraph;
class BugReporter;
class BugReporterContext;
class GRExprEngine;
diff --git a/include/clang/Checker/BugReporter/BugType.h b/include/clang/Checker/BugReporter/BugType.h
index 4f1523a5440d..afc07c89e86f 100644
--- a/include/clang/Checker/BugReporter/BugType.h
+++ b/include/clang/Checker/BugReporter/BugType.h
@@ -14,15 +14,12 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
-#include <llvm/ADT/FoldingSet.h>
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "llvm/ADT/FoldingSet.h"
#include <string>
namespace clang {
-class BugReportEquivClass;
-class BugReporter;
-class BuiltinBugReport;
-class BugReporterContext;
class ExplodedNode;
class GRExprEngine;
diff --git a/include/clang/Checker/BugReporter/PathDiagnostic.h b/include/clang/Checker/BugReporter/PathDiagnostic.h
index d380c45480cb..24c75ce7b228 100644
--- a/include/clang/Checker/BugReporter/PathDiagnostic.h
+++ b/include/clang/Checker/BugReporter/PathDiagnostic.h
@@ -168,7 +168,7 @@ public:
private:
const std::string str;
- std::vector<CodeModificationHint> CodeModificationHints;
+ std::vector<FixItHint> FixItHints;
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
@@ -203,8 +203,8 @@ public:
ranges.push_back(SourceRange(B,E));
}
- void addCodeModificationHint(const CodeModificationHint& Hint) {
- CodeModificationHints.push_back(Hint);
+ void addFixItHint(const FixItHint& Hint) {
+ FixItHints.push_back(Hint);
}
typedef const SourceRange* range_iterator;
@@ -217,15 +217,15 @@ public:
return ranges_begin() + ranges.size();
}
- typedef const CodeModificationHint *code_modifications_iterator;
+ typedef const FixItHint *fixit_iterator;
- code_modifications_iterator code_modifications_begin() const {
- return CodeModificationHints.empty()? 0 : &CodeModificationHints[0];
+ fixit_iterator fixit_begin() const {
+ return FixItHints.empty()? 0 : &FixItHints[0];
}
- code_modifications_iterator code_modifications_end() const {
- return CodeModificationHints.empty()? 0
- : &CodeModificationHints[0] + CodeModificationHints.size();
+ fixit_iterator fixit_end() const {
+ return FixItHints.empty()? 0
+ : &FixItHints[0] + FixItHints.size();
}
static inline bool classof(const PathDiagnosticPiece* P) {
diff --git a/include/clang/Checker/DomainSpecific/CocoaConventions.h b/include/clang/Checker/DomainSpecific/CocoaConventions.h
index ee3d648b8608..4bbdab0e7fe1 100644
--- a/include/clang/Checker/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Checker/DomainSpecific/CocoaConventions.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_CHECKER_DS_COCOA
#define LLVM_CLANG_CHECKER_DS_COCOA
-#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/Type.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/BasicValueFactory.h b/include/clang/Checker/PathSensitive/BasicValueFactory.h
index 2f0b6c2a0348..59dd9190d25e 100644
--- a/include/clang/Checker/PathSensitive/BasicValueFactory.h
+++ b/include/clang/Checker/PathSensitive/BasicValueFactory.h
@@ -16,7 +16,6 @@
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
-#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h
index 2401a72741b2..8cb9cc8337c6 100644
--- a/include/clang/Checker/PathSensitive/Checker.h
+++ b/include/clang/Checker/PathSensitive/Checker.h
@@ -14,21 +14,15 @@
#ifndef LLVM_CLANG_ANALYSIS_CHECKER
#define LLVM_CLANG_ANALYSIS_CHECKER
+
#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
-#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
//===----------------------------------------------------------------------===//
// Checker interface.
//===----------------------------------------------------------------------===//
namespace clang {
- class GRExprEngine;
class CheckerContext {
ExplodedNodeSet &Dst;
diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h
index 6051654f4855..b9bbebc652f2 100644
--- a/include/clang/Checker/PathSensitive/Environment.h
+++ b/include/clang/Checker/PathSensitive/Environment.h
@@ -18,11 +18,8 @@
// typedefs.
#include "clang/Checker/PathSensitive/Store.h"
-#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/Checker/PathSensitive/SVals.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h
index d6c4436c594c..c09c89312e10 100644
--- a/include/clang/Checker/PathSensitive/ExplodedGraph.h
+++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h
@@ -9,6 +9,10 @@
//
// This file defines the template classes ExplodedNode and ExplodedGraph,
// which represent a path-sensitive, intra-procedural "exploded graph."
+// See "Precise interprocedural dataflow analysis via graph reachability"
+// by Reps, Horwitz, and Sagiv
+// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
+// exploded graph.
//
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Checker/PathSensitive/GRBlockCounter.h b/include/clang/Checker/PathSensitive/GRBlockCounter.h
index 67ed9532db02..b7d0e8ae0c71 100644
--- a/include/clang/Checker/PathSensitive/GRBlockCounter.h
+++ b/include/clang/Checker/PathSensitive/GRBlockCounter.h
@@ -22,6 +22,8 @@ namespace llvm {
namespace clang {
+class StackFrameContext;
+
class GRBlockCounter {
void* Data;
@@ -30,7 +32,8 @@ class GRBlockCounter {
public:
GRBlockCounter() : Data(0) {}
- unsigned getNumVisited(unsigned BlockID) const;
+ unsigned getNumVisited(const StackFrameContext *CallSite,
+ unsigned BlockID) const;
class Factory {
void* F;
@@ -39,7 +42,9 @@ public:
~Factory();
GRBlockCounter GetEmptyCounter();
- GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
+ GRBlockCounter IncrementCount(GRBlockCounter BC,
+ const StackFrameContext *CallSite,
+ unsigned BlockID);
};
friend class Factory;
diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
index c5bf5138a63f..a3ff0dbedc7b 100644
--- a/include/clang/Checker/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -82,7 +82,7 @@ class GRCoreEngine {
void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder);
- bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+ bool ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
GRBlockCounter BC);
@@ -174,7 +174,9 @@ public:
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(B.getBlockID());
+ return getBlockCounter().getNumVisited(
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ B.getBlockID());
}
ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
@@ -434,7 +436,9 @@ public:
}
unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(B.getBlockID());
+ return getBlockCounter().getNumVisited(
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ B.getBlockID());
}
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 916511e8bd09..161cb28df033 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -16,7 +16,6 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
-#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRSubEngine.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
@@ -28,11 +27,9 @@
#include "clang/AST/ExprCXX.h"
namespace clang {
-
- class PathDiagnosticClient;
- class Diagnostic;
- class ObjCForCollectionStmt;
- class Checker;
+class AnalysisManager;
+class Checker;
+class ObjCForCollectionStmt;
class GRExprEngine : public GRSubEngine {
AnalysisManager &AMgr;
@@ -153,7 +150,7 @@ public:
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
- bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC);
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
@@ -216,7 +213,7 @@ public:
const GRState* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
-protected:
+
/// CheckerVisit - Dispatcher for performing checker-specific logic
/// at specific statements.
void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
@@ -351,10 +348,21 @@ protected:
void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+
+ void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// Synthesize CXXThisRegion.
+ const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD,
+ const StackFrameContext *SFC);
+
/// 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/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
index 383463b822cb..6d85e5fe6a90 100644
--- a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
+++ b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
@@ -17,18 +17,9 @@
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
#include "clang/Checker/PathSensitive/GRAuditor.h"
-#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
-class Diagnostic;
-class BugReporter;
-class ASTContext;
-class GRExprEngine;
-class PathDiagnosticClient;
-class ExplodedGraph;
-
-
class GRSimpleAPICheck : public GRAuditor {
public:
GRSimpleAPICheck() {}
diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
index 657266b7508d..25ba1f85fdff 100644
--- a/include/clang/Checker/PathSensitive/GRState.h
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -14,30 +14,22 @@
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
-// FIXME: Reduce the number of includes.
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Checker/PathSensitive/ConstraintManager.h"
#include "clang/Checker/PathSensitive/Environment.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/Store.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/DataTypes.h"
-#include <functional>
-namespace clang {
+namespace llvm {
+class APSInt;
+class BumpPtrAllocator;
+class raw_ostream;
+}
+namespace clang {
+class ASTContext;
class GRStateManager;
class Checker;
@@ -302,6 +294,8 @@ public:
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const;
+ template <typename T>
+ const GRState *remove() const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::data_type D) const;
@@ -464,6 +458,7 @@ public:
// Methods that manipulate the GDM.
const GRState* addGDM(const GRState* St, void* Key, void* Data);
+ const GRState *removeGDM(const GRState *state, void *Key);
// Methods that query & manipulate the Store.
@@ -528,6 +523,10 @@ public:
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
}
+ template <typename T>
+ const GRState *remove(const GRState *st) {
+ return removeGDM(st, GRStateTrait<T>::GDMIndex());
+ }
void* FindGDMContext(void* index,
void* (*CreateContext)(llvm::BumpPtrAllocator&),
@@ -702,6 +701,11 @@ const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
return getStateManager().remove<T>(this, K, C);
}
+template <typename T>
+const GRState *GRState::remove() const {
+ return getStateManager().remove<T>(this);
+}
+
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h
index f2cd0486e326..d2e7457ea93d 100644
--- a/include/clang/Checker/PathSensitive/GRSubEngine.h
+++ b/include/clang/Checker/PathSensitive/GRSubEngine.h
@@ -20,6 +20,7 @@ namespace clang {
class Stmt;
class CFGBlock;
class CFGElement;
+class ExplodedNode;
class GRState;
class GRStateManager;
class GRBlockCounter;
@@ -47,7 +48,7 @@ public:
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
- virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ virtual bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC) = 0;
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
index 04634effd587..13325edea778 100644
--- a/include/clang/Checker/PathSensitive/GRTransferFuncs.h
+++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
@@ -15,16 +15,18 @@
#ifndef LLVM_CLANG_ANALYSIS_GRTF
#define LLVM_CLANG_ANALYSIS_GRTF
-#include "clang/Checker/PathSensitive/SVals.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SVals.h"
#include <vector>
namespace clang {
-
+class ExplodedNode;
+class ExplodedNodeSet;
+class GREndPathNodeBuilder;
class GRExprEngine;
-class ObjCMessageExpr;
+class GRStmtNodeBuilder;
class GRStmtNodeBuilderRef;
+class ObjCMessageExpr;
class GRTransferFuncs {
public:
diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
index be89d2a3eb88..57ea8a3f6d9d 100644
--- a/include/clang/Checker/PathSensitive/MemRegion.h
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -18,17 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/SVals.h"
-#include "clang/AST/ASTContext.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ImmutableList.h"
-#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/Support/Allocator.h"
#include <string>
-namespace llvm { class raw_ostream; }
+namespace llvm {
+class BumpPtrAllocator;
+class raw_ostream;
+}
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index edc338012ada..72565f4d740d 100644
--- a/include/clang/Checker/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -18,9 +18,6 @@
#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallVector.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h
index b6630c3d97d2..dea877c0657f 100644
--- a/include/clang/Checker/PathSensitive/SymbolManager.h
+++ b/include/clang/Checker/PathSensitive/SymbolManager.h
@@ -17,14 +17,14 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/System/DataTypes.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseSet.h"
namespace llvm {
- class raw_ostream;
+class BumpPtrAllocator;
+class raw_ostream;
}
namespace clang {
@@ -34,9 +34,6 @@ namespace clang {
class TypedRegion;
class VarRegion;
class StackFrameContext;
-}
-
-namespace clang {
class SymExpr : public llvm::FoldingSetNode {
public:
@@ -247,6 +244,7 @@ public:
QualType t)
: SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+ BinaryOperator::Opcode getOpcode() const { return Op; }
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 85c6c3e3abcf..638ed516ed0b 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -15,7 +15,6 @@
#define LLVM_CLANG_CODEGEN_CODEGENOPTIONS_H
#include <string>
-#include <vector>
namespace clang {
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index feebbc78864f..124288a76305 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -156,6 +156,7 @@ def dependency_file : Separate<"-dependency-file">,
HelpText<"Filename (or -) to write dependency output to">;
def sys_header_deps : Flag<"-sys-header-deps">,
HelpText<"Include system headers in dependency output">;
+def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">;
def MT : Separate<"-MT">, HelpText<"Specify target for dependency">;
def MP : Flag<"-MP">,
HelpText<"Create phony target for each dependency (other than main file)">;
@@ -407,6 +408,8 @@ def fwritable_strings : Flag<"-fwritable-strings">,
def nostdinc : Flag<"-nostdinc">,
HelpText<"Disable standard #include directories">;
+def nostdincxx : Flag<"-nostdinc++">,
+ HelpText<"Disable standard #include directories for the C++ standard library">;
def nobuiltininc : Flag<"-nobuiltininc">,
HelpText<"Disable builtin #include directories">;
def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">,
diff --git a/include/clang/Driver/CMakeLists.txt b/include/clang/Driver/CMakeLists.txt
index f720d15d8ccc..ed9825b59df5 100644
--- a/include/clang/Driver/CMakeLists.txt
+++ b/include/clang/Driver/CMakeLists.txt
@@ -2,10 +2,10 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(Options.inc
-gen-opt-parser-defs)
add_custom_target(ClangDriverOptions
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Options.inc)
+ DEPENDS Options.inc)
set(LLVM_TARGET_DEFINITIONS CC1Options.td)
tablegen(CC1Options.inc
-gen-opt-parser-defs)
add_custom_target(ClangCC1Options
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CC1Options.inc)
+ DEPENDS CC1Options.inc)
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index f49c3b97c1c4..90c3a0dcdc18 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -64,6 +64,12 @@ public:
/// The path to the compiler resource directory.
std::string ResourceDir;
+ /// A prefix directory used to emulated a limited subset of GCC's '-Bprefix'
+ /// functionality.
+ /// FIXME: This type of customization should be removed in favor of the
+ /// universal driver when it is ready.
+ std::string PrefixDir;
+
/// Default host triple.
std::string DefaultHostTriple;
@@ -133,7 +139,8 @@ public:
Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
llvm::StringRef _DefaultHostTriple,
llvm::StringRef _DefaultImageName,
- bool IsProduction, Diagnostic &_Diags);
+ bool IsProduction, bool CXXIsProduction,
+ Diagnostic &_Diags);
~Driver();
/// @name Accessors
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 71258f9814be..d088be04c03e 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -118,7 +118,7 @@ def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>,
HelpText<"Print the commands to run for this compilation">;
def A : JoinedOrSeparate<"-A">;
-def B : JoinedOrSeparate<"-B">, Flags<[Unsupported]>;
+def B : JoinedOrSeparate<"-B">;
def CC : Flag<"-CC">;
def C : Flag<"-C">;
def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>;
@@ -470,6 +470,7 @@ def noprebind : Flag<"-noprebind">;
def noseglinkedit : Flag<"-noseglinkedit">;
def nostartfiles : Flag<"-nostartfiles">;
def nostdinc : Flag<"-nostdinc">;
+def nostdincxx : Flag<"-nostdinc++">;
def nostdlib : Flag<"-nostdlib">;
def object : Flag<"-object">;
def o : JoinedOrSeparate<"-o">, Flags<[DriverOption, RenderAsInput]>,
diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h
index 690408547c0d..c6682451835a 100644
--- a/include/clang/Frontend/HeaderSearchOptions.h
+++ b/include/clang/Frontend/HeaderSearchOptions.h
@@ -71,13 +71,17 @@ public:
/// Include the system standard include search directories.
unsigned UseStandardIncludes : 1;
+ /// Include the system standard C++ library include search directories.
+ unsigned UseStandardCXXIncludes : 1;
+
/// Whether header search information should be output as for -v.
unsigned Verbose : 1;
public:
HeaderSearchOptions(llvm::StringRef _Sysroot = "/")
: Sysroot(_Sysroot), UseBuiltinIncludes(true),
- UseStandardIncludes(true), Verbose(false) {}
+ UseStandardIncludes(true), UseStandardCXXIncludes(true),
+ Verbose(false) {}
/// AddPath - Add the \arg Path path to the specified \arg Group list.
void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group,
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index d09e51fd0184..157876b59d34 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -69,7 +69,7 @@ public:
void EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges, unsigned NumRanges,
SourceManager &SM,
- const CodeModificationHint *Hints,
+ const FixItHint *Hints,
unsigned NumHints,
unsigned Columns);
diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def
index dd5018af82aa..3add99a941c4 100644
--- a/include/clang/Frontend/TypeXML.def
+++ b/include/clang/Frontend/TypeXML.def
@@ -233,7 +233,7 @@ NODE_XML(QualifiedNameType, "QualifiedNameType")
TYPE_ATTRIBUTE_XML(getNamedType())
END_NODE_XML
-NODE_XML(TypenameType, "TypenameType")
+NODE_XML(DependentNameType, "DependentNameType")
ID_ATTRIBUTE_XML
END_NODE_XML
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index dd24fb7d7ba2..e891e94d4cbc 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -44,6 +44,12 @@ public:
SrcMgr::CharacteristicKind FileType) {
}
+
+ /// EndOfMainFile - This callback is invoked when the end of the main file is
+ /// reach, no subsequent callbacks will be made.
+ virtual void EndOfMainFile() {
+ }
+
/// Ident - This callback is invoked when a #ident or #sccs directive is read.
///
virtual void Ident(SourceLocation Loc, const std::string &str) {
@@ -90,6 +96,11 @@ public:
Second->FileChanged(Loc, Reason, FileType);
}
+ virtual void EndOfMainFile() {
+ First->EndOfMainFile();
+ Second->EndOfMainFile();
+ }
+
virtual void Ident(SourceLocation Loc, const std::string &str) {
First->Ident(Loc, str);
Second->Ident(Loc, str);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 23c118d1fc63..312a760e01d3 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -368,6 +368,10 @@ public:
/// which implicitly adds the builtin defines etc.
bool 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.
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 85c44c5a0b80..477a2130cf0e 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -21,6 +21,7 @@
namespace clang {
+class FileEntry;
class Preprocessor;
class PreprocessorLexer {
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index b79e698d50c9..59cc0d218cec 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -1761,7 +1761,8 @@ public:
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac) {
+ SourceLocation RBrac,
+ AttributeList *AttrList) {
}
//===---------------------------C++ Templates----------------------------===//
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7f5c9b1ec1e6..c77acce1bd06 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -45,7 +45,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels),
- BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
+ BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts),
+ LastSDM(0, 0) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
ObjCSelRedefinitionType = QualType();
@@ -858,34 +859,22 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
}
-unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
- unsigned count = 0;
- for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
- E = PD->prop_end(); I != E; ++I)
- if ((*I)->getPropertyIvarDecl())
- ++count;
-
- // Also look into nested protocols.
- for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
- E = PD->protocol_end(); P != E; ++P)
- count += CountProtocolSynthesizedIvars(*P);
- return count;
-}
-
-unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) {
- unsigned count = 0;
- for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
- E = OI->prop_end(); I != E; ++I) {
- if ((*I)->getPropertyIvarDecl())
+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;
+ }
}
- // Also look into interface's protocol list for properties declared
- // in the protocol and whose ivars are synthesized.
- for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
- PE = OI->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *PD = (*P);
- count += CountProtocolSynthesizedIvars(PD);
- }
+
+ // 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;
return count;
}
@@ -966,7 +955,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
// Add in synthesized ivar count if laying out an implementation.
if (Impl) {
- unsigned SynthCount = CountSynthesizedIvars(D);
+ unsigned SynthCount = CountNonClassIvars(D);
// If there aren't any sythesized ivars then reuse the interface
// entry. Note we can't cache this because we simply free all
// entries later; however we shouldn't look up implementations
@@ -1108,14 +1097,12 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
-static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
- bool AddNoReturn,
- CallingConv CallConv) {
+static QualType getExtFunctionType(ASTContext& Context, QualType T,
+ const FunctionType::ExtInfo &Info) {
QualType ResultType;
if (const PointerType *Pointer = T->getAs<PointerType>()) {
QualType Pointee = Pointer->getPointeeType();
- ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
- CallConv);
+ ResultType = getExtFunctionType(Context, Pointee, Info);
if (ResultType == Pointee)
return T;
@@ -1123,19 +1110,18 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
} else if (const BlockPointerType *BlockPointer
= T->getAs<BlockPointerType>()) {
QualType Pointee = BlockPointer->getPointeeType();
- ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
- CallConv);
+ ResultType = getExtFunctionType(Context, Pointee, Info);
if (ResultType == Pointee)
return T;
ResultType = Context.getBlockPointerType(ResultType);
} else if (const FunctionType *F = T->getAs<FunctionType>()) {
- if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv)
+ if (F->getExtInfo() == Info)
return T;
if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(),
- AddNoReturn, CallConv);
+ Info);
} else {
const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
ResultType
@@ -1146,7 +1132,7 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
FPT->hasAnyExceptionSpec(),
FPT->getNumExceptions(),
FPT->exception_begin(),
- AddNoReturn, CallConv);
+ Info);
}
} else
return T;
@@ -1155,11 +1141,21 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
}
QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
- return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv());
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withNoReturn(AddNoReturn));
}
QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
- return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv);
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withCallingConv(CallConv));
+}
+
+QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) {
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withRegParm(RegParm));
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -1617,12 +1613,13 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
-QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
- CallingConv CallConv) {
+QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
+ const FunctionType::ExtInfo &Info) {
+ const CallingConv CallConv = Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
+ FunctionNoProtoType::Profile(ID, ResultTy, Info);
void *InsertPos = 0;
if (FunctionNoProtoType *FT =
@@ -1632,8 +1629,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
QualType Canonical;
if (!ResultTy.isCanonical() ||
getCanonicalCallConv(CallConv) != CallConv) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
- getCanonicalCallConv(CallConv));
+ Canonical =
+ getFunctionNoProtoType(getCanonicalType(ResultTy),
+ Info.withCallingConv(getCanonicalCallConv(CallConv)));
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1642,7 +1640,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
}
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
+ FunctionNoProtoType(ResultTy, Canonical, Info);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1654,14 +1652,15 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec, unsigned NumExs,
- const QualType *ExArray, bool NoReturn,
- CallingConv CallConv) {
+ const QualType *ExArray,
+ const FunctionType::ExtInfo &Info) {
+ const CallingConv CallConv= Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- NumExs, ExArray, NoReturn, CallConv);
+ NumExs, ExArray, Info);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1686,8 +1685,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
- false, 0, 0, NoReturn,
- getCanonicalCallConv(CallConv));
+ false, 0, 0,
+ Info.withCallingConv(getCanonicalCallConv(CallConv)));
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1704,7 +1703,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
NumExs*sizeof(QualType), TypeAlignment);
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- ExArray, NumExs, Canonical, NoReturn, CallConv);
+ ExArray, NumExs, Canonical, Info);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1963,66 +1962,76 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
return QualType(T, 0);
}
-QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon) {
+QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
- if (CanonNNS != NNS)
- Canon = getTypenameType(CanonNNS, Name);
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+
+ if (CanonNNS != NNS || CanonKeyword != Keyword)
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
}
llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, Name);
+ DependentNameType::Profile(ID, Keyword, NNS, Name);
void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *T
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
- T = new (*this) TypenameType(NNS, Name, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
Types.push_back(T);
- TypenameTypes.InsertNode(T, InsertPos);
+ DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
QualType
-ASTContext::getTypenameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon) {
+ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, TemplateId);
+ DependentNameType::Profile(ID, Keyword, NNS, TemplateId);
void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *T
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
- if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+ if (CanonNNS != NNS || CanonKeyword != Keyword ||
+ CanonType != QualType(TemplateId, 0)) {
const TemplateSpecializationType *CanonTemplateId
= CanonType->getAs<TemplateSpecializationType>();
assert(CanonTemplateId &&
"Canonical type must also be a template specialization type");
- Canon = getTypenameType(CanonNNS, CanonTemplateId);
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId);
}
- TypenameType *CheckT
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *CheckT
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
}
- T = new (*this) TypenameType(NNS, TemplateId, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon);
Types.push_back(T);
- TypenameTypes.InsertNode(T, InsertPos);
+ DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
@@ -4127,14 +4136,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
- if (RHSOPT->isObjCBuiltinType())
+ if (RHSOPT->isObjCBuiltinType() ||
+ LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
}
- if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ if (RHSOPT->isObjCQualifiedIdType())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
@@ -4315,13 +4325,22 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
allRTypes = false;
// FIXME: double check this
- bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
- if (NoReturn != lbase->getNoReturnAttr())
+ // FIXME: should we error if lbase->getRegParmAttr() != 0 &&
+ // rbase->getRegParmAttr() != 0 &&
+ // lbase->getRegParmAttr() != rbase->getRegParmAttr()?
+ FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo();
+ FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
+ unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() :
+ lbaseInfo.getRegParm();
+ bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
+ if (NoReturn != lbaseInfo.getNoReturn() ||
+ RegParm != lbaseInfo.getRegParm())
allLTypes = false;
- if (NoReturn != rbase->getNoReturnAttr())
+ if (NoReturn != rbaseInfo.getNoReturn() ||
+ RegParm != rbaseInfo.getRegParm())
allRTypes = false;
- CallingConv lcc = lbase->getCallConv();
- CallingConv rcc = rbase->getCallConv();
+ CallingConv lcc = lbaseInfo.getCC();
+ CallingConv rcc = rbaseInfo.getCC();
// Compatible functions must have compatible calling conventions
if (!isSameCallConv(lcc, rcc))
return QualType();
@@ -4360,7 +4379,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- false, false, 0, 0, NoReturn, lcc);
+ false, false, 0, 0,
+ FunctionType::ExtInfo(NoReturn, RegParm, lcc));
}
if (lproto) allRTypes = false;
@@ -4393,13 +4413,15 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
proto->getNumArgs(), proto->isVariadic(),
- proto->getTypeQuals(),
- false, false, 0, 0, NoReturn, lcc);
+ proto->getTypeQuals(),
+ false, false, 0, 0,
+ FunctionType::ExtInfo(NoReturn, RegParm, lcc));
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- return getFunctionNoProtoType(retType, NoReturn, lcc);
+ FunctionType::ExtInfo Info(NoReturn, RegParm, lcc);
+ return getFunctionNoProtoType(retType, Info);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
@@ -4903,7 +4925,7 @@ QualType ASTContext::GetBuiltinType(unsigned id,
// FIXME: Should we create noreturn types?
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
TypeStr[0] == '.', 0, false, false, 0, 0,
- false, CC_Default);
+ FunctionType::ExtInfo());
}
QualType
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index dd2528a6b3b3..75cf1380a112 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -73,7 +73,7 @@ namespace {
// FIXME: SubstTemplateTypeParmType
// FIXME: TemplateSpecializationType
QualType VisitQualifiedNameType(QualifiedNameType *T);
- // FIXME: TypenameType
+ // FIXME: DependentNameType
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
@@ -484,10 +484,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Function1->getResultType(),
Function2->getResultType()))
return false;
- if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr())
- return false;
- if (Function1->getCallConv() != Function2->getCallConv())
- return false;
+ if (Function1->getExtInfo() != Function2->getExtInfo())
+ return false;
break;
}
@@ -620,9 +618,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
- case Type::Typename: {
- const TypenameType *Typename1 = cast<TypenameType>(T1);
- const TypenameType *Typename2 = cast<TypenameType>(T2);
+ case Type::DependentName: {
+ const DependentNameType *Typename1 = cast<DependentNameType>(T1);
+ const DependentNameType *Typename2 = cast<DependentNameType>(T2);
if (!IsStructurallyEquivalent(Context,
Typename1->getQualifier(),
Typename2->getQualifier()))
@@ -1200,10 +1198,9 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
QualType ToResultType = Importer.Import(T->getResultType());
if (ToResultType.isNull())
return QualType();
-
+
return Importer.getToContext().getFunctionNoProtoType(ToResultType,
- T->getNoReturnAttr(),
- T->getCallConv());
+ T->getExtInfo());
}
QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
@@ -1241,8 +1238,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
T->hasAnyExceptionSpec(),
ExceptionTypes.size(),
ExceptionTypes.data(),
- T->getNoReturnAttr(),
- T->getCallConv());
+ T->getExtInfo());
}
QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 3408a1e3cc74..91aaddc9a481 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangAST
AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
+ DeclarationName.cpp
DeclBase.cpp
DeclCXX.cpp
DeclFriend.cpp
@@ -16,10 +17,9 @@ add_clang_library(clangAST
DeclObjC.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- DeclarationName.cpp
Expr.cpp
- ExprCXX.cpp
ExprConstant.cpp
+ ExprCXX.cpp
FullExpr.cpp
InheritViz.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 70f8ee4bca5e..a9f223045864 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -416,3 +416,240 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
return false;
}
+
+void OverridingMethods::add(unsigned OverriddenSubobject,
+ UniqueVirtualMethod Overriding) {
+ llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ = Overrides[OverriddenSubobject];
+ if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
+ Overriding) == SubobjectOverrides.end())
+ SubobjectOverrides.push_back(Overriding);
+}
+
+void OverridingMethods::add(const OverridingMethods &Other) {
+ for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {
+ for (overriding_const_iterator M = I->second.begin(),
+ MEnd = I->second.end();
+ M != MEnd;
+ ++M)
+ add(I->first, *M);
+ }
+}
+
+void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {
+ for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {
+ I->second.clear();
+ I->second.push_back(Overriding);
+ }
+}
+
+
+namespace {
+ class FinalOverriderCollector {
+ /// \brief The number of subobjects of a given class type that
+ /// occur within the class hierarchy.
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
+
+ /// \brief Overriders for each virtual base subobject.
+ llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
+
+ CXXFinalOverriderMap FinalOverriders;
+
+ public:
+ ~FinalOverriderCollector();
+
+ void Collect(const CXXRecordDecl *RD, bool VirtualBase,
+ const CXXRecordDecl *InVirtualSubobject,
+ CXXFinalOverriderMap &Overriders);
+ };
+}
+
+void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
+ bool VirtualBase,
+ const CXXRecordDecl *InVirtualSubobject,
+ CXXFinalOverriderMap &Overriders) {
+ unsigned SubobjectNumber = 0;
+ if (!VirtualBase)
+ SubobjectNumber
+ = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
+
+ for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+ BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
+ if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
+ const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ if (Overriders.empty() && !Base->isVirtual()) {
+ // There are no other overriders of virtual member functions,
+ // so let the base class fill in our overriders for us.
+ Collect(BaseDecl, false, InVirtualSubobject, Overriders);
+ continue;
+ }
+
+ // Collect all of the overridders from the base class subobject
+ // and merge them into the set of overridders for this class.
+ // For virtual base classes, populate or use the cached virtual
+ // overrides so that we do not walk the virtual base class (and
+ // its base classes) more than once.
+ CXXFinalOverriderMap ComputedBaseOverriders;
+ CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
+ if (Base->isVirtual()) {
+ CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
+ if (!MyVirtualOverriders) {
+ MyVirtualOverriders = new CXXFinalOverriderMap;
+ Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);
+ }
+
+ BaseOverriders = MyVirtualOverriders;
+ } else
+ Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);
+
+ // Merge the overriders from this base class into our own set of
+ // overriders.
+ for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),
+ OMEnd = BaseOverriders->end();
+ OM != OMEnd;
+ ++OM) {
+ const CXXMethodDecl *CanonOM
+ = cast<CXXMethodDecl>(OM->first->getCanonicalDecl());
+ Overriders[CanonOM].add(OM->second);
+ }
+ }
+ }
+
+ for (CXXRecordDecl::method_iterator M = RD->method_begin(),
+ MEnd = RD->method_end();
+ M != MEnd;
+ ++M) {
+ // We only care about virtual methods.
+ if (!M->isVirtual())
+ continue;
+
+ CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl());
+
+ if (CanonM->begin_overridden_methods()
+ == CanonM->end_overridden_methods()) {
+ // This is a new virtual function that does not override any
+ // other virtual function. Add it to the map of virtual
+ // functions for which we are tracking overridders.
+
+ // C++ [class.virtual]p2:
+ // For convenience we say that any virtual function overrides itself.
+ Overriders[CanonM].add(SubobjectNumber,
+ UniqueVirtualMethod(CanonM, SubobjectNumber,
+ InVirtualSubobject));
+ continue;
+ }
+
+ // This virtual method overrides other virtual methods, so it does
+ // not add any new slots into the set of overriders. Instead, we
+ // replace entries in the set of overriders with the new
+ // overrider. To do so, we dig down to the original virtual
+ // functions using data recursion and update all of the methods it
+ // overrides.
+ typedef std::pair<CXXMethodDecl::method_iterator,
+ CXXMethodDecl::method_iterator> OverriddenMethods;
+ llvm::SmallVector<OverriddenMethods, 4> Stack;
+ Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(),
+ CanonM->end_overridden_methods()));
+ while (!Stack.empty()) {
+ OverriddenMethods OverMethods = Stack.back();
+ Stack.pop_back();
+
+ for (; OverMethods.first != OverMethods.second; ++OverMethods.first) {
+ const CXXMethodDecl *CanonOM
+ = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl());
+ if (CanonOM->begin_overridden_methods()
+ == CanonOM->end_overridden_methods()) {
+ // C++ [class.virtual]p2:
+ // A virtual member function C::vf of a class object S is
+ // a final overrider unless the most derived class (1.8)
+ // of which S is a base class subobject (if any) declares
+ // or inherits another member function that overrides vf.
+ //
+ // Treating this object like the most derived class, we
+ // replace any overrides from base classes with this
+ // overriding virtual function.
+ Overriders[CanonOM].replaceAll(
+ UniqueVirtualMethod(CanonM, SubobjectNumber,
+ InVirtualSubobject));
+ continue;
+ }
+
+ // Continue recursion to the methods that this virtual method
+ // overrides.
+ Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(),
+ CanonOM->end_overridden_methods()));
+ }
+ }
+ }
+}
+
+FinalOverriderCollector::~FinalOverriderCollector() {
+ for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
+ VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
+ VO != VOEnd;
+ ++VO)
+ delete VO->second;
+}
+
+void
+CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
+ FinalOverriderCollector Collector;
+ Collector.Collect(this, false, 0, FinalOverriders);
+
+ // Weed out any final overriders that come from virtual base class
+ // subobjects that were hidden by other subobjects along any path.
+ // This is the final-overrider variant of C++ [class.member.lookup]p10.
+ for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(),
+ OMEnd = FinalOverriders.end();
+ OM != OMEnd;
+ ++OM) {
+ for (OverridingMethods::iterator SO = OM->second.begin(),
+ SOEnd = OM->second.end();
+ SO != SOEnd;
+ ++SO) {
+ llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ if (Overriding.size() < 2)
+ continue;
+
+ for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ Pos = Overriding.begin(), PosEnd = Overriding.end();
+ Pos != PosEnd;
+ /* increment in loop */) {
+ if (!Pos->InVirtualSubobject) {
+ ++Pos;
+ continue;
+ }
+
+ // We have an overriding method in a virtual base class
+ // subobject (or non-virtual base class subobject thereof);
+ // determine whether there exists an other overriding method
+ // in a base class subobject that hides the virtual base class
+ // subobject.
+ bool Hidden = false;
+ for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ OP = Overriding.begin(), OPEnd = Overriding.end();
+ OP != OPEnd && !Hidden;
+ ++OP) {
+ if (Pos == OP)
+ continue;
+
+ if (OP->Method->getParent()->isVirtuallyDerivedFrom(
+ const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject)))
+ Hidden = true;
+ }
+
+ if (Hidden) {
+ // The current overriding function is hidden by another
+ // overriding function; remove this one.
+ Pos = Overriding.erase(Pos);
+ PosEnd = Overriding.end();
+ } else {
+ ++Pos;
+ }
+ }
+ }
+ }
+}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6c9a45ef6c44..dc9fb59e3090 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1413,10 +1413,8 @@ void TagDecl::startDefinition() {
CXXRecordDecl *D = cast<CXXRecordDecl>(this);
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
- do {
- D->DefinitionData = Data;
- D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration());
- } while (D);
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ cast<CXXRecordDecl>(*I)->DefinitionData = Data;
}
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 1aac7cfd598a..c693e153dda5 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
@@ -481,7 +482,7 @@ DeclContext::~DeclContext() {
// FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
// ~DeclContext() is not guaranteed to be called when ASTContext uses
// a BumpPtrAllocator.
- // delete static_cast<StoredDeclsMap*>(LookupPtr);
+ // delete LookupPtr;
}
void DeclContext::DestroyDecls(ASTContext &C) {
@@ -516,10 +517,16 @@ bool DeclContext::isDependentContext() const {
if (Record->getDescribedClassTemplate())
return true;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
if (Function->getDescribedFunctionTemplate())
return true;
+ // Friend function declarations are dependent if their *lexical*
+ // context is dependent.
+ if (cast<Decl>(this)->getFriendObjectKind())
+ return getLexicalParent()->isDependentContext();
+ }
+
return getParent() && getParent()->isDependentContext();
}
@@ -666,9 +673,7 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const {
// Load the declaration IDs for all of the names visible in this
// context.
assert(!LookupPtr && "Have a lookup map before de-serialization?");
- StoredDeclsMap *Map =
- (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap();
- LookupPtr = Map;
+ StoredDeclsMap *Map = CreateStoredDeclsMap(getParentASTContext());
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
}
@@ -727,10 +732,9 @@ void DeclContext::removeDecl(Decl *D) {
if (isa<NamedDecl>(D)) {
NamedDecl *ND = cast<NamedDecl>(D);
- void *OpaqueMap = getPrimaryContext()->LookupPtr;
- if (!OpaqueMap) return;
+ StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
+ if (!Map) return;
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap);
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
assert(Pos != Map->end() && "no lookup entry for decl");
Pos->second.remove(ND);
@@ -808,9 +812,8 @@ DeclContext::lookup(DeclarationName Name) {
return lookup_result(0, 0);
}
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr);
- StoredDeclsMap::iterator Pos = Map->find(Name);
- if (Pos == Map->end())
+ StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
+ if (Pos == LookupPtr->end())
return lookup_result(0, 0);
return Pos->second.getLookupResult(getParentASTContext());
}
@@ -878,12 +881,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
ASTContext *C = 0;
if (!LookupPtr) {
C = &getParentASTContext();
- LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap();
+ CreateStoredDeclsMap(*C);
}
// Insert this declaration into the map.
- StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
- StoredDeclsList &DeclNameEntries = Map[D->getDeclName()];
+ StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
@@ -952,13 +954,69 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) {
// Creation and Destruction of StoredDeclsMaps. //
//===----------------------------------------------------------------------===//
-void *ASTContext::CreateStoredDeclsMap() {
- StoredDeclsMap *M = new StoredDeclsMap();
- SDMs.push_back(M);
+StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
+ assert(!LookupPtr && "context already has a decls map");
+ assert(getPrimaryContext() == this &&
+ "creating decls map on non-primary context");
+
+ StoredDeclsMap *M;
+ bool Dependent = isDependentContext();
+ if (Dependent)
+ M = new DependentStoredDeclsMap();
+ else
+ M = new StoredDeclsMap();
+ M->Previous = C.LastSDM;
+ C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
+ LookupPtr = M;
return M;
}
void ASTContext::ReleaseDeclContextMaps() {
- for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I)
- delete (StoredDeclsMap*) *I;
+ // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap
+ // pointer because the subclass doesn't add anything that needs to
+ // be deleted.
+
+ StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt());
+}
+
+void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) {
+ while (Map) {
+ // Advance the iteration before we invalidate memory.
+ llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous;
+
+ if (Dependent)
+ delete static_cast<DependentStoredDeclsMap*>(Map);
+ else
+ delete Map;
+
+ Map = Next.getPointer();
+ Dependent = Next.getInt();
+ }
+}
+
+DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
+ DeclContext *Parent,
+ const PartialDiagnostic &PDiag) {
+ assert(Parent->isDependentContext()
+ && "cannot iterate dependent diagnostics of non-dependent context");
+ Parent = Parent->getPrimaryContext();
+ if (!Parent->LookupPtr)
+ Parent->CreateStoredDeclsMap(C);
+
+ DependentStoredDeclsMap *Map
+ = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr);
+
+ // Allocate the copy of the PartialDiagnostic via the ASTContext's
+ // BumpPtrAllocator, rather than the ASTContext itself.
+ PartialDiagnostic::Storage *DiagStorage = 0;
+ if (PDiag.hasStorage())
+ DiagStorage = new (C) PartialDiagnostic::Storage;
+
+ DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage);
+
+ // TODO: Maybe we shouldn't reverse the order during insertion.
+ DD->NextDiagnostic = Map->FirstDiagnostic;
+ Map->FirstDiagnostic = DD;
+
+ return DD;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 37f7479b36cd..94ed85c7cd2d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -83,9 +83,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (data().Bases)
C.Deallocate(data().Bases);
- int vbaseCount = 0;
- llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
- bool hasDirectVirtualBase = false;
+ // The set of seen virtual base types.
+ llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
+
+ // The virtual bases of this class.
+ llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases;
data().Bases = new(C) CXXBaseSpecifier [NumBases];
data().NumBases = NumBases;
@@ -99,58 +101,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
continue;
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- if (Base->isVirtual())
- hasDirectVirtualBase = true;
+
+ // Now go through all virtual bases of this base and add them.
for (CXXRecordDecl::base_class_iterator VBase =
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
- // Add this vbase to the array of vbases for current class if it is
- // not already in the list.
- // FIXME. Note that we do a linear search as number of such classes are
- // very few.
- int i;
- for (i = 0; i < vbaseCount; ++i)
- if (UniqueVbases[i]->getType() == VBase->getType())
- break;
- if (i == vbaseCount) {
- UniqueVbases.push_back(VBase);
- ++vbaseCount;
- }
+ // Add this base if it's not already in the list.
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ VBases.push_back(VBase);
}
- }
- if (hasDirectVirtualBase) {
- // Iterate one more time through the direct bases and add the virtual
- // base to the list of vritual bases for current class.
- for (unsigned i = 0; i < NumBases; ++i) {
- const CXXBaseSpecifier *VBase = Bases[i];
- if (!VBase->isVirtual())
- continue;
- int j;
- for (j = 0; j < vbaseCount; ++j)
- if (UniqueVbases[j]->getType() == VBase->getType())
- break;
- if (j == vbaseCount) {
- UniqueVbases.push_back(VBase);
- ++vbaseCount;
- }
+
+ if (Base->isVirtual()) {
+ // Add this base if it's not already in the list.
+ if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
+ VBases.push_back(Base);
}
+
}
- if (vbaseCount > 0) {
- // build AST for inhireted, direct or indirect, virtual bases.
- data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
- data().NumVBases = vbaseCount;
- for (int i = 0; i < vbaseCount; i++) {
- QualType QT = UniqueVbases[i]->getType();
- // Skip dependent types; we can't do any checking on them now.
- if (QT->isDependentType())
- continue;
- CXXRecordDecl *VBaseClassDecl
- = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
- data().VBases[i] =
- CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
- VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
- UniqueVbases[i]->getAccessSpecifier(), QT);
- }
+
+ if (VBases.empty())
+ return;
+
+ // Create base specifier for any direct or indirect virtual bases.
+ data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
+ data().NumVBases = VBases.size();
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType VBaseType = VBases[I]->getType();
+
+ // Skip dependent types; we can't do any checking on them now.
+ if (VBaseType->isDependentType())
+ continue;
+
+ CXXRecordDecl *VBaseClassDecl
+ = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+
+ data().VBases[I] =
+ CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
+ VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+ VBases[I]->getAccessSpecifier(), VBaseType);
}
}
@@ -320,6 +308,8 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
+ if (isa<UsingShadowDecl>(Conv))
+ Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
T = ConvTemp->getTemplatedDecl()->getResultType();
else
@@ -457,26 +447,45 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
return &data().VisibleConversions;
}
-void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
- assert(!ConvDecl->getDescribedFunctionTemplate() &&
- "Conversion function templates should cast to FunctionTemplateDecl.");
+#ifndef NDEBUG
+void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
assert(ConvDecl->getDeclContext() == this &&
"conversion function does not belong to this record");
- // We intentionally don't use the decl's access here because it
- // hasn't been set yet. That's really just a misdesign in Sema.
- data().Conversions.addDecl(ConvDecl);
+ ConvDecl = ConvDecl->getUnderlyingDecl();
+ if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
+ assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
+ } else {
+ assert(isa<CXXConversionDecl>(ConvDecl));
+ }
}
+#endif
+
+void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
+ // This operation is O(N) but extremely rare. Sema only uses it to
+ // remove UsingShadowDecls in a class that were followed by a direct
+ // declaration, e.g.:
+ // class A : B {
+ // using B::operator int;
+ // operator int();
+ // };
+ // This is uncommon by itself and even more uncommon in conjunction
+ // with sufficiently large numbers of directly-declared conversions
+ // that asymptotic behavior matters.
+
+ UnresolvedSetImpl &Convs = *getConversionFunctions();
+ for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
+ if (Convs[I].getDecl() == ConvDecl) {
+ Convs.erase(I);
+ assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
+ && "conversion was found multiple times in unresolved set");
+ return;
+ }
+ }
-void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
- assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
- "Function template is not a conversion function template");
- assert(ConvDecl->getDeclContext() == this &&
- "conversion function does not belong to this record");
- data().Conversions.addDecl(ConvDecl);
+ llvm_unreachable("conversion not found in set!");
}
-
void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
Method->setVirtualAsWritten(true);
setAggregate(false);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6a71e925d9b3..6764612c80b6 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -492,44 +492,45 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
-MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
- SourceRange qualrange, ValueDecl *memberdecl,
- SourceLocation l, const TemplateArgumentListInfo *targs,
- QualType ty)
- : Expr(MemberExprClass, ty,
- base->isTypeDependent() || (qual && qual->isDependent()),
- base->isValueDependent() || (qual && qual->isDependent())),
- Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) {
- // Initialize the qualifier, if any.
- if (HasQualifier) {
- NameQualifier *NQ = getMemberQualifier();
- NQ->NNS = qual;
- NQ->Range = qualrange;
- }
-
- // Initialize the explicit template argument list, if any.
- if (targs)
- getExplicitTemplateArgumentList()->initializeFrom(*targs);
-}
-
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
ValueDecl *memberdecl,
+ NamedDecl *founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
- if (qual != 0)
- Size += sizeof(NameQualifier);
+
+ bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
+ if (hasQualOrFound)
+ Size += sizeof(MemberNameQualifier);
if (targs)
Size += ExplicitTemplateArgumentList::sizeFor(*targs);
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
- return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
- targs, ty);
+ MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty);
+
+ if (hasQualOrFound) {
+ if (qual && qual->isDependent()) {
+ E->setValueDependent(true);
+ E->setTypeDependent(true);
+ }
+ E->HasQualifierOrFoundDecl = true;
+
+ MemberNameQualifier *NQ = E->getMemberQualifier();
+ NQ->NNS = qual;
+ NQ->Range = qualrange;
+ NQ->FoundDecl = founddecl;
+ }
+
+ if (targs) {
+ E->HasExplicitTemplateArgumentList = true;
+ E->getExplicitTemplateArgumentList()->initializeFrom(*targs);
+ }
+
+ return E;
}
const char *CastExpr::getCastKindName() const {
@@ -544,6 +545,8 @@ const char *CastExpr::getCastKindName() const {
return "BaseToDerived";
case CastExpr::CK_DerivedToBase:
return "DerivedToBase";
+ case CastExpr::CK_UncheckedDerivedToBase:
+ return "UncheckedDerivedToBase";
case CastExpr::CK_Dynamic:
return "Dynamic";
case CastExpr::CK_ToUnion:
@@ -914,8 +917,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case CXXConstructExprClass:
return false;
- case ObjCMessageExprClass:
+ case ObjCMessageExprClass: {
+ const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
+ Loc = getExprLoc();
+ return true;
+ }
return false;
+ }
case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send.
#if 0
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 8a64f8ea97ec..27a277ddbcb0 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -750,7 +750,7 @@ bool Type::isSpecifierType() const {
case SubstTemplateTypeParm:
case TemplateSpecialization:
case QualifiedName:
- case Typename:
+ case DependentName:
case ObjCInterface:
case ObjCObjectPointer:
case Elaborated:
@@ -760,6 +760,27 @@ bool Type::isSpecifierType() const {
}
}
+bool Type::isElaboratedTypeSpecifier() const {
+ if (getTypeClass() == Elaborated)
+ return true;
+
+ if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
+ switch (Dependent->getKeyword()) {
+ case ETK_None:
+ case ETK_Typename:
+ return false;
+
+ case ETK_Class:
+ case ETK_Struct:
+ case ETK_Union:
+ case ETK_Enum:
+ return true;
+ }
+ }
+
+ return false;
+}
+
const char *Type::getTypeClassName() const {
switch (TC) {
default: assert(0 && "Type class not in TypeNodes.def!");
@@ -820,8 +841,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs, bool NoReturn,
- CallingConv CallConv) {
+ exception_iterator Exs,
+ const FunctionType::ExtInfo &Info) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -833,15 +854,16 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
for (unsigned i = 0; i != NumExceptions; ++i)
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
- ID.AddInteger(NoReturn);
- ID.AddInteger(CallConv);
+ ID.AddInteger(Info.getNoReturn());
+ ID.AddInteger(Info.getRegParm());
+ ID.AddInteger(Info.getCC());
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin(), getNoReturnAttr(),
- getCallConv());
+ getNumExceptions(), exception_begin(),
+ getExtInfo());
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0c4896decf85..4cf0922ee316 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -282,7 +282,8 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
- switch(T->getCallConv()) {
+ FunctionType::ExtInfo Info = T->getExtInfo();
+ switch(Info.getCC()) {
case CC_Default:
default: break;
case CC_C:
@@ -295,9 +296,11 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += " __attribute__((fastcall))";
break;
}
- if (T->getNoReturnAttr())
+ if (Info.getNoReturn())
S += " __attribute__((noreturn))";
-
+ if (Info.getRegParm())
+ S += " __attribute__((regparm (" +
+ llvm::utostr_32(Info.getRegParm()) + ")))";
if (T->hasExceptionSpec()) {
S += " throw(";
@@ -564,12 +567,20 @@ void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
S = MyString + ' ' + S;
}
-void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) {
+void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) {
std::string MyString;
{
llvm::raw_string_ostream OS(MyString);
- OS << "typename ";
+ switch (T->getKeyword()) {
+ case ETK_None: break;
+ case ETK_Typename: OS << "typename "; break;
+ case ETK_Class: OS << "class "; break;
+ case ETK_Struct: OS << "struct "; break;
+ case ETK_Union: OS << "union "; break;
+ case ETK_Enum: OS << "enum "; break;
+ }
+
T->getQualifier()->print(OS, Policy);
if (const IdentifierInfo *Ident = T->getIdentifier())
@@ -819,4 +830,3 @@ void QualType::getAsStringInternal(std::string &S,
TypePrinter Printer(Policy);
Printer.Print(*this, S);
}
-
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 5640c4a461e0..06d8aec3910e 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -54,8 +54,12 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
}
CFG *AnalysisContext::getCFG() {
- if (!cfg)
+ if (!builtCFG) {
cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
+ // Even when the cfg is not successfully built, we don't
+ // want to try building it again.
+ builtCFG = true;
+ }
return cfg;
}
@@ -126,9 +130,9 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx,
llvm::FoldingSetNodeID ID;
LOC::Profile(ID, ctx, parent, d);
void *InsertPos;
-
+
LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
-
+
if (!L) {
L = new LOC(ctx, parent, d);
Contexts.InsertNode(L, InsertPos);
@@ -144,7 +148,7 @@ LocationContextManager::getStackFrame(AnalysisContext *ctx,
llvm::FoldingSetNodeID ID;
StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
void *InsertPos;
- StackFrameContext *L =
+ StackFrameContext *L =
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
if (!L) {
L = new StackFrameContext(ctx, parent, s, blk, idx);
@@ -253,7 +257,7 @@ public:
IgnoredContexts.insert(BR->getBlockDecl());
Visit(BR->getBlockDecl()->getBody());
}
-};
+};
} // end anonymous namespace
typedef BumpVector<const VarDecl*> DeclVec;
@@ -263,16 +267,16 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
llvm::BumpPtrAllocator &A) {
if (Vec)
return (DeclVec*) Vec;
-
+
BumpVectorContext BC(A);
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
new (BV) DeclVec(BC, 10);
-
+
// Find the referenced variables.
FindBlockDeclRefExprsVals F(*BV, BC);
F.Visit(BD->getBody());
-
- Vec = BV;
+
+ Vec = BV;
return BV;
}
@@ -281,7 +285,7 @@ std::pair<AnalysisContext::referenced_decls_iterator,
AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
if (!ReferencedBlockVars)
ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
-
+
DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
return std::make_pair(V->begin(), V->end());
}
@@ -310,12 +314,12 @@ LocationContextManager::~LocationContextManager() {
void LocationContextManager::clear() {
for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
- E = Contexts.end(); I != E; ) {
+ E = Contexts.end(); I != E; ) {
LocationContext *LC = &*I;
++I;
delete LC;
}
-
+
Contexts.clear();
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index a4a021f20b21..f94f6b3f127f 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -571,7 +571,7 @@ static bool CanThrow(Expr *E) {
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
// If this is a call to a no-return function, this stops the block here.
bool NoReturn = false;
- if (C->getCallee()->getType().getNoReturnAttr()) {
+ if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) {
NoReturn = true;
}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 46acc8a377bf..c38aae34764c 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -75,7 +75,7 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
char c = *I;
if (c >= '0' && c <= '9') {
hasDigits = true;
- accumulator += (accumulator * 10) + (c - '0');
+ accumulator = (accumulator * 10) + (c - '0');
continue;
}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index f7ec873e4c15..2b7fcd07f9d0 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -124,10 +125,20 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
return 0;
}
-bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->SFINAE && Info->Class == CLASS_ERROR;
- return false;
+Diagnostic::SFINAEResponse
+Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
+ if (!Info->SFINAE)
+ return SFINAE_Report;
+
+ if (Info->Class == CLASS_ERROR)
+ return SFINAE_SubstitutionFailure;
+
+ // Suppress notes, warnings, and extensions;
+ return SFINAE_Suppress;
+ }
+
+ return SFINAE_Report;
}
/// getDiagClass - Return the class field of the diagnostic.
@@ -222,6 +233,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
+ DelayedDiagID = 0;
+
// Set all mappings to 'unset'.
DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0);
DiagMappingsStack.push_back(BlankDiags);
@@ -289,6 +302,23 @@ const char *Diagnostic::getDescription(unsigned DiagID) const {
return CustomDiagInfo->getDescription(DiagID);
}
+void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
+ llvm::StringRef Arg2) {
+ if (DelayedDiagID)
+ return;
+
+ DelayedDiagID = DiagID;
+ DelayedDiagArg1 = Arg1.str();
+ DelayedDiagArg2 = Arg2.str();
+}
+
+void Diagnostic::ReportDelayed() {
+ Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
+ DelayedDiagID = 0;
+ DelayedDiagArg1.clear();
+ DelayedDiagArg2.clear();
+}
+
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
@@ -532,6 +562,35 @@ bool Diagnostic::ProcessDiag() {
return true;
}
+bool DiagnosticBuilder::Emit() {
+ // If DiagObj is null, then its soul was stolen by the copy ctor
+ // or the user called Emit().
+ if (DiagObj == 0) return false;
+
+ // When emitting diagnostics, we set the final argument count into
+ // the Diagnostic object.
+ DiagObj->NumDiagArgs = NumArgs;
+ DiagObj->NumDiagRanges = NumRanges;
+ DiagObj->NumFixItHints = NumFixItHints;
+
+ // Process the diagnostic, sending the accumulated information to the
+ // DiagnosticClient.
+ bool Emitted = DiagObj->ProcessDiag();
+
+ // Clear out the current diagnostic object.
+ unsigned DiagID = DiagObj->CurDiagID;
+ DiagObj->Clear();
+
+ // If there was a delayed diagnostic, emit it now.
+ if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID)
+ DiagObj->ReportDelayed();
+
+ // This diagnostic is dead.
+ DiagObj = 0;
+
+ return Emitted;
+}
+
DiagnosticClient::~DiagnosticClient() {}
@@ -937,9 +996,9 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I)
Ranges.push_back(Info.getRange(I));
- FixIts.reserve(Info.getNumCodeModificationHints());
- for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I)
- FixIts.push_back(Info.getCodeModificationHint(I));
+ FixIts.reserve(Info.getNumFixItHints());
+ for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I)
+ FixIts.push_back(Info.getFixItHint(I));
}
StoredDiagnostic::~StoredDiagnostic() { }
@@ -1172,7 +1231,7 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
return Diag;
}
- CodeModificationHint Hint;
+ FixItHint Hint;
Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
@@ -1188,3 +1247,13 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
/// DiagnosticClient should be included in the number of diagnostics
/// reported by Diagnostic.
bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; }
+
+PartialDiagnostic::StorageAllocator::StorageAllocator() {
+ for (unsigned I = 0; I != NumCached; ++I)
+ FreeList[I] = Cached + I;
+ NumFreeListEntries = NumCached;
+}
+
+PartialDiagnostic::StorageAllocator::~StorageAllocator() {
+ assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
+}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 6def967c4cfa..27cb9bebde42 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -89,16 +89,26 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
- Diag.Report(diag::err_cannot_open_file)
- << Entry->getName() << ErrorStr;
+
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
+ Entry->getName(), ErrorStr);
+ else
+ Diag.Report(diag::err_cannot_open_file)
+ << Entry->getName() << ErrorStr;
+
Buffer.setInt(true);
} else if (FileInfo.st_size != Entry->getSize() ||
- FileInfo.st_mtime != Entry->getModificationTime() ||
- FileInfo.st_ino != Entry->getInode()) {
+ 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).
- Diag.Report(diag::err_file_modified) << Entry->getName();
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_file_modified,
+ Entry->getName());
+ else
+ Diag.Report(diag::err_file_modified) << Entry->getName();
+
Buffer.setInt(true);
}
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 8f472b3d3d45..e3d9ed3335a7 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -292,6 +292,7 @@ protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
// PS3 PPU defines.
+ Builder.defineMacro("__PPC__");
Builder.defineMacro("__PPU__");
Builder.defineMacro("__CELLOS_LV2__");
Builder.defineMacro("__ELF__");
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp
index e95a86b838b6..b92f2e705625 100644
--- a/lib/Checker/AdjustedReturnValueChecker.cpp
+++ b/lib/Checker/AdjustedReturnValueChecker.cpp
@@ -14,11 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
using namespace clang;
diff --git a/lib/Checker/AggExprVisitor.cpp b/lib/Checker/AggExprVisitor.cpp
new file mode 100644
index 000000000000..343afec18d21
--- /dev/null
+++ b/lib/Checker/AggExprVisitor.cpp
@@ -0,0 +1,55 @@
+//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- 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 AggExprVisitor class, which contains lots of boiler
+// plate code for evaluating expressions of C++ class type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+
+namespace {
+class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
+ SVal DestPtr;
+ ExplodedNode *Pred;
+ ExplodedNodeSet &DstSet;
+ GRExprEngine &Eng;
+
+public:
+ AggExprVisitor(SVal dest, ExplodedNode *N, ExplodedNodeSet &dst,
+ GRExprEngine &eng)
+ : DestPtr(dest), Pred(N), DstSet(dst), Eng(eng) {}
+
+ void VisitCastExpr(CastExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
+};
+}
+
+void AggExprVisitor::VisitCastExpr(CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ assert(0 && "Unhandled cast kind");
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_ConstructorConversion:
+ Visit(E->getSubExpr());
+ break;
+ }
+}
+
+void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ Eng.VisitCXXConstructExpr(E, DestPtr, Pred, DstSet);
+}
+
+void GRExprEngine::VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
+}
diff --git a/lib/Checker/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp
index 74fb06f45564..746b3f95d41e 100644
--- a/lib/Checker/ArrayBoundChecker.cpp
+++ b/lib/Checker/ArrayBoundChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp
index 83dc13e92b63..309a74ce544b 100644
--- a/lib/Checker/AttrNonNullChecker.cpp
+++ b/lib/Checker/AttrNonNullChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index d6c09a2e04a6..810d0fbb997a 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -19,9 +19,8 @@
#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 7272b348581b..12e61afa1010 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
@@ -1139,12 +1140,9 @@ void EdgeBuilder::addContext(const Stmt *S) {
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N) {
-
-
EdgeBuilder EB(PD, PDB);
- const ExplodedNode* NextNode = N->pred_empty()
- ? NULL : *(N->pred_begin());
+ const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
NextNode = GetPredecessorNode(N);
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 1d6994b94b4b..06cee5bcd1bc 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 9a76f6a2a3ad..3c4a27cc07f4 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -16,8 +16,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index c5bd2eb7cc2c..dec375e65da7 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangChecker
AdjustedReturnValueChecker.cpp
+ AggExprVisitor.cpp
ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
BasicConstraintManager.cpp
@@ -11,16 +12,16 @@ add_clang_library(clangChecker
BugReporter.cpp
BugReporterVisitors.cpp
BuiltinFunctionChecker.cpp
- CFRefCount.cpp
CallAndMessageChecker.cpp
CallInliner.cpp
CastToStructChecker.cpp
+ CFRefCount.cpp
CheckDeadStores.cpp
+ Checker.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
- Checker.cpp
CocoaConventions.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
@@ -38,11 +39,11 @@ add_clang_library(clangChecker
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ NoReturnFunctionChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
- NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
ObjCUnusedIVarsChecker.cpp
+ OSAtomicChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
@@ -52,18 +53,18 @@ add_clang_library(clangChecker
ReturnPointerRangeChecker.cpp
ReturnStackAddressChecker.cpp
ReturnUndefChecker.cpp
- SVals.cpp
- SValuator.cpp
SimpleConstraintManager.cpp
SimpleSValuator.cpp
Store.cpp
+ SVals.cpp
+ SValuator.cpp
SymbolManager.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
- UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
+ UndefResultChecker.cpp
UnixAPIChecker.cpp
- VLASizeChecker.cpp
ValueManager.cpp
+ VLASizeChecker.cpp
)
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index 32cf7534c8f6..dd1856c9d2d6 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/AST/ParentMap.h"
-#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index bef5bc285ee2..2c16f8905811 100644
--- a/lib/Checker/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index 923baf50f3f6..efbce6126146 100644
--- a/lib/Checker/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -36,7 +36,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
-
+
const bool CheckRand;
public:
@@ -214,8 +214,8 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
llvm::SmallVector<SourceRange, 2> ranges;
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
os << "Variable '" << drCond->getDecl()->getNameAsCString()
<< "' with floating point type '" << drCond->getType().getAsString()
@@ -315,7 +315,7 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
if(!FPT)
return;
-
+
// Verify that the funcion takes a single argument.
if (FPT->getNumArgs() != 1)
return;
@@ -328,17 +328,16 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
// Verify that the argument is a 'char*'.
if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
return;
-
+
// Issue a waring.
SourceRange R = CE->getCallee()->getSourceRange();
BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
"Security",
"Call to function 'mktemp' is insecure as it always "
- "creates or uses insecure temporary file",
+ "creates or uses insecure temporary file. Use 'mkstemp' instead",
CE->getLocStart(), &R, 1);
}
-
//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
@@ -386,20 +385,18 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- std::string buf1;
- llvm::raw_string_ostream os1(buf1);
+ llvm::SmallString<256> buf1;
+ llvm::raw_svector_ostream os1(buf1);
os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
- std::string buf2;
- llvm::raw_string_ostream os2(buf2);
+ llvm::SmallString<256> buf2;
+ llvm::raw_svector_ostream os2(buf2);
os2 << "Function '" << FD->getNameAsString()
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
SourceRange R = CE->getCallee()->getSourceRange();
-
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),
- CE->getLocStart(), &R, 1);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -425,8 +422,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
"Security",
"The 'random' function produces a sequence of values that "
"an adversary may be able to predict. Use 'arc4random' "
- "instead",
- CE->getLocStart(), &R, 1);
+ "instead", CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -474,22 +470,20 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
return;
// Issue a warning.
- std::string buf1;
- llvm::raw_string_ostream os1(buf1);
+ llvm::SmallString<256> buf1;
+ llvm::raw_svector_ostream os1(buf1);
os1 << "Return value is not checked in call to '" << FD->getNameAsString()
<< "'";
- std::string buf2;
- llvm::raw_string_ostream os2(buf2);
+ 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()
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
-
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),
- CE->getLocStart(), &R, 1);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp
index 0cbc4086701a..af74c79558d5 100644
--- a/lib/Checker/DereferenceChecker.cpp
+++ b/lib/Checker/DereferenceChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
using namespace clang;
@@ -29,9 +29,9 @@ public:
DereferenceChecker() : BT_null(0), BT_undef(0) {}
static void *getTag() { static int tag = 0; return &tag; }
void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
-
+
std::pair<ExplodedNode * const*, ExplodedNode * const*>
- getImplicitNodes() const {
+ getImplicitNodes() const {
return std::make_pair(ImplicitNullDerefNodes.data(),
ImplicitNullDerefNodes.data() +
ImplicitNullDerefNodes.size());
@@ -59,7 +59,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_undef)
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
-
+
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
@@ -68,31 +68,32 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
}
return;
}
-
+
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
-
- // Check for null dereferences.
+
+ // Check for null dereferences.
if (!isa<Loc>(location))
return;
-
+
const GRState *state = C.getState();
const GRState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->Assume(location);
-
+
// The explicit NULL case.
if (nullState) {
- if (!notNullState) {
+ if (!notNullState) {
// Generate an error node.
ExplodedNode *N = C.GenerateSink(nullState);
if (!N)
return;
-
+
// We know that 'location' cannot be non-null. This is what
- // we call an "explicit" null dereference.
+ // we call an "explicit" null dereference.
if (!BT_null)
BT_null = new BuiltinBug("Dereference of null pointer");
-
+
llvm::SmallString<100> buf;
+ llvm::SmallVector<SourceRange, 2> Ranges;
switch (S->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
@@ -101,10 +102,26 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
llvm::raw_svector_ostream os(buf);
- os << "Dereference of null pointer loaded from variable '"
- << VD->getName() << '\'';
+ os << "Dereference of null pointer (loaded from variable '"
+ << VD->getName() << "')";
+ Ranges.push_back(DR->getSourceRange());
}
}
+ break;
+ }
+ case Stmt::MemberExprClass: {
+ const MemberExpr *M = cast<MemberExpr>(S);
+ if (M->isArrow())
+ if (DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ llvm::raw_svector_ostream os(buf);
+ os << "Field access results in a dereference of a null pointer "
+ "(loaded from variable '" << VD->getName() << "')";
+ Ranges.push_back(M->getBase()->getSourceRange());
+ }
+ }
+ break;
}
default:
break;
@@ -117,19 +134,23 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
-
+
+ for (llvm::SmallVectorImpl<SourceRange>::iterator
+ I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
+ report->addRange(*I);
+
C.EmitReport(report);
return;
}
else {
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
- // dereference.
+ // dereference.
if (ExplodedNode *N = C.GenerateSink(nullState))
ImplicitNullDerefNodes.push_back(N);
}
}
-
+
// From this point forward, we know that the location is not null.
C.addTransition(notNullState);
}
diff --git a/lib/Checker/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp
index e1346e11b6fd..e09a87149f5c 100644
--- a/lib/Checker/DivZeroChecker.cpp
+++ b/lib/Checker/DivZeroChecker.cpp
@@ -12,8 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp
index 671cf89119f3..cc71f8569c62 100644
--- a/lib/Checker/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -10,9 +10,10 @@
// This file defined the Environment and EnvironmentManager classes.
//
//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
diff --git a/lib/Checker/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp
index 04c17d6d7abb..4fce45bd35e8 100644
--- a/lib/Checker/FixedAddressChecker.cpp
+++ b/lib/Checker/FixedAddressChecker.cpp
@@ -13,8 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp
index 3fa3e1ebb9c6..cd26060ef0aa 100644
--- a/lib/Checker/GRBlockCounter.cpp
+++ b/lib/Checker/GRBlockCounter.cpp
@@ -18,7 +18,34 @@
using namespace clang;
-typedef llvm::ImmutableMap<unsigned,unsigned> CountMap;
+namespace {
+
+class CountKey {
+ const StackFrameContext *CallSite;
+ unsigned BlockID;
+
+public:
+ CountKey(const StackFrameContext *CS, unsigned ID)
+ : CallSite(CS), BlockID(ID) {}
+
+ bool operator==(const CountKey &RHS) const {
+ return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
+ }
+
+ bool operator<(const CountKey &RHS) const {
+ return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID)
+ : (CallSite < RHS.CallSite);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(CallSite);
+ ID.AddInteger(BlockID);
+ }
+};
+
+}
+
+typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
static inline CountMap GetMap(void* D) {
return CountMap(static_cast<CountMap::TreeTy*>(D));
@@ -28,9 +55,10 @@ static inline CountMap::Factory& GetFactory(void* F) {
return *static_cast<CountMap::Factory*>(F);
}
-unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const {
+unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite,
+ unsigned BlockID) const {
CountMap M = GetMap(Data);
- CountMap::data_type* T = M.lookup(BlockID);
+ CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
return T ? *T : 0;
}
@@ -43,9 +71,12 @@ GRBlockCounter::Factory::~Factory() {
}
GRBlockCounter
-GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) {
- return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID,
- BC.getNumVisited(BlockID)+1).getRoot());
+GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC,
+ const StackFrameContext *CallSite,
+ unsigned BlockID) {
+ return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data),
+ CountKey(CallSite, BlockID),
+ BC.getNumVisited(CallSite, BlockID)+1).getRoot());
}
GRBlockCounter
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index a9347d01641c..e4ef6b0e106f 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -126,9 +126,9 @@ void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) {
SubEngine.ProcessStmt(E, Builder);
}
-bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
GRBlockCounter BC) {
- return SubEngine.ProcessBlockEntrance(Blk, State, BC);
+ return SubEngine.ProcessBlockEntrance(Blk, Pred, BC);
}
void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator,
@@ -256,7 +256,7 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
// FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
- if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
+ if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter()))
GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred);
}
@@ -265,7 +265,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
// Increment the block counter.
GRBlockCounter Counter = WList->getBlockCounter();
- Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID());
+ Counter = BCounterFactory.IncrementCount(Counter,
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ L.getBlock()->getBlockID());
WList->setBlockCounter(Counter);
// Process the entrance of the block.
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 3ace552adcb2..bab8922a8c2b 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -13,6 +13,8 @@
//
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Checker/PathSensitive/Checker.h"
@@ -582,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
switch (S->getStmtClass()) {
// C++ stuff we don't support yet.
- case Stmt::CXXMemberCallExprClass:
case Stmt::CXXNamedCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
@@ -671,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXMemberCallExprClass: {
+ CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
+ VisitCXXMemberCallExpr(MCE, Pred, Dst);
+ break;
+ }
+
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
@@ -895,6 +902,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
}
+ case Stmt::ObjCIsaExprClass:
+ // FIXME: Do something more intelligent with 'x->isa = ...'.
+ // For now, just ignore the assignment.
+ return;
+
case Stmt::ObjCPropertyRefExprClass:
case Stmt::ObjCImplicitSetterGetterRefExprClass:
// FIXME: Property assignments are lvalues, but not really "locations".
@@ -944,10 +956,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
// Block entrance. (Update counters).
//===----------------------------------------------------------------------===//
-bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
+bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC) {
- return BC.getNumVisited(B->getBlockID()) < 3;
+ return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
+ B->getBlockID()) < 3;
}
//===----------------------------------------------------------------------===//
@@ -1328,6 +1341,22 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
if (ReturnedExpr) {
SVal RetVal = state->getSVal(ReturnedExpr);
state = state->BindExpr(CE, RetVal);
+ // Clear the return expr GDM.
+ state = state->remove<ReturnExpr>();
+ }
+
+ // Bind the constructed object value to CXXConstructExpr.
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
+ const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx);
+ // We might not have 'this' region in the binding if we didn't inline
+ // the ctor call.
+ SVal ThisV = state->getSVal(ThisR);
+ loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV);
+ if (V) {
+ SVal ObjVal = state->getSVal(V->getRegion());
+ assert(isa<nonloc::LazyCompoundVal>(ObjVal));
+ state = state->BindExpr(CCE, ObjVal);
+ }
}
B.GenerateNode(state);
@@ -2282,6 +2311,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
case CastExpr::CK_AnyPointerToObjCPointerCast:
case CastExpr::CK_AnyPointerToBlockPointerCast:
case CastExpr::CK_DerivedToBase:
+ case CastExpr::CK_UncheckedDerivedToBase:
// Delegate to SValuator to process.
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
ExplodedNode* N = *I;
@@ -2338,8 +2368,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet Tmp;
if (InitEx) {
- if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) {
- VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD,
+ QualType InitTy = InitEx->getType();
+ if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) {
+ // Delegate expressions of C++ record type evaluation to AggExprVisitor.
+ VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD,
Pred->getLocationContext()), Pred, Dst);
return;
} else if (VD->getType()->isReferenceType())
@@ -2908,7 +2940,8 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state.
+ // Record the returned expression in the state. It will be used in
+ // ProcessCallExit to bind the return value to the call expr.
{
static int Tag = 0;
SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
@@ -3137,6 +3170,10 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
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);
@@ -3190,10 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
Pred->getLocationContext(),
E, Builder->getBlock(), Builder->getIndex());
- Type *T = CD->getParent()->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T,0));
- const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT,
- SFC);
+ const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
CallEnter Loc(E, CD, Pred->getLocationContext());
for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
@@ -3206,6 +3240,91 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
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/GRState.cpp b/lib/Checker/GRState.cpp
index 2defbcd93c01..f68e10b0cbc9 100644
--- a/lib/Checker/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/CFG.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -227,6 +227,18 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
return getPersistentState(NewSt);
}
+const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) {
+ GRState::GenericDataMap OldM = state->getGDM();
+ GRState::GenericDataMap NewM = GDMFactory.Remove(OldM, Key);
+
+ if (NewM == OldM)
+ return state;
+
+ GRState NewState = *state;
+ NewState.GDM = NewM;
+ return getPersistentState(NewState);
+}
+
//===----------------------------------------------------------------------===//
// Utility.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp
index 9621e853bc48..bcd96e73305e 100644
--- a/lib/Checker/MacOSXAPIChecker.cpp
+++ b/lib/Checker/MacOSXAPIChecker.cpp
@@ -17,7 +17,7 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp
index a08afc4b7959..a22df3046920 100644
--- a/lib/Checker/MallocChecker.cpp
+++ b/lib/Checker/MallocChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9a26988fcf1d..9f12ab622fbf 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -13,10 +13,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index e428e2e83f2a..9130bfad8407 100644
--- a/lib/Checker/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -16,7 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/Checkers/LocalCheckers.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
diff --git a/lib/Checker/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp
index 1455d87665db..12527e076221 100644
--- a/lib/Checker/NoReturnFunctionChecker.cpp
+++ b/lib/Checker/NoReturnFunctionChecker.cpp
@@ -13,17 +13,17 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
namespace {
-class NoReturnFunctionChecker : public Checker {
+class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
public:
static void *getTag() { static int tag = 0; return &tag; }
- virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
};
}
@@ -32,48 +32,48 @@ void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) {
Eng.registerCheck(new NoReturnFunctionChecker());
}
-bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
- bool BuildSinks = false;
+ bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
- if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
- BuildSinks = true;
- else if (const IdentifierInfo *II = FD->getIdentifier()) {
- // HACK: Some functions are not marked noreturn, and don't return.
- // Here are a few hardwired ones. If this takes too long, we can
- // potentially cache these results.
- BuildSinks
- = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
+ if (!BuildSinks) {
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return;
+
+ if (FD->getAttr<AnalyzerNoReturnAttr>())
+ BuildSinks = true;
+ else if (const IdentifierInfo *II = FD->getIdentifier()) {
+ // HACK: Some functions are not marked noreturn, and don't return.
+ // Here are a few hardwired ones. If this takes too long, we can
+ // potentially cache these results.
+ BuildSinks
+ = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
+ .Case("exit", true)
+ .Case("panic", true)
+ .Case("error", true)
+ .Case("Assert", true)
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ .Case("ziperr", true)
+ .Case("assfail", true)
+ .Case("db_error", true)
+ .Case("__assert", true)
+ .Case("__assert_rtn", true)
+ .Case("__assert_fail", true)
+ .Case("dtrace_assfail", true)
+ .Case("yy_fatal_error", true)
+ .Case("_XCAssertionFailureHandler", true)
+ .Case("_DTAssertionFailureHandler", true)
+ .Case("_TSAssertionFailureHandler", true)
+ .Default(false);
+ }
}
-
- if (!BuildSinks)
- return false;
- C.GenerateSink(CE);
- return true;
+ if (BuildSinks)
+ C.GenerateSink(CE);
}
diff --git a/lib/Checker/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp
index 97500d95785c..963923c9ad10 100644
--- a/lib/Checker/PathDiagnostic.cpp
+++ b/lib/Checker/PathDiagnostic.cpp
@@ -108,8 +108,8 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
P->addRange(Info.getRange(i));
- for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
- P->addCodeModificationHint(Info.getCodeModificationHint(i));
+ for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
+ P->addFixItHint(Info.getFixItHint(i));
D->push_front(P);
HandlePathDiagnostic(D);
diff --git a/lib/Checker/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp
index 3d62d0c7b9d7..ed60c42613fe 100644
--- a/lib/Checker/PointerArithChecker.cpp
+++ b/lib/Checker/PointerArithChecker.cpp
@@ -12,8 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp
index acc848ac8edb..bc0fd24d19b4 100644
--- a/lib/Checker/PointerSubChecker.cpp
+++ b/lib/Checker/PointerSubChecker.cpp
@@ -13,8 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index c2b702acad9a..c97da33aaac6 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -536,15 +536,15 @@ public:
// First visit the cluster.
static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end());
- // Next, visit the region.
- static_cast<DERIVED*>(this)->VisitRegion(baseR);
+ // Next, visit the base region.
+ static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
}
}
public:
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {}
- void VisitRegion(const MemRegion *baseR) {}
+ void VisitBaseRegion(const MemRegion *baseR) {}
};
}
@@ -580,7 +580,7 @@ public:
Ex(ex), Count(count), IS(is) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
- void VisitRegion(const MemRegion *baseR);
+ void VisitBaseRegion(const MemRegion *baseR);
private:
void VisitBinding(SVal V);
@@ -627,7 +627,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
}
}
-void InvalidateRegionsWorker::VisitRegion(const MemRegion *baseR) {
+void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (IS) {
// Symbolic region? Mark that symbol touched by the invalidation.
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
@@ -787,9 +787,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
return ValMgr.makeIntVal(CAT->getSize(), false);
}
- // Clients can use ordinary variables as if they were arrays. These
- // essentially are arrays of size 1.
- return ValMgr.makeIntVal(1, false);
+ // Clients can reinterpret ordinary variables as arrays, possibly of
+ // another type. The width is rounded down to ensure that an access is
+ // entirely within bounds.
+ CharUnits VarSize = getContext().getTypeSizeInChars(T);
+ CharUnits EleSize = getContext().getTypeSizeInChars(EleTy);
+ return ValMgr.makeIntVal(VarSize / EleSize, false);
}
}
@@ -963,7 +966,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return V;
return getDefaultBinding(B, R);
@@ -1044,7 +1047,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
#endif
- if (RTy->isStructureType())
+ if (RTy->isStructureType() || RTy->isClassType())
return RetrieveStruct(store, R);
// FIXME: Handle unions.
@@ -1144,7 +1147,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1175,7 +1178,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
}
// Check if the immediate super region has a direct binding.
- if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (const Optional<SVal> &V = getDirectBinding(B, superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1203,7 +1206,7 @@ SVal RegionStoreManager::RetrieveField(Store store,
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
QualType Ty = R->getValueType(getContext());
@@ -1278,13 +1281,13 @@ SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
const MemRegion *superR = R->getSuperRegion();
// Check if the super region has a default binding.
- if (Optional<SVal> V = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &V = getDefaultBinding(B, superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1300,7 +1303,7 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
// Lazily derive a value for the VarRegion.
@@ -1313,8 +1316,23 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
return ValMgr.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
- if (VD->isFileVarDecl())
+ if (VD->isFileVarDecl()) {
+ // Is 'VD' declared constant? If so, retrieve the constant value.
+ QualType CT = Ctx.getCanonicalType(T);
+ if (CT.isConstQualified()) {
+ const Expr *Init = VD->getInit();
+ // Do the null check first, as we want to call 'IgnoreParenCasts'.
+ if (Init)
+ if (const IntegerLiteral *IL =
+ dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
+ const nonloc::ConcreteInt &V = ValMgr.makeIntVal(IL);
+ return ValMgr.getSValuator().EvalCast(V, Init->getType(),
+ IL->getType());
+ }
+ }
+
return ValMgr.getRegionValueSymbolVal(R);
+ }
if (T->isIntegerType())
return ValMgr.makeIntVal(0, T);
@@ -1337,8 +1355,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
- assert(T->isStructureType());
- assert(T->getAsStructureType()->getDecl()->isDefinition());
+ assert(T->isStructureType() || T->isClassType());
return ValMgr.makeLazyCompoundVal(store, R);
}
@@ -1692,8 +1709,8 @@ public:
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
- void VisitRegion(const MemRegion *baseR);
+ void VisitBindingKey(BindingKey K);
bool UpdatePostponed();
void VisitBinding(SVal V);
};
@@ -1730,11 +1747,8 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
BindingKey *I, BindingKey *E) {
- for ( ; I != E; ++I) {
- const MemRegion *R = I->getRegion();
- if (R != baseR)
- VisitRegion(R);
- }
+ for ( ; I != E; ++I)
+ VisitBindingKey(*I);
}
void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
@@ -1762,34 +1776,36 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
SymReaper.markLive(*SI);
}
-void RemoveDeadBindingsWorker::VisitRegion(const MemRegion *R) {
+void RemoveDeadBindingsWorker::VisitBindingKey(BindingKey K) {
+ const MemRegion *R = K.getRegion();
+
// Mark this region "live" by adding it to the worklist. This will cause
// use to visit all regions in the cluster (if we haven't visited them
// already).
- AddToWorkList(R);
-
- // Mark the symbol for any live SymbolicRegion as "live". This means we
- // should continue to track that symbol.
- if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
- SymReaper.markLive(SymR->getSymbol());
+ if (AddToWorkList(R)) {
+ // Mark the symbol for any live SymbolicRegion as "live". This means we
+ // should continue to track that symbol.
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+ SymReaper.markLive(SymR->getSymbol());
+
+ // For BlockDataRegions, enqueue the VarRegions for variables marked
+ // with __block (passed-by-reference).
+ // via BlockDeclRefExprs.
+ if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
+ RI != RE; ++RI) {
+ if ((*RI)->getDecl()->getAttr<BlocksAttr>())
+ AddToWorkList(*RI);
+ }
- // For BlockDataRegions, enqueue the VarRegions for variables marked
- // with __block (passed-by-reference).
- // via BlockDeclRefExprs.
- if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
- for (BlockDataRegion::referenced_vars_iterator
- RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
- RI != RE; ++RI) {
- if ((*RI)->getDecl()->getAttr<BlocksAttr>())
- AddToWorkList(*RI);
+ // No possible data bindings on a BlockDataRegion.
+ return;
}
-
- // No possible data bindings on a BlockDataRegion.
- return;
}
- // Get the data binding for R (if any).
- if (Optional<SVal> V = RM.getBinding(B, R))
+ // Visit the data binding for K.
+ if (const SVal *V = RM.Lookup(B, K))
VisitBinding(*V);
}
diff --git a/lib/Checker/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp
index 949ded507c5b..14edf5668983 100644
--- a/lib/Checker/ReturnPointerRangeChecker.cpp
+++ b/lib/Checker/ReturnPointerRangeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp
index 9cbabba4a5f5..35b1cdebf620 100644
--- a/lib/Checker/ReturnStackAddressChecker.cpp
+++ b/lib/Checker/ReturnStackAddressChecker.cpp
@@ -14,8 +14,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/Checker/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp
index ee259883e48c..52a0b3076b6a 100644
--- a/lib/Checker/ReturnUndefChecker.cpp
+++ b/lib/Checker/ReturnUndefChecker.cpp
@@ -14,10 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp
index 65a46e31fefa..f3a803c57d32 100644
--- a/lib/Checker/SymbolManager.cpp
+++ b/lib/Checker/SymbolManager.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp
index e047b187b108..90883456b17c 100644
--- a/lib/Checker/UndefBranchChecker.cpp
+++ b/lib/Checker/UndefBranchChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp
index a8d7284b40ac..b1010c9c4892 100644
--- a/lib/Checker/UndefCapturedBlockVarChecker.cpp
+++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp
@@ -14,7 +14,7 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp
index fb2283a62044..8b07aed10e30 100644
--- a/lib/Checker/UndefResultChecker.cpp
+++ b/lib/Checker/UndefResultChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Checker/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp
index a2792ad17ba1..148629e0093f 100644
--- a/lib/Checker/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp
index 7c33c1d39235..6cef60eaee29 100644
--- a/lib/Checker/UndefinedAssignmentChecker.cpp
+++ b/lib/Checker/UndefinedAssignmentChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
@@ -53,27 +53,43 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
if (!N)
return;
+ const char *str = "Assigned value is garbage or undefined";
+
if (!BT)
- BT = new BuiltinBug("Assigned value is garbage or undefined");
+ BT = new BuiltinBug(str);
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ const Expr *ex = 0;
- if (AssignE) {
- const Expr *ex = 0;
+ while (AssignE) {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) {
+ if (B->isCompoundAssignmentOp()) {
+ const GRState *state = C.getState();
+ if (state->getSVal(B->getLHS()).isUndef()) {
+ str = "The left expression of the compound assignment is an "
+ "uninitialized value. The computed value will also be garbage";
+ ex = B->getLHS();
+ break;
+ }
+ }
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE))
ex = B->getRHS();
- else if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) {
+ break;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) {
const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
ex = VD->getInit();
}
- if (ex) {
- R->addRange(ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
- }
+
+ break;
}
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N);
+ if (ex) {
+ R->addRange(ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+ }
C.EmitReport(R);
-}
+}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index 7ff817ae7677..d75e5d25c49d 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -12,11 +12,10 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "llvm/ADT/StringSwitch.h"
-#include "GRExprEngineInternalChecks.h"
#include <fcntl.h>
using namespace clang;
diff --git a/lib/Checker/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp
index 51ad1e2daf5e..cea9d191aa77 100644
--- a/lib/Checker/VLASizeChecker.cpp
+++ b/lib/Checker/VLASizeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index c10a401d8abf..509734123b0c 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -17,6 +17,7 @@
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Target/TargetData.h"
#include <algorithm>
@@ -192,7 +193,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
CallArgList Args;
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args,
- CC_Default, false);
+ FunctionType::ExtInfo());
if (CGM.ReturnTypeUsesSret(FnInfo))
flags |= BLOCK_USE_STRET;
}
@@ -472,8 +473,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(),
- FuncTy->getNoReturnAttr());
+ CGM.getTypes().getFunctionInfo(ResultType, Args,
+ FuncTy->getExtInfo());
// Cast the function pointer to the right type.
const llvm::Type *BlockFTy =
@@ -678,8 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType;
- CallingConv CC = BlockFunctionType->getCallConv();
- bool NoReturn = BlockFunctionType->getNoReturnAttr();
+ FunctionType::ExtInfo EInfo = getFunctionExtInfo(*BlockFunctionType);
bool IsVariadic;
if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) {
@@ -718,7 +718,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
Args.push_back(std::make_pair(*i, (*i)->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, EInfo);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
@@ -843,7 +843,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -924,7 +924,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1008,7 +1008,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1071,7 +1071,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index e91319f6ddab..efee0e36b853 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -17,7 +17,6 @@
#include "CodeGenTypes.h"
#include "clang/AST/Type.h"
#include "llvm/Module.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 419ed734e83e..a9b0b645a4a6 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -81,10 +81,6 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1)) };
Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
-
- if (Id == Intrinsic::atomic_load_nand)
- Result = CGF.Builder.CreateNot(Result);
-
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
}
@@ -550,12 +546,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E);
- case Builtin::BI__sync_fetch_and_nand_1:
- case Builtin::BI__sync_fetch_and_nand_2:
- case Builtin::BI__sync_fetch_and_nand_4:
- case Builtin::BI__sync_fetch_and_nand_8:
- case Builtin::BI__sync_fetch_and_nand_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_nand, E);
// Clang extensions: not overloaded yet.
case Builtin::BI__sync_fetch_and_min:
@@ -602,13 +592,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_xor_and_fetch_16:
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E,
llvm::Instruction::Xor);
- case Builtin::BI__sync_nand_and_fetch_1:
- case Builtin::BI__sync_nand_and_fetch_2:
- case Builtin::BI__sync_nand_and_fetch_4:
- case Builtin::BI__sync_nand_and_fetch_8:
- case Builtin::BI__sync_nand_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_nand, E,
- llvm::Instruction::And);
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index b88001c81e9f..93a182f5cc47 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -297,311 +297,6 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
-llvm::Constant *
-CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const ThunkAdjustment &ThisAdjustment) {
- return GenerateCovariantThunk(Fn, GD, Extern,
- CovariantThunkAdjustment(ThisAdjustment,
- ThunkAdjustment()));
-}
-
-llvm::Value *
-CodeGenFunction::DynamicTypeAdjust(llvm::Value *V,
- const ThunkAdjustment &Adjustment) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-
- const llvm::Type *OrigTy = V->getType();
- if (Adjustment.NonVirtual) {
- // Do the non-virtual adjustment
- V = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual);
- V = Builder.CreateBitCast(V, OrigTy);
- }
-
- if (!Adjustment.Virtual)
- return V;
-
- assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 &&
- "vtable entry unaligned");
-
- // Do the virtual this adjustment
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
- const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo();
-
- llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo());
- V = Builder.CreateLoad(V, "vtable");
-
- llvm::Value *VTablePtr = V;
- uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8);
- V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
- V = Builder.CreateLoad(V);
- V = Builder.CreateGEP(ThisVal, V);
-
- return Builder.CreateBitCast(V, OrigTy);
-}
-
-llvm::Constant *
-CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
- GlobalDecl GD, bool Extern,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getResultType();
-
- FunctionArgList Args;
- ImplicitParamDecl *ThisDecl =
- ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
- MD->getThisType(getContext()));
- Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType()));
- for (FunctionDecl::param_const_iterator i = MD->param_begin(),
- e = MD->param_end();
- i != e; ++i) {
- ParmVarDecl *D = *i;
- Args.push_back(std::make_pair(D, D->getType()));
- }
- IdentifierInfo *II
- = &CGM.getContext().Idents.get("__thunk_named_foo_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
- SourceLocation(), II, ResultType, 0,
- Extern
- ? FunctionDecl::Extern
- : FunctionDecl::Static,
- false, true);
- StartFunction(FD, ResultType, Fn, Args, SourceLocation());
-
- // generate body
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
-
- CallArgList CallArgs;
-
- bool ShouldAdjustReturnPointer = true;
- QualType ArgType = MD->getThisType(getContext());
- llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this");
- if (!Adjustment.ThisAdjustment.isEmpty()) {
- // Do the this adjustment.
- const llvm::Type *OrigTy = Callee->getType();
- Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment);
-
- if (!Adjustment.ReturnAdjustment.isEmpty()) {
- const CovariantThunkAdjustment &ReturnAdjustment =
- CovariantThunkAdjustment(ThunkAdjustment(),
- Adjustment.ReturnAdjustment);
-
- Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment);
-
- Callee = Builder.CreateBitCast(Callee, OrigTy);
- ShouldAdjustReturnPointer = false;
- }
- }
-
- CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType));
-
- for (FunctionDecl::param_const_iterator i = MD->param_begin(),
- e = MD->param_end();
- i != e; ++i) {
- ParmVarDecl *D = *i;
- QualType ArgType = D->getType();
-
- // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst);
- Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(),
- SourceLocation());
- CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType));
- }
-
- RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
- FPT->getCallConv(),
- FPT->getNoReturnAttr()),
- Callee, ReturnValueSlot(), CallArgs, MD);
- if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
- bool CanBeZero = !(ResultType->isReferenceType()
- // FIXME: attr nonnull can't be zero either
- /* || ResultType->hasAttr<NonNullAttr>() */ );
- // Do the return result adjustment.
- if (CanBeZero) {
- llvm::BasicBlock *NonZeroBlock = createBasicBlock();
- llvm::BasicBlock *ZeroBlock = createBasicBlock();
- llvm::BasicBlock *ContBlock = createBasicBlock();
-
- const llvm::Type *Ty = RV.getScalarVal()->getType();
- llvm::Value *Zero = llvm::Constant::getNullValue(Ty);
- Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero),
- NonZeroBlock, ZeroBlock);
- EmitBlock(NonZeroBlock);
- llvm::Value *NZ =
- DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment);
- EmitBranch(ContBlock);
- EmitBlock(ZeroBlock);
- llvm::Value *Z = RV.getScalarVal();
- EmitBlock(ContBlock);
- llvm::PHINode *RVOrZero = Builder.CreatePHI(Ty);
- RVOrZero->reserveOperandSpace(2);
- RVOrZero->addIncoming(NZ, NonZeroBlock);
- RVOrZero->addIncoming(Z, ZeroBlock);
- RV = RValue::get(RVOrZero);
- } else
- RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(),
- Adjustment.ReturnAdjustment));
- }
-
- if (!ResultType->isVoidType())
- EmitReturnOfRValue(RV, ResultType);
-
- FinishFunction();
- return Fn;
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
- const ThunkAdjustment &ThisAdjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Compute mangled name
- llvm::SmallString<256> OutName;
- if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
- getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment,
- OutName);
- else
- getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
-
- // Get function for mangled name
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
- return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl());
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Compute mangled name
- llvm::SmallString<256> Name;
- getMangleContext().mangleCovariantThunk(MD, Adjustment, Name);
-
- // Get function for mangled name
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
-}
-
-void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
- CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD);
- if (!AdjPtr)
- return;
- CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr;
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- for (unsigned i = 0; i < Adj.size(); i++) {
- GlobalDecl OGD = Adj[i].first;
- const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl());
- QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType oret = getContext().getCanonicalType(nc_oret);
- QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType ret = getContext().getCanonicalType(nc_ret);
- ThunkAdjustment ReturnAdjustment;
- if (oret != ret) {
- QualType qD = nc_ret->getPointeeType();
- QualType qB = nc_oret->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- ReturnAdjustment = ComputeThunkAdjustment(D, B);
- }
- ThunkAdjustment ThisAdjustment = Adj[i].second;
- bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace();
- if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
- CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment);
- llvm::Constant *FnConst;
- if (!ReturnAdjustment.isEmpty())
- FnConst = GetAddrOfCovariantThunk(GD, CoAdj);
- else
- FnConst = GetAddrOfThunk(GD, ThisAdjustment);
- if (!isa<llvm::Function>(FnConst)) {
- llvm::Constant *SubExpr =
- cast<llvm::ConstantExpr>(FnConst)->getOperand(0);
- llvm::Function *OldFn = cast<llvm::Function>(SubExpr);
- llvm::Constant *NewFnConst;
- if (!ReturnAdjustment.isEmpty())
- NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj);
- else
- NewFnConst = GetAddrOfThunk(GD, ThisAdjustment);
- llvm::Function *NewFn = cast<llvm::Function>(NewFnConst);
- NewFn->takeName(OldFn);
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType());
- OldFn->replaceAllUsesWith(NewPtrForOldDecl);
- OldFn->eraseFromParent();
- FnConst = NewFn;
- }
- llvm::Function *Fn = cast<llvm::Function>(FnConst);
- if (Fn->isDeclaration()) {
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- Fn->setLinkage(linktype);
- if (!Features.Exceptions && !Features.ObjCNonFragileABI)
- Fn->addFnAttr(llvm::Attribute::NoUnwind);
- Fn->setAlignment(2);
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj);
- }
- }
- }
-}
-
-llvm::Constant *
-CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern,
- const ThunkAdjustment &ThisAdjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- llvm::SmallString<256> OutName;
- if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) {
- getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment,
- OutName);
- } else
- getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
-
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
- &getModule());
- CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
-llvm::Constant *
-CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- llvm::SmallString<256> OutName;
- getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
- &getModule());
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -618,17 +313,17 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD);
- return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+ return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- uint64_t VtableIndex =
- CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
+ uint64_t VTableIndex =
+ CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type));
- return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+ return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 072b1f6585fd..cb1ecc1aa616 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -67,8 +67,7 @@ const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
llvm::SmallVector<CanQualType, 16>(),
- FTNP->getCallConv(),
- FTNP->getNoReturnAttr());
+ FTNP->getExtInfo());
}
/// \param Args - contains any initial parameters besides those
@@ -81,8 +80,7 @@ static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
ArgTys.push_back(FTP->getArgType(i));
CanQualType ResTy = FTP->getResultType().getUnqualifiedType();
return CGT.getFunctionInfo(ResTy, ArgTys,
- FTP->getCallConv(),
- FTP->getNoReturnAttr());
+ FTP->getExtInfo());
}
const CGFunctionInfo &
@@ -175,8 +173,10 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
}
return getFunctionInfo(GetReturnType(MD->getResultType()),
ArgTys,
- getCallingConventionForDecl(MD),
- /*NoReturn*/ false);
+ FunctionType::ExtInfo(
+ /*NoReturn*/ false,
+ /*RegParm*/ 0,
+ getCallingConventionForDecl(MD)));
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@@ -194,43 +194,40 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- CallingConv CC,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
llvm::SmallVector<CanQualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->second));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn);
+ return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- CallingConv CC,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
llvm::SmallVector<CanQualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->second));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn);
+ return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
- CallingConv CallConv,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
#ifndef NDEBUG
for (llvm::SmallVectorImpl<CanQualType>::const_iterator
I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
assert(I->isCanonicalAsParam());
#endif
- unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
+ unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC());
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy,
+ CGFunctionInfo::Profile(ID, Info, ResTy,
ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
@@ -239,7 +236,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
+ FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information.
@@ -250,11 +247,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
bool _NoReturn,
+ unsigned _RegParm,
CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
- NoReturn(_NoReturn)
+ NoReturn(_NoReturn), RegParm(_RegParm)
{
NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs];
@@ -610,11 +608,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// FIXME: we need to honour command line settings also...
// FIXME: RegParm should be reduced in case of nested functions and/or global
// register variable.
- signed RegParm = 0;
- if (TargetDecl)
- if (const RegparmAttr *RegParmAttr
- = TargetDecl->getAttr<RegparmAttr>())
- RegParm = RegParmAttr->getNumParams();
+ signed RegParm = FI.getRegParm();
unsigned PointerWidth = getContext().Target.getPointerWidth(0);
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
@@ -623,8 +617,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const ABIArgInfo &AI = it->info;
unsigned Attributes = 0;
- if (ParamType.isRestrictQualified())
- Attributes |= llvm::Attribute::NoAlias;
+ // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
+ // have the corresponding parameter variable. It doesn't make
+ // sense to do it here because parameters are so fucked up.
switch (AI.getKind()) {
case ABIArgInfo::Coerce:
@@ -749,6 +744,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
V = CreateMemTemp(Ty);
Builder.CreateStore(AI, V);
} else {
+ if (Arg->getType().isRestrictQualified())
+ AI->addAttr(llvm::Attribute::NoAlias);
+
if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
// This must be a promotion, for something like
// "void a(x) short x; {..."
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 3d81165b1bf1..31c8aac3f241 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -76,12 +76,16 @@ namespace CodeGen {
unsigned NumArgs;
ArgInfo *Args;
+ /// How many arguments to pass inreg.
+ unsigned RegParm;
+
public:
typedef const ArgInfo *const_arg_iterator;
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention,
bool NoReturn,
+ unsigned RegParm,
CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -108,6 +112,8 @@ namespace CodeGen {
EffectiveCallingConvention = Value;
}
+ unsigned getRegParm() const { return RegParm; }
+
CanQualType getReturnType() const { return Args[0].type; }
ABIArgInfo &getReturnInfo() { return Args[0].info; }
@@ -116,19 +122,20 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
+ ID.AddInteger(RegParm);
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
}
template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
- unsigned CallingConvention,
- bool NoReturn,
+ const FunctionType::ExtInfo &Info,
CanQualType ResTy,
Iterator begin,
Iterator end) {
- ID.AddInteger(CallingConvention);
- ID.AddBoolean(NoReturn);
+ ID.AddInteger(Info.getCC());
+ ID.AddBoolean(Info.getNoReturn());
+ ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);
for (; begin != end; ++begin) {
CanQualType T = *begin; // force iterator to be over canonical types
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 525e85841646..177e86230477 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -69,42 +69,6 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-// FIXME: This probably belongs in CGVtable, but it relies on
-// the static function ComputeNonVirtualBaseClassOffset, so we should make that
-// a CodeGenModule member function as well.
-ThunkAdjustment
-CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return ThunkAdjustment();
- }
-
- unsigned Start = 0;
- uint64_t VirtualOffset = 0;
-
- const CXXBasePath &Path = Paths.front();
- const CXXRecordDecl *VBase = 0;
- for (unsigned i = 0, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
- if (Element.Base->isVirtual()) {
- Start = i+1;
- QualType VBaseType = Element.Base->getType();
- VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
- }
- if (VBase)
- VirtualOffset =
- getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
-
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
- return ThunkAdjustment(Offset, VirtualOffset);
-}
-
/// Gets the address of a virtual base class within a complete object.
/// This should only be used for (1) non-virtual bases or (2) virtual bases
/// when the type is known to be complete (e.g. in complete destructors).
@@ -139,7 +103,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
return V;
-}
+}
llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
@@ -308,6 +272,53 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return 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);
+
+ 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()));
+
+
+ {
+ CodeGenFunction::CXXTemporariesCleanupScope Scope(CGF);
+
+ // If the copy constructor has default arguments, emit them.
+ for (unsigned I = 1, E = CopyCtor->getNumParams(); I < E; ++I) {
+ const ParmVarDecl *Param = CopyCtor->getParamDecl(I);
+ const Expr *DefaultArgExpr = Param->getDefaultArg();
+
+ assert(DefaultArgExpr && "Ctor parameter must have default arg!");
+
+ QualType ArgType = Param->getType();
+ CallArgs.push_back(std::make_pair(CGF.EmitCallArg(DefaultArgExpr,
+ ArgType),
+ ArgType));
+ }
+
+ const FunctionProtoType *FPT =
+ CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
+ Callee, ReturnValueSlot(), CallArgs, CopyCtor);
+ }
+}
+
/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
/// copy or via a copy constructor call.
@@ -354,22 +365,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
if (BitwiseCopy)
EmitAggregateCopy(Dest, Src, Ty);
else if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
+ BaseClassDecl->getCopyConstructor(getContext(), 0))
+ EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src);
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT
- = BaseCopyCtor->getType()->getAs<FunctionProtoType>();
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
- }
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -471,7 +469,7 @@ 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) {
- if (!CGVtableInfo::needsVTTParameter(GD)) {
+ if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
}
@@ -486,21 +484,21 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
// If the record matches the base, this is the complete ctor/dtor
// variant calling the base variant in a class with virtual bases.
if (RD == Base) {
- assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) &&
+ assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
SubVTTIndex = 0;
} else {
- SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+ SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base);
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
- if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
// A VTT parameter was passed to the constructor, use it.
VTT = CGF.LoadCXXVTT();
VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
} else {
// We're the complete constructor, so get the VTT by name.
- VTT = CGF.CGM.getVtableInfo().getVTT(RD);
+ VTT = CGF.CGM.getVTables().getVTT(RD);
VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
}
@@ -531,29 +529,13 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
return;
}
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
-
- // Push the VTT parameter, if necessary.
- if (llvm::Value *VTT =
- GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
- }
+ CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0);
+ if (!BaseCopyCtor)
+ return;
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT =
- BaseCopyCtor->getType()->getAs<FunctionProtoType>();
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
- }
+ 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
@@ -690,7 +672,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
}
}
- InitializeVtablePtrs(ClassDecl);
+ InitializeVTablePointers(ClassDecl);
}
/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
@@ -1010,7 +992,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
MemberInitializers.push_back(Member);
}
- InitializeVtablePtrs(ClassDecl);
+ InitializeVTablePointers(ClassDecl);
for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) {
assert(LiveTemporaries.empty() &&
@@ -1060,7 +1042,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// Otherwise, we're in the base variant, so we need to ensure the
// vtable ptrs are right before emitting the body.
} else {
- InitializeVtablePtrs(Dtor->getParent());
+ InitializeVTablePointers(Dtor->getParent());
}
// Emit the body of the statement.
@@ -1286,14 +1268,12 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
// before the construction of the next array element, if any.
// Keep track of the current number of live temporaries.
- unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+ {
+ CXXTemporariesCleanupScope Scope(*this);
- EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ }
- // Pop temporaries.
- while (LiveTemporaries.size() > OldNumLiveTemporaries)
- PopCXXTemporary();
-
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -1399,7 +1379,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy;
const CGFunctionInfo &FI
- = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ = CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
@@ -1474,7 +1454,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
- if (CGVtableInfo::needsVTTParameter(CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CurGD)) {
assert(I != E && "cannot skip vtt parameter, already done with args");
assert(I->second == VoidPP && "skipping parameter not of vtt type");
++I;
@@ -1541,7 +1521,7 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
int64_t VBaseOffsetOffset =
- CGM.getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
+ CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
llvm::Value *VBaseOffsetPtr =
Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr");
@@ -1556,69 +1536,126 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
-void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->isDynamicClass())
- return;
+void
+CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // Compute the address point.
+ llvm::Value *VTableAddressPoint;
+
+ // Check if we need to use a vtable from the VTT.
+ if (CodeGenVTables::needsVTTParameter(CurGD) &&
+ (RD->getNumVBases() || BaseIsMorallyVirtual)) {
+ // Get the secondary vpointer index.
+ uint64_t VirtualPointerIndex =
+ CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
+
+ /// Load the VTT.
+ llvm::Value *VTT = LoadCXXVTT();
+ if (VirtualPointerIndex)
+ VTT = Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
- llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
- CGVtableInfo::AddrSubMap_t& AddressPoints =
- *(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl];
- llvm::Value *ThisPtr = LoadCXXThis();
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+ // And load the address point from the VTT.
+ VTableAddressPoint = Builder.CreateLoad(VTT);
+ } else {
+ uint64_t AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ VTableAddressPoint =
+ Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
+ }
- // Store address points for virtual bases
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, Offset);
+ // Compute where to store the address point.
+ llvm::Value *VTableField;
+
+ if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) {
+ // 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);
+ } else {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+
+ VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy);
+ VTableField =
+ Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8);
}
- // Store address points for non-virtual bases and current class
- InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
+ // Finally, store the address point.
+ const llvm::Type *AddressPointPtrTy =
+ VTableAddressPoint->getType()->getPointerTo();
+ VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy);
+ Builder.CreateStore(VTableAddressPoint, VTableField);
}
-void CodeGenFunction::InitializeVtablePtrsRecursive(
- const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CGVtableInfo::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset) {
- if (!ClassDecl->isDynamicClass())
- return;
+void
+CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsNonVirtualPrimaryBase,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy& VBases) {
+ // If this base is a non-virtual primary base the address point has already
+ // been set.
+ if (!BaseIsNonVirtualPrimaryBase) {
+ // Initialize the vtable pointer for this base.
+ InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass);
+ }
+
+ const CXXRecordDecl *RD = Base.getBase();
- // Store address points for non-virtual bases
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- if (Base.isVirtual())
+ // Traverse bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore classes without a vtable.
+ if (!BaseDecl->isDynamicClass())
continue;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, NewOffset);
+
+ uint64_t BaseOffset;
+ bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ bool BaseDeclIsNonVirtualPrimaryBase;
+
+ if (I->isVirtual()) {
+ // Check if we've visited this virtual base before.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(VTableClass);
+
+ BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
+ BaseDeclIsMorallyVirtual = true;
+ BaseDeclIsNonVirtualPrimaryBase = false;
+ } else {
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+
+ BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+ BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
+ }
+
+ InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
+ BaseDeclIsMorallyVirtual,
+ BaseDeclIsNonVirtualPrimaryBase,
+ VTable, VTableClass, VBases);
}
+}
- // Compute the address point
- assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
- "Missing address point for class");
- uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
- llvm::Value *VtableAddressPoint =
- Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
-
- // Compute the address to store the address point
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
- VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
- const llvm::Type *AddressPointPtrTy =
- VtableAddressPoint->getType()->getPointerTo();
- VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
+void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
+ // Ignore classes without a vtable.
+ if (!RD->isDynamicClass())
+ return;
+
+ // Get the VTable.
+ llvm::Constant *VTable = CGM.getVTables().GetAddrOfVTable(RD);
- // Store address point
- Builder.CreateStore(VtableAddressPoint, VtableField);
+ // Initialize the vtable pointers for this class and all of its bases.
+ VisitedVirtualBasesSetTy VBases;
+ InitializeVTablePointers(BaseSubobject(RD, 0),
+ /*BaseIsMorallyVirtual=*/false,
+ /*BaseIsNonVirtualPrimaryBase=*/false,
+ VTable, RD, VBases);
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index ad97d08a2bf7..58acd3c2e172 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -88,17 +88,35 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
/// getOrCreateFile - Get the file debug info descriptor for the input location.
llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
- if (!Loc.isValid())
+ if (!Loc.isValid())
// If Location is not valid then use main input file.
return DebugFactory.CreateFile(TheCU.getFilename(), TheCU.getDirectory(),
TheCU);
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // Cache the results.
+ const char *fname = PLoc.getFilename();
+ llvm::DenseMap<const char *, llvm::WeakVH>::iterator it =
+ DIFileCache.find(fname);
+
+ if (it != DIFileCache.end()) {
+ // Verify that the information still exists.
+ if (&*it->second)
+ return llvm::DIFile(cast<llvm::MDNode>(it->second));
+ }
+
+ // FIXME: We shouldn't even need to call 'makeAbsolute()' in the cases
+ // where we can consult the FileEntry.
llvm::sys::Path AbsFileName(PLoc.getFilename());
AbsFileName.makeAbsolute();
- return DebugFactory.CreateFile(AbsFileName.getLast(),
- AbsFileName.getDirname(), TheCU);
+ llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(),
+ AbsFileName.getDirname(), TheCU);
+
+ DIFileCache[fname] = F.getNode();
+ return F;
+
}
/// CreateCompileUnit - Create new compile unit.
void CGDebugInfo::CreateCompileUnit() {
@@ -112,6 +130,10 @@ void CGDebugInfo::CreateCompileUnit() {
llvm::sys::Path AbsFileName(MainFileName);
AbsFileName.makeAbsolute();
+ // The main file name provided via the "-main-file-name" option contains just
+ // the file name itself with no path information. This file name may have had
+ // a relative path, so we look into the actual file entry for the main
+ // file to determine the real absolute path for the file.
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
MainFileDir = MainFile->getDir()->getName();
@@ -604,7 +626,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.getVtableInfo().getMethodVtableIndex(Method);
+ VIndex = CGM.getVTables().getMethodVtableIndex(Method);
ContainingType = RecordTy;
}
@@ -662,7 +684,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
if (BI->isVirtual()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
- BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, Base);
+ BaseOffset = 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base);
BFlags = llvm::DIType::FlagVirtual;
} else
BaseOffset = RL.getBaseClassOffset(Base);
@@ -692,10 +714,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
ASTContext &Context = CGM.getContext();
/* Function type */
- llvm::SmallVector<llvm::DIDescriptor, 16> STys;
- STys.push_back(getOrCreateType(Context.IntTy, Unit));
- llvm::DIArray SElements =
- DebugFactory.GetOrCreateArray(STys.data(), STys.size());
+ llvm::DIDescriptor STy = getOrCreateType(Context.IntTy, Unit);
+ llvm::DIArray SElements = DebugFactory.GetOrCreateArray(&STy, 1);
llvm::DIType SubTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
Unit, "", Unit,
@@ -1048,11 +1068,9 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty,
uint64_t NumElems = Ty->getNumElements();
if (NumElems > 0)
--NumElems;
- llvm::SmallVector<llvm::DIDescriptor, 8> Subscripts;
- Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, NumElems));
- llvm::DIArray SubscriptArray =
- DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size());
+ llvm::DIDescriptor Subscript = DebugFactory.GetOrCreateSubrange(0, NumElems);
+ llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(&Subscript, 1);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
@@ -1208,7 +1226,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
Ty = UnwrapTypeForDebugInfo(Ty);
// Check for existing entry.
- std::map<void *, llvm::WeakVH>::iterator it =
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
// Verify that the debug info still exists.
@@ -1371,13 +1389,10 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
llvm::DIFile Unit = getOrCreateFile(CurLoc);
PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
- llvm::DIDescriptor DR(RegionStack.back());
- llvm::DIScope DS = llvm::DIScope(DR.getNode());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL =
- DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(),
- DS, DO);
- Builder.SetCurrentDebugLocation(DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Builder.SetCurrentDebugLocation(llvm::NewDebugLoc::get(PLoc.getLine(),
+ PLoc.getColumn(),
+ Scope));
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
@@ -1580,11 +1595,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Instruction *Call =
DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
- llvm::DIScope DS(RegionStack.back());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL = DebugFactory.CreateLocation(Line, Column, DS, DO);
-
- Call->setMetadata("dbg", DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Call->setDebugLoc(llvm::NewDebugLoc::get(Line, Column, Scope));
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1646,13 +1658,9 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
-
- llvm::DIScope DS(RegionStack.back());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL =
- DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO);
- Call->setMetadata("dbg", DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Call->setDebugLoc(llvm::NewDebugLoc::get(Line, PLoc.getColumn(), Scope));
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 47a462048342..8397245e3184 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -21,7 +21,6 @@
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/Allocator.h"
-#include <map>
#include "CGBuilder.h"
@@ -52,8 +51,7 @@ class CGDebugInfo {
unsigned FwdDeclCount;
/// TypeCache - Cache of previously constructed Types.
- // FIXME: Eliminate this map. Be careful of iterator invalidation.
- std::map<void *, llvm::WeakVH> TypeCache;
+ llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
@@ -65,6 +63,7 @@ class CGDebugInfo {
/// constructed on demand. For example, C++ destructors, C++ operators etc..
llvm::BumpPtrAllocator DebugInfoNames;
+ llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index dc9ecd64f4e4..87ec159a6010 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGCall.h"
+#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -1468,7 +1469,9 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
const FieldDecl* Field,
unsigned CVRQualifiers) {
- CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field);
// FIXME: CodeGenTypes should expose a method to get the appropriate type for
// FieldTy (the appropriate type is ABI-dependent).
@@ -1496,7 +1499,9 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
if (Field->isBitField())
return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ unsigned idx = RL.getLLVMFieldNo(Field);
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
// Match union field type.
@@ -1531,7 +1536,9 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue,
if (!FieldType->isReferenceType())
return EmitLValueForField(BaseValue, Field, CVRQualifiers);
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ unsigned idx = RL.getLLVMFieldNo(Field);
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
@@ -1637,6 +1644,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CastExpr::CK_AnyPointerToObjCPointerCast:
return EmitLValue(E->getSubExpr());
+ case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
@@ -1872,7 +1880,6 @@ LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) {
LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
// Can only get l-value for message expression returning aggregate type
RValue RV = EmitAnyExprToTemp(E);
- // FIXME: can this be volatile?
return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 4847ca3f8248..e2e2cd050419 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -333,8 +333,7 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
llvm::Value *FuncPtr;
if (MD->isVirtual()) {
- int64_t Index =
- CGF.CGM.getVtableInfo().getMethodVtableIndex(MD);
+ int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD);
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
@@ -500,10 +499,6 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
llvm::Value *Val = DestPtr;
- if (!Val) {
- // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
- }
CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 032862160464..d9585c9c6d20 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -44,9 +44,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
QualType ResultType = FPT->getResultType();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- FPT->getCallConv(),
- FPT->getNoReturnAttr()), Callee,
- ReturnValue, Args, MD);
+ FPT->getExtInfo()),
+ Callee, ReturnValue, Args, MD);
}
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
@@ -411,7 +410,8 @@ static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
return CalculateCookiePadding(Ctx, E->getAllocatedType());
}
-static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
+static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
+ CodeGenFunction &CGF,
const CXXNewExpr *E,
llvm::Value *& NumElements) {
QualType Type = E->getAllocatedType();
@@ -432,6 +432,15 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
NumElements =
llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
+ while (const ArrayType *AType = Context.getAsArrayType(Type)) {
+ const llvm::ArrayType *llvmAType =
+ cast<llvm::ArrayType>(CGF.ConvertType(Type));
+ NumElements =
+ CGF.Builder.CreateMul(NumElements,
+ llvm::ConstantInt::get(
+ SizeTy, llvmAType->getNumElements()));
+ Type = AType->getElementType();
+ }
return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity());
}
@@ -444,6 +453,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
CGF.Builder.CreateMul(NumElements,
llvm::ConstantInt::get(SizeTy,
TypeSize.getQuantity()));
+
+ while (const ArrayType *AType = Context.getAsArrayType(Type)) {
+ const llvm::ArrayType *llvmAType =
+ cast<llvm::ArrayType>(CGF.ConvertType(Type));
+ NumElements =
+ CGF.Builder.CreateMul(NumElements,
+ llvm::ConstantInt::get(
+ SizeTy, llvmAType->getNumElements()));
+ Type = AType->getElementType();
+ }
// And add the cookie padding if necessary.
if (!CookiePadding.isZero())
@@ -504,7 +523,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
QualType SizeTy = getContext().getSizeType();
llvm::Value *NumElements = 0;
- llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements);
+ llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(),
+ *this, E, NumElements);
NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
@@ -590,10 +610,20 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
CookiePadding.getQuantity());
}
- NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
-
- EmitNewInitializer(*this, E, NewPtr, NumElements);
-
+ if (AllocType->isArrayType()) {
+ while (const ArrayType *AType = getContext().getAsArrayType(AllocType))
+ AllocType = AType->getElementType();
+ NewPtr =
+ Builder.CreateBitCast(NewPtr,
+ ConvertType(getContext().getPointerType(AllocType)));
+ EmitNewInitializer(*this, E, NewPtr, NumElements);
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+ }
+ else {
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+ EmitNewInitializer(*this, E, NewPtr, NumElements);
+ }
+
if (NullCheckResult) {
Builder.CreateBr(NewEnd);
NewNotNull = Builder.GetInsertBlock();
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 591534042f51..0a0c9149b41b 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -522,13 +522,21 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
// scalar.
OpInfo.Ty = E->getComputationResultType();
OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
-
+
LValue LHSLV = CGF.EmitLValue(E->getLHS());
-
-
// We know the LHS is a complex lvalue.
- OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
- OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
+ ComplexPairTy LHSComplexPair;
+ if (LHSLV.isPropertyRef())
+ LHSComplexPair =
+ CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal();
+ else if (LHSLV.isKVCRef())
+ LHSComplexPair =
+ CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal();
+ else
+ LHSComplexPair = EmitLoadOfComplex(LHSLV.getAddress(),
+ LHSLV.isVolatileQualified());
+
+ OpInfo.LHS=EmitComplexToComplexCast(LHSComplexPair, LHSTy, OpInfo.Ty);
// Expand the binary operator.
ComplexPairTy Result = (this->*Func)(OpInfo);
@@ -537,12 +545,22 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
// Store the result value into the LHS lvalue.
- EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
+ if (LHSLV.isPropertyRef())
+ CGF.EmitObjCPropertySet(LHSLV.getPropertyRefExpr(),
+ RValue::getComplex(Result));
+ else if (LHSLV.isKVCRef())
+ CGF.EmitObjCPropertySet(LHSLV.getKVCRefExpr(), RValue::getComplex(Result));
+ else
+ EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
// And now return the LHS
IgnoreReal = ignreal;
IgnoreImag = ignimag;
IgnoreRealAssign = ignreal;
IgnoreImagAssign = ignimag;
+ if (LHSLV.isPropertyRef())
+ return CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal();
+ else if (LHSLV.isKVCRef())
+ return CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal();
return EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index f0d82a8f0dc6..172a77d78e5f 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
@@ -417,7 +418,7 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD);
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
@@ -1011,7 +1012,9 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
E = RD->field_end(); I != E; ++I) {
const FieldDecl *FD = *I;
- unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ const CGRecordLayout &RL =
+ getTypes().getCGRecordLayout(FD->getParent());
+ unsigned FieldNo = RL.getLLVMFieldNo(FD);
Elements[FieldNo] = EmitNullConstant(FD->getType());
}
@@ -1047,7 +1050,9 @@ CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) {
const llvm::StructType *ClassLTy =
cast<llvm::StructType>(getTypes().ConvertType(ClassType));
- unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ const CGRecordLayout &RL =
+ getTypes().getCGRecordLayout(FD->getParent());
+ unsigned FieldNo = RL.getLLVMFieldNo(FD);
uint64_t Offset =
getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 7e26971414b4..42bf68ed52ce 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -769,6 +769,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
const Expr *E = CE->getSubExpr();
+
+ if (CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase)
+ return false;
if (isa<CXXThisExpr>(E)) {
// We always assume that 'this' is never null.
@@ -826,6 +829,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
NullCheckValue);
}
+ case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -1337,6 +1341,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub");
+
+ // Signed integer overflow is undefined behavior.
+ if (Ops.Ty->isSignedIntegerType())
+ return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub");
+
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 3ff77f0170c1..9eaf57c445ed 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -191,7 +191,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
- CC_Default, false),
+ FunctionType::ExtInfo()),
GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
@@ -201,7 +201,12 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
EmitReturnOfRValue(RV, PD->getType());
} else {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
- if (hasAggregateLLVMType(Ivar->getType())) {
+ if (Ivar->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(),
+ LV.isVolatileQualified());
+ StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
+ }
+ else if (hasAggregateLLVMType(Ivar->getType())) {
EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
} else {
CodeGenTypes &Types = CGM.getTypes();
@@ -280,7 +285,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- CC_Default, false), SetPropertyFn,
+ FunctionType::ExtInfo()),
+ SetPropertyFn,
ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
@@ -459,12 +465,13 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
static const unsigned NumItems = 16;
// Get selector
- llvm::SmallVector<IdentifierInfo*, 3> II;
- II.push_back(&CGM.getContext().Idents.get("countByEnumeratingWithState"));
- II.push_back(&CGM.getContext().Idents.get("objects"));
- II.push_back(&CGM.getContext().Idents.get("count"));
- Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(),
- &II[0]);
+ IdentifierInfo *II[] = {
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
+ };
+ Selector FastEnumSel =
+ CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]);
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
@@ -555,7 +562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
- CC_Default, false),
+ FunctionType::ExtInfo()),
EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 119819b810be..d4452000dc04 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -465,7 +465,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -573,7 +573,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -1694,7 +1694,7 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
Params.push_back(ASTIdTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 475280b6a01e..883ed98511e7 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -13,6 +13,7 @@
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
@@ -306,7 +307,8 @@ public:
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -325,7 +327,8 @@ public:
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -337,7 +340,8 @@ public:
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -1559,7 +1563,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -3131,8 +3135,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()) {
- CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+ const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field);
const llvm::Type *Ty =
CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
@@ -3141,7 +3147,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
FieldOffset = Info.FieldNo * TypeSize;
} else
FieldOffset =
- Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field));
+ Layout->getElementOffset(RL.getLLVMFieldNo(Field));
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
@@ -5094,7 +5100,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
// FIXME. This is too much work to get the ABI-specific result type needed to
// find the message name.
const CGFunctionInfo &FnInfo
- = Types.getFunctionInfo(ResultType, CallArgList(), CC_Default, false);
+ = Types.getFunctionInfo(ResultType, CallArgList(),
+ FunctionType::ExtInfo());
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) {
@@ -5169,7 +5176,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
ObjCTypes.MessageRefCPtrTy));
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee);
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index ff5d40bfbc87..b781940ffad5 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -16,7 +16,6 @@
#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
#define CLANG_CODEGEN_OBCJRUNTIME_H
#include "clang/Basic/IdentifierTable.h" // Selector
-#include "llvm/ADT/SmallVector.h"
#include "clang/AST/DeclObjC.h"
#include <string>
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 4907223fe346..1caec97fc367 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -148,7 +148,7 @@ public:
};
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
- llvm::Constant *BuildTypeInfo(QualType Ty);
+ llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -327,83 +327,20 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
if (ContainsIncompleteClassType(Ty))
return llvm::GlobalValue::InternalLinkage;
- switch (Ty->getTypeClass()) {
- default:
- // FIXME: We need to add code to handle all types.
- assert(false && "Unhandled type!");
- break;
-
- case Type::Pointer: {
- const PointerType *PointerTy = cast<PointerType>(Ty);
-
- // If the pointee type has internal linkage, then the pointer type needs to
- // have it as well.
- if (getTypeInfoLinkage(PointerTy->getPointeeType()) ==
- llvm::GlobalVariable::InternalLinkage)
- return llvm::GlobalVariable::InternalLinkage;
-
- return llvm::GlobalVariable::WeakODRLinkage;
- }
-
- case Type::Enum: {
- const EnumType *EnumTy = cast<EnumType>(Ty);
- const EnumDecl *ED = EnumTy->getDecl();
-
- // If we're in an anonymous namespace, then we always want internal linkage.
- if (ED->isInAnonymousNamespace() || !ED->hasLinkage())
- return llvm::GlobalVariable::InternalLinkage;
-
- return llvm::GlobalValue::WeakODRLinkage;
- }
-
- case Type::Record: {
- const RecordType *RecordTy = cast<RecordType>(Ty);
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
-
- // If we're in an anonymous namespace, then we always want internal linkage.
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
- return llvm::GlobalVariable::InternalLinkage;
-
- // If this class does not have a vtable, we want weak linkage.
- if (!RD->isDynamicClass())
- return llvm::GlobalValue::WeakODRLinkage;
-
- return CodeGenModule::getVtableLinkage(RD);
- }
-
- case Type::Vector:
- case Type::ExtVector:
- case Type::Builtin:
- return llvm::GlobalValue::WeakODRLinkage;
-
- case Type::FunctionProto: {
- const FunctionProtoType *FPT = cast<FunctionProtoType>(Ty);
+ switch (Ty->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return llvm::GlobalValue::InternalLinkage;
- // Check the return type.
- if (getTypeInfoLinkage(FPT->getResultType()) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
-
- // Check the parameter types.
- for (unsigned i = 0; i != FPT->getNumArgs(); ++i) {
- if (getTypeInfoLinkage(FPT->getArgType(i)) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
+ case ExternalLinkage:
+ if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (RD->isDynamicClass())
+ return CodeGenModule::getVtableLinkage(RD);
}
-
- return llvm::GlobalValue::WeakODRLinkage;
- }
-
- case Type::ConstantArray:
- case Type::IncompleteArray: {
- const ArrayType *AT = cast<ArrayType>(Ty);
-
- // Check the element type.
- if (getTypeInfoLinkage(AT->getElementType()) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
- }
+ return llvm::GlobalValue::WeakODRLinkage;
}
return llvm::GlobalValue::WeakODRLinkage;
@@ -444,6 +381,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
switch (Ty->getTypeClass()) {
default: assert(0 && "Unhandled type!");
+ case Type::Builtin:
// GCC treats vector types as fundamental types.
case Type::Vector:
case Type::ExtVector:
@@ -511,7 +449,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
Fields.push_back(Vtable);
}
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -525,7 +463,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
// Check if there is already an external RTTI descriptor for this type.
- if (ShouldUseExternalRTTIDescriptor(Ty))
+ if (!Force && ShouldUseExternalRTTIDescriptor(Ty))
return GetAddrOfExternalRTTIDescriptor(Ty);
llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
@@ -538,11 +476,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
switch (Ty->getTypeClass()) {
default: assert(false && "Unhandled type class!");
- case Type::Builtin:
- assert(false && "Builtin type info must be in the standard library!");
- break;
// GCC treats vector types as fundamental types.
+ case Type::Builtin:
case Type::Vector:
case Type::ExtVector:
// Itanium C++ ABI 2.9.5p4:
@@ -760,7 +696,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// subobject. For a virtual base, this is the offset in the virtual table of
// the virtual base offset for the virtual base referenced (negative).
if (Base->isVirtual())
- OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ OffsetFlags = CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8;
@@ -854,3 +790,61 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
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;
+}
+
+void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
+ QualType PointerType = Context.getPointerType(Type);
+ QualType PointerTypeConst = Context.getPointerType(Type.withConst());
+ RTTIBuilder(*this).BuildTypeInfo(Type, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
+}
+
+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,
+ Context.UnsignedShortTy, Context.ShortTy,
+ Context.UnsignedLongTy, Context.LongTy,
+ Context.UnsignedIntTy, Context.IntTy,
+ Context.UnsignedCharTy, Context.FloatTy,
+ Context.LongDoubleTy, Context.DoubleTy,
+ Context.CharTy, Context.BoolTy,
+ Context.SignedCharTy };
+ for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i)
+ EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
+}
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
new file mode 100644
index 000000000000..d0d8f984a9ef
--- /dev/null
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -0,0 +1,95 @@
+//===--- CGRecordLayout.h - LLVM Record Layout Information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H
+#define CLANG_CODEGEN_CGRECORDLAYOUT_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+namespace llvm {
+ class Type;
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// CGRecordLayout - This class handles struct and union layout info while
+/// lowering AST types to LLVM types.
+///
+/// These layout objects are only created on demand as IR generation requires.
+class CGRecordLayout {
+ friend class CodeGenTypes;
+
+ CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT
+ void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
+
+public:
+ struct BitFieldInfo {
+ BitFieldInfo(unsigned FieldNo,
+ unsigned Start,
+ unsigned Size)
+ : FieldNo(FieldNo), Start(Start), Size(Size) {}
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
+ };
+
+private:
+ /// The LLVMType corresponding to this record layout.
+ const llvm::Type *LLVMType;
+
+ /// Map from (non-bit-field) struct field to the corresponding llvm struct
+ /// type field no. This info is populated by record builder.
+ llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
+
+ /// Map from (bit-field) struct field to the corresponding llvm struct type
+ /// field no. This info is populated by record builder.
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields;
+
+ /// Whether one of the fields in this record layout is a pointer to data
+ /// member, or a struct that contains pointer to data member.
+ bool ContainsPointerToDataMember : 1;
+
+public:
+ CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
+ : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) {}
+
+ /// \brief Return the LLVM type associated with this record.
+ const llvm::Type *getLLVMType() const {
+ return LLVMType;
+ }
+
+ /// \brief Check whether this struct contains pointers to data members.
+ bool containsPointerToDataMember() const {
+ return ContainsPointerToDataMember;
+ }
+
+ /// \brief Return the BitFieldInfo 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.
+ const BitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
+ assert(FD->isBitField() && "Invalid call for non bit-field decl!");
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo>::const_iterator
+ it = BitFields.find(FD);
+ assert(it != BitFields.end() && "Unable to find bitfield info");
+ return it->second;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index baafd6836c63..daebabddc61f 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -1,4 +1,4 @@
-//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===//
+//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,25 +7,131 @@
//
//===----------------------------------------------------------------------===//
//
-// This is a helper class used to build CGRecordLayout objects and LLVM types.
+// Builder implementation for CGRecordLayout objects.
//
//===----------------------------------------------------------------------===//
-#include "CGRecordLayoutBuilder.h"
-
+#include "CGRecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "CodeGenTypes.h"
+#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"
-
-
using namespace clang;
using namespace CodeGen;
+namespace clang {
+namespace CodeGen {
+
+class CGRecordLayoutBuilder {
+public:
+ /// FieldTypes - Holds the LLVM types that the struct is created from.
+ std::vector<const llvm::Type *> FieldTypes;
+
+ /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
+ typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
+ llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
+
+ /// LLVMBitFieldInfo - Holds location and size information about a bit field.
+ struct LLVMBitFieldInfo {
+ LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start,
+ unsigned Size)
+ : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { }
+
+ const FieldDecl *FD;
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
+ };
+ llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
+
+ /// Packed - Whether the resulting LLVM struct will be packed or not.
+ bool Packed;
+
+private:
+ CodeGenTypes &Types;
+
+ /// Alignment - Contains the alignment of the RecordDecl.
+ //
+ // FIXME: This is not needed and should be removed.
+ unsigned Alignment;
+
+ /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
+ /// LLVM types.
+ unsigned AlignmentAsLLVMStruct;
+
+ /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
+ /// this will have the number of bits still available in the field.
+ char BitsAvailableInLastField;
+
+ /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
+ uint64_t NextFieldOffsetInBytes;
+
+ /// LayoutUnion - Will layout a union RecordDecl.
+ void LayoutUnion(const RecordDecl *D);
+
+ /// LayoutField - try to layout all fields in the record decl.
+ /// Returns false if the operation failed because the struct is not packed.
+ bool LayoutFields(const RecordDecl *D);
+
+ /// LayoutBases - layout the bases and vtable pointer of a record decl.
+ void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
+
+ /// LayoutField - layout a single field. Returns false if the operation failed
+ /// because the current struct is not packed.
+ bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// LayoutBitField - layout a single bit field.
+ void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// 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);
+
+ /// AppendBytes - Append a given number of bytes to the record.
+ void AppendBytes(uint64_t NumBytes);
+
+ /// AppendTailPadding - Append enough tail padding so that the type will have
+ /// the passed size.
+ 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.
+ void CheckForPointerToDataMember(QualType T);
+
+public:
+ CGRecordLayoutBuilder(CodeGenTypes &Types)
+ : ContainsPointerToDataMember(false), Packed(false), Types(Types),
+ Alignment(0), AlignmentAsLLVMStruct(1),
+ BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
+
+ /// Layout - Will layout a RecordDecl.
+ void Layout(const RecordDecl *D);
+};
+
+}
+}
+
void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
Packed = D->hasAttr<PackedAttr>();
@@ -110,7 +216,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// Check if we have a pointer to data member in this field.
CheckForPointerToDataMember(D->getType());
-
+
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
uint64_t FieldOffsetInBytes = FieldOffset / 8;
@@ -166,7 +272,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
unsigned Align = 0;
bool HasOnlyZeroSizedBitFields = true;
-
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -182,12 +288,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
continue;
// Add the bit field info.
- Types.addBitFieldInfo(*Field, 0, 0, FieldSize);
- } else
- Types.addFieldInfo(*Field, 0);
+ LLVMBitFields.push_back(LLVMBitFieldInfo(*Field, 0, 0, FieldSize));
+ } else {
+ LLVMFields.push_back(LLVMFieldInfo(*Field, 0));
+ }
HasOnlyZeroSizedBitFields = false;
-
+
const llvm::Type *FieldTy =
Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
@@ -218,7 +325,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
"0-align record did not have all zero-sized bit-fields!");
Align = 1;
}
-
+
// Append tail padding.
if (Layout.getSize() / 8 > Size)
AppendPadding(Layout.getSize() / 8, Align);
@@ -228,9 +335,9 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) {
// Check if we need to add a vtable pointer.
if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
- const llvm::Type *Int8PtrTy =
+ const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(Types.getLLVMContext());
-
+
assert(NextFieldOffsetInBytes == 0 &&
"Vtable pointer must come first!");
AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
@@ -245,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
LayoutBases(RD, Layout);
-
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
@@ -269,14 +376,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
uint64_t RecordSizeInBytes = RecordSize / 8;
assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
- uint64_t AlignedNextFieldOffset =
+ uint64_t AlignedNextFieldOffset =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);
if (AlignedNextFieldOffset == RecordSizeInBytes) {
// We don't need any padding.
return;
}
-
+
unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
AppendBytes(NumPadBytes);
}
@@ -359,46 +466,49 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
}
} else if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
+
// FIXME: It would be better if there was a way to explicitly compute the
// record layout instead of converting to a type.
Types.ConvertTagDeclType(RD);
-
+
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
-
+
if (Layout.containsPointerToDataMember())
ContainsPointerToDataMember = true;
- }
+ }
}
-CGRecordLayout *
-CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
- const RecordDecl *D) {
- CGRecordLayoutBuilder Builder(Types);
+CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
+ CGRecordLayoutBuilder Builder(*this);
Builder.Layout(D);
- const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(),
+ const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),
Builder.FieldTypes,
Builder.Packed);
- assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 ==
- Types.getTargetData().getTypeAllocSize(Ty) &&
+ assert(getContext().getASTRecordLayout(D).getSize() / 8 ==
+ getTargetData().getTypeAllocSize(Ty) &&
"Type size mismatch!");
+ CGRecordLayout *RL =
+ new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
+
// Add all the field numbers.
for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) {
const FieldDecl *FD = Builder.LLVMFields[i].first;
unsigned FieldNo = Builder.LLVMFields[i].second;
- Types.addFieldInfo(FD, FieldNo);
+ RL->FieldInfo.insert(std::make_pair(FD, FieldNo));
}
// Add bitfield info.
for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) {
- const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i];
+ const CGRecordLayoutBuilder::LLVMBitFieldInfo &Info =
+ Builder.LLVMBitFields[i];
- Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
+ CGRecordLayout::BitFieldInfo BFI(Info.FieldNo, Info.Start, Info.Size);
+ RL->BitFields.insert(std::make_pair(Info.FD, BFI));
}
- return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
+ return RL;
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
deleted file mode 100644
index eb60ed7b5b1d..000000000000
--- a/lib/CodeGen/CGRecordLayoutBuilder.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is a helper class used to build CGRecordLayout objects and LLVM types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
-#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/System/DataTypes.h"
-#include <vector>
-
-namespace llvm {
- class Type;
-}
-
-namespace clang {
- class ASTRecordLayout;
- class CXXRecordDecl;
- class FieldDecl;
- class RecordDecl;
- class QualType;
-
-namespace CodeGen {
- class CGRecordLayout;
- class CodeGenTypes;
-
-class CGRecordLayoutBuilder {
- CodeGenTypes &Types;
-
- /// Packed - Whether the resulting LLVM struct will be packed or not.
- bool Packed;
-
- /// ContainsPointerToDataMember - Whether one of the fields in this record
- /// layout is a pointer to data member, or a struct that contains pointer to
- /// data member.
- bool ContainsPointerToDataMember;
-
- /// Alignment - Contains the alignment of the RecordDecl.
- unsigned Alignment;
-
- /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
- /// LLVM types.
- unsigned AlignmentAsLLVMStruct;
-
- /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
- /// this will have the number of bits still available in the field.
- char BitsAvailableInLastField;
-
- /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
- uint64_t NextFieldOffsetInBytes;
-
- /// FieldTypes - Holds the LLVM types that the struct is created from.
- std::vector<const llvm::Type *> FieldTypes;
-
- /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
- typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
- llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
-
- /// LLVMBitFieldInfo - Holds location and size information about a bit field.
- struct LLVMBitFieldInfo {
- LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start,
- unsigned Size)
- : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { }
-
- const FieldDecl *FD;
-
- unsigned FieldNo;
- unsigned Start;
- unsigned Size;
- };
- llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
-
- CGRecordLayoutBuilder(CodeGenTypes &Types)
- : Types(Types), Packed(false), ContainsPointerToDataMember(false)
- , Alignment(0), AlignmentAsLLVMStruct(1)
- , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
-
- /// Layout - Will layout a RecordDecl.
- void Layout(const RecordDecl *D);
-
- /// LayoutUnion - Will layout a union RecordDecl.
- void LayoutUnion(const RecordDecl *D);
-
- /// LayoutField - try to layout all fields in the record decl.
- /// Returns false if the operation failed because the struct is not packed.
- bool LayoutFields(const RecordDecl *D);
-
- /// LayoutBases - layout the bases and vtable pointer of a record decl.
- void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
-
- /// LayoutField - layout a single field. Returns false if the operation failed
- /// because the current struct is not packed.
- bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// LayoutBitField - layout a single bit field.
- void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// 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);
-
- /// AppendBytes - Append a given number of bytes to the record.
- void AppendBytes(uint64_t NumBytes);
-
- /// AppendTailPadding - Append enough tail padding so that the type will have
- /// the passed size.
- 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.
- void CheckForPointerToDataMember(QualType T);
-
-public:
- /// ComputeLayout - Return the right record layout for a given record decl.
- static CGRecordLayout *ComputeLayout(CodeGenTypes &Types,
- const RecordDecl *D);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-
-#endif
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a889e55a9e80..ae2f791719d3 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -607,7 +607,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (FnRetTy->isReferenceType()) {
// If this function returns a reference, take the address of the expression
// rather than the value.
- Builder.CreateStore(EmitLValue(RV).getAddress(), ReturnValue);
+ RValue Result = EmitReferenceBindingToExpr(RV, false);
+ Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else if (!hasAggregateLLVMType(RV->getType())) {
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
} else if (RV->getType()->isAnyComplexType()) {
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index bed843966e62..6d38ab98dee6 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -127,15 +127,14 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
size_t CleanupStackDepth = CleanupEntries.size();
(void) CleanupStackDepth;
- unsigned OldNumLiveTemporaries = LiveTemporaries.size();
-
- RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
- /*IgnoreResult=*/false, IsInitializer);
-
- // Pop temporaries.
- while (LiveTemporaries.size() > OldNumLiveTemporaries)
- PopCXXTemporary();
+ RValue RV;
+
+ {
+ CXXTemporariesCleanupScope Scope(*this);
+ RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
+ /*IgnoreResult=*/false, IsInitializer);
+ }
assert(CleanupEntries.size() == CleanupStackDepth &&
"Cleanup size mismatch!");
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 96c104b22d15..91d9f763bfe7 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -19,283 +19,355 @@ using namespace CodeGen;
#define D1(x)
namespace {
+
+/// VTT builder - Class for building VTT layout information.
class VTTBuilder {
- /// Inits - The list of values built for the VTT.
- std::vector<llvm::Constant *> &Inits;
- /// Class - The most derived class that this vtable is being built for.
- const CXXRecordDecl *Class;
- CodeGenModule &CGM; // Per-module state.
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
- /// BLayout - Layout for the most derived class that this vtable is being
- /// built for.
- const ASTRecordLayout &BLayout;
- CGVtableInfo::AddrMap_t &AddressPoints;
- // vtbl - A pointer to the vtable for Class.
- llvm::Constant *ClassVtbl;
- llvm::LLVMContext &VMContext;
-
- /// SeenVBasesInSecondary - The seen virtual bases when building the
- /// secondary virtual pointers.
- llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary;
+
+ CodeGenModule &CGM;
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy;
- bool GenerateDefinition;
+ /// VTTComponents - The VTT components.
+ VTTComponentsVectorTy VTTComponents;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
- llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
- llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
- CtorVtableAddressPoints;
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+
+ /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
+ /// class.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
+ /// all subobjects of the most derived class.
+ llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
+
+ /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
+ /// the VTT.
+ bool GenerateDefinition;
- llvm::Constant *getCtorVtable(const BaseSubobject &Base,
- bool BaseIsVirtual) {
- if (!GenerateDefinition)
- return 0;
-
- llvm::Constant *&CtorVtable = CtorVtables[Base];
- if (!CtorVtable) {
- // Build the vtable.
- CGVtableInfo::CtorVtableInfo Info
- = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseIsVirtual);
-
- CtorVtable = Info.Vtable;
-
- // Add the address points for this base.
- for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
- Info.AddressPoints.begin(), E = Info.AddressPoints.end();
- I != E; ++I) {
- uint64_t &AddressPoint =
- CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
-
- // Check if we already have the address points for this base.
- if (AddressPoint)
- break;
-
- // Otherwise, insert it.
- AddressPoint = I->second;
- }
- }
-
- return CtorVtable;
+ /// GetAddrOfVTable - Returns the address of the vtable for the base class in
+ /// the given vtable class.
+ ///
+ /// \param AddressPoints - If the returned vtable is a construction vtable,
+ /// this will hold the address points for it.
+ llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
+ AddressPointsMapTy& AddressPoints);
+
+ /// AddVTablePointer - Add a vtable pointer to the VTT currently being built.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints);
+
+ /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
+ /// subobject.
+ void LayoutSecondaryVTTs(BaseSubobject Base);
+
+ /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
+ /// 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.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
+ /// for the given base subobject.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ llvm::Constant *VTable,
+ const AddressPointsMapTy& AddressPoints);
+
+ /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
+ /// given record decl.
+ void LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutVTT - Will lay out the VTT for the given subobject, including any
+ /// secondary VTTs, secondary virtual pointers and virtual VTTs.
+ void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
+
+public:
+ VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition);
+
+ // getVTTComponents - Returns a reference to the VTT components.
+ const VTTComponentsVectorTy &getVTTComponents() const {
+ return VTTComponents;
}
+ /// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
+ const llvm::DenseMap<const CXXRecordDecl *, uint64_t> &
+ getSubVTTIndicies() const {
+ return SubVTTIndicies;
+ }
- /// BuildVtablePtr - Build up a referene to the given secondary vtable
- llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
- const CXXRecordDecl *VtableClass,
- const CXXRecordDecl *RD,
- uint64_t Offset) {
- if (!GenerateDefinition)
- return 0;
-
- uint64_t AddressPoint;
-
- if (VtableClass != Class) {
- // We have a ctor vtable, look for the address point in the ctor vtable
- // address points.
- AddressPoint =
- CtorVtableAddressPoints[std::make_pair(VtableClass,
- BaseSubobject(RD, Offset))];
- } else {
- AddressPoint =
- (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)];
- }
+ /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
+ /// virtual pointer indices.
+ const llvm::DenseMap<BaseSubobject, uint64_t> &
+ getSecondaryVirtualPointerIndices() const {
+ return SecondaryVirtualPointerIndices;
+ }
- // FIXME: We can never have 0 address point. Do this for now so gepping
- // retains the same structure. Later we'll just assert.
- if (AddressPoint == 0)
- AddressPoint = 1;
- D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
- RD->getNameAsCString(), VtblClass->getNameAsCString(),
- Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
-
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0),
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint)
- };
+};
+
+VTTBuilder::VTTBuilder(CodeGenModule &CGM,
+ const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition)
+ : CGM(CGM), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)),
+ GenerateDefinition(GenerateDefinition) {
- llvm::Constant *Init =
- llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2);
+ // Lay out this VTT.
+ LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false);
+}
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+llvm::Constant *
+VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
+ AddressPointsMapTy& AddressPoints) {
+ if (!GenerateDefinition)
+ return 0;
+
+ if (Base.getBase() == MostDerivedClass) {
+ assert(Base.getBaseOffset() == 0 &&
+ "Most derived class vtable must have a zero offset!");
+ // This is a regular vtable.
+ return CGM.getVTables().GetAddrOfVTable(MostDerivedClass);
}
+
+ return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass,
+ Base, BaseIsVirtual,
+ AddressPoints);
+}
- /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
- /// current offset in bits to the object we're working on.
- void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl,
- const CXXRecordDecl *VtblClass, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- if (RD->getNumVBases() == 0 && ! MorallyVirtual)
- return;
-
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
- // We only want to visit each virtual base once.
- if (i->isVirtual() && SeenVBasesInSecondary.count(Base))
- continue;
-
- // Itanium C++ ABI 2.6.2:
- // Secondary virtual pointers are present for all bases with either
- // virtual bases or virtual function declarations overridden along a
- // virtual path.
- //
- // If the base class is not dynamic, we don't want to add it, nor any
- // of its base classes.
- if (!Base->isDynamicClass())
- continue;
+void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints) {
+ // Store the vtable pointer index if we're generating the primary VTT.
+ if (VTableClass == MostDerivedClass) {
+ assert(!SecondaryVirtualPointerIndices.count(Base) &&
+ "A virtual pointer index already exists for this base subobject!");
+ SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
+ }
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
- bool NonVirtualPrimaryBase;
- NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
- bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
- uint64_t BaseOffset;
- if (!i->isVirtual()) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- } else
- BaseOffset = BLayout.getVBaseClassOffset(Base);
- llvm::Constant *subvtbl = vtbl;
- const CXXRecordDecl *subVtblClass = VtblClass;
- if ((Base->getNumVBases() || BaseMorallyVirtual)
- && !NonVirtualPrimaryBase) {
- llvm::Constant *init;
- if (BaseMorallyVirtual || VtblClass == Class)
- init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset);
- else {
- init = getCtorVtable(BaseSubobject(Base, BaseOffset), i->isVirtual());
-
- subvtbl = init;
- subVtblClass = Base;
-
- init = BuildVtablePtr(init, Class, Base, BaseOffset);
- }
-
- Inits.push_back(init);
- }
-
- if (i->isVirtual())
- SeenVBasesInSecondary.insert(Base);
-
- Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual);
- }
+ if (!GenerateDefinition) {
+ VTTComponents.push_back(0);
+ return;
}
- /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
- /// currnet object we're working on.
- void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool BaseIsVirtual,
- bool MorallyVirtual) {
- // Itanium C++ ABI 2.6.2:
- // An array of virtual table addresses, called the VTT, is declared for
- // each class type that has indirect or direct virtual base classes.
- if (RD->getNumVBases() == 0)
- return;
+ uint64_t AddressPoint;
+ if (VTableClass != MostDerivedClass) {
+ // The vtable is a construction vtable, look in the construction vtable
+ // address points.
+ AddressPoint = AddressPoints.lookup(Base);
+ } else {
+ // Just get the address point for the regular vtable.
+ AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ }
- // Remember the sub-VTT index.
- SubVTTIndicies[RD] = Inits.size();
+ 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),
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()),
+ AddressPoint)
+ };
+
+ llvm::Constant *Init =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2);
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+
+ VTTComponents.push_back(Init);
+}
- llvm::Constant *Vtable;
- const CXXRecordDecl *VtableClass;
+void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
- // First comes the primary virtual table pointer...
- if (MorallyVirtual) {
- Vtable = ClassVtbl;
- VtableClass = Class;
- } else {
- Vtable = getCtorVtable(BaseSubobject(RD, Offset),
- /*IsVirtual=*/BaseIsVirtual);
- VtableClass = RD;
- }
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
- llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
- Inits.push_back(Init);
-
- // then the secondary VTTs....
- SecondaryVTTs(RD, Offset, MorallyVirtual);
+ // Don't layout virtual bases.
+ if (I->isVirtual())
+ continue;
- // Make sure to clear the set of seen virtual bases.
- SeenVBasesInSecondary.clear();
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- // and last the secondary vtable pointers.
- Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual);
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ // Layout the VTT for this base.
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
}
+}
+
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints,
+ VisitedVirtualBasesSetTy &VBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // We're not interested in bases that don't have virtual bases, and not
+ // morally virtual bases.
+ if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
+ return;
- /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
- /// built from each direct non-virtual proper base that requires a VTT in
- /// declaration order.
- void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual())
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers are present for all bases with either
+ // virtual bases or virtual function declarations overridden along a
+ // virtual path.
+ //
+ // If the base class is not dynamic, we don't want to add it, nor any
+ // of its base classes.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ bool BaseDeclIsNonVirtualPrimaryBase = false;
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ // Ignore virtual bases that we've already visited.
+ if (!VBases.insert(BaseDecl))
continue;
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ BaseDeclIsMorallyVirtual = true;
+ } else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/false, MorallyVirtual);
+ BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+
+ if (!Layout.getPrimaryBaseWasVirtual() &&
+ Layout.getPrimaryBase() == BaseDecl)
+ BaseDeclIsNonVirtualPrimaryBase = true;
}
- }
- /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
- /// graph preorder.
- void VirtualVTTs(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual() && !SeenVBase.count(Base)) {
- SeenVBase.insert(Base);
- uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/true, false);
- }
- VirtualVTTs(Base);
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers: for each base class X which (a) has virtual
+ // bases or is reachable along a virtual path from D, and (b) is not a
+ // non-virtual primary base, the address of the virtual table for X-in-D
+ // or an appropriate construction virtual table.
+ if (!BaseDeclIsNonVirtualPrimaryBase &&
+ (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
+ // Add the vtable pointer.
+ AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass,
+ AddressPoints);
}
+
+ // And lay out the secondary virtual pointers for the base class.
+ LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
+ BaseDeclIsMorallyVirtual, VTable,
+ VTableClass, AddressPoints, VBases);
}
+}
-public:
- VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm, bool GenerateDefinition)
- : Inits(inits), Class(c), CGM(cgm),
- BLayout(cgm.getContext().getASTRecordLayout(c)),
- AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
- VMContext(cgm.getModule().getContext()),
- GenerateDefinition(GenerateDefinition) {
-
- // First comes the primary virtual table pointer for the complete class...
- ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0;
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ llvm::Constant *VTable,
+ const AddressPointsMapTy& AddressPoints) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
+ VTable, Base.getBase(), AddressPoints, VBases);
+}
- llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0);
- Inits.push_back(Init);
+void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- // then the secondary VTTs...
- SecondaryVTTs(Class);
+ // Check if this is a virtual base.
+ if (I->isVirtual()) {
+ // Check if we've seen this base before.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ uint64_t BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
+ }
+
+ // We only need to layout virtual VTTs for this base if it actually has
+ // virtual bases.
+ if (BaseDecl->getNumVBases())
+ LayoutVirtualVTTs(BaseDecl, VBases);
+ }
+}
- // Make sure to clear the set of seen virtual bases.
- SeenVBasesInSecondary.clear();
+void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
+ const CXXRecordDecl *RD = Base.getBase();
- // then the secondary vtable pointers...
- Secondary(Class, ClassVtbl, Class);
+ // Itanium C++ ABI 2.6.2:
+ // An array of virtual table addresses, called the VTT, is declared for
+ // each class type that has indirect or direct virtual base classes.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
- // and last, the virtual VTTs.
- VirtualVTTs(Class);
+ if (!IsPrimaryVTT) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[RD] = VTTComponents.size();
}
+
+ AddressPointsMapTy AddressPoints;
+ llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints);
+
+ // Add the primary vtable pointer.
+ AddVTablePointer(Base, VTable, RD, AddressPoints);
+
+ // Add the secondary VTTs.
+ LayoutSecondaryVTTs(Base);
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
- return SubVTTIndicies;
+ // Add the secondary virtual pointers.
+ LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints);
+
+ // If this is the primary VTT, we want to lay out virtual VTTs as well.
+ if (IsPrimaryVTT) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutVirtualVTTs(Base.getBase(), VBases);
}
-};
+}
+
}
llvm::GlobalVariable *
-CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition,
- const CXXRecordDecl *RD) {
+CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
+ const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
return 0;
@@ -311,13 +383,15 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+ VTTBuilder Builder(CGM, RD, GenerateDefinition);
+
+ const llvm::ArrayType *Type =
+ llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
llvm::Constant *Init = 0;
if (GenerateDefinition)
- Init = llvm::ConstantArray::get(Type, inits);
+ Init = llvm::ConstantArray::get(Type, Builder.getVTTComponents().data(),
+ Builder.getVTTComponents().size());
llvm::GlobalVariable *OldGV = GV;
GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
@@ -336,26 +410,12 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
return GV;
}
-CGVtableInfo::CtorVtableInfo
-CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
- const BaseSubobject &Base, bool BaseIsVirtual) {
- CtorVtableInfo Info;
-
- Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
- /*GenerateDefinition=*/true,
- RD, Base.getBase(), Base.getBaseOffset(),
- BaseIsVirtual, Info.AddressPoints);
- return Info;
-}
-
-llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+llvm::GlobalVariable *CodeGenVTables::getVTT(const CXXRecordDecl *RD) {
return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
/*GenerateDefinition=*/false, RD);
-
}
-
-bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
+bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// We don't have any virtual bases, just return early.
@@ -373,19 +433,17 @@ bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
return false;
}
-uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *Base) {
+uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
ClassPairTy ClassPair(RD, Base);
- SubVTTIndiciesTy::iterator I =
- SubVTTIndicies.find(ClassPair);
+ SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair);
if (I != SubVTTIndicies.end())
return I->second;
- std::vector<llvm::Constant *> inits;
- VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+ VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
// Insert all indices.
@@ -399,3 +457,31 @@ uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
return I->second;
}
+
+uint64_t
+CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
+ BaseSubobject Base) {
+ SecondaryVirtualPointerIndicesMapTy::iterator I =
+ SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
+
+ if (I != SecondaryVirtualPointerIndices.end())
+ return I->second;
+
+ VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
+
+ // Insert all secondary vpointer indices.
+ for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
+ Builder.getSecondaryVirtualPointerIndices().begin(),
+ E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) {
+ std::pair<const CXXRecordDecl *, BaseSubobject> Pair =
+ std::make_pair(RD, I->first);
+
+ SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second));
+ }
+
+ I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
+ assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!");
+
+ return I->second;
+}
+
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index df30f479acc8..2d1c73440bbe 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -138,7 +138,7 @@ private:
/// AddOverriders - Add the final overriders for this base subobject to the
/// map of final overriders.
- void AddOverriders(BaseSubobject Base,uint64_t OffsetInLayoutClass,
+ void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass,
SubobjectOffsetsMapTy &Offsets);
/// PropagateOverrider - Propagate the NewMD overrider to all the functions
@@ -636,6 +636,10 @@ public:
reinterpret_cast<uintptr_t>(MD));
}
+ static VtableComponent getFromOpaqueInteger(uint64_t I) {
+ return VtableComponent(I);
+ }
+
/// getKind - Get the kind of this vtable component.
Kind getKind() const {
return (Kind)(Value & 0x7);
@@ -725,6 +729,9 @@ private:
return static_cast<uintptr_t>(Value & ~7ULL);
}
+ explicit VtableComponent(uint64_t Value)
+ : Value(Value) { }
+
/// The kind is stored in the lower 3 bits of the value. For offsets, we
/// make use of the facts that classes can't be larger than 2^55 bytes,
/// so we store the offset in the lower part of the 61 bytes that remain.
@@ -1091,9 +1098,15 @@ public:
typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
PrimaryBasesSetVectorTy;
+ typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ VBaseOffsetOffsetsMapTy;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t>
+ AddressPointsMapTy;
+
private:
- /// VtableInfo - Global vtable information.
- CGVtableInfo &VtableInfo;
+ /// VTables - Global vtable information.
+ CodeGenVTables &VTables;
/// MostDerivedClass - The most derived class for which we're building this
/// vtable.
@@ -1122,9 +1135,6 @@ private:
/// bases in this vtable.
llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
- typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
- VBaseOffsetOffsetsMapTy;
-
/// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
/// the most derived class.
VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
@@ -1133,29 +1143,8 @@ private:
llvm::SmallVector<VtableComponent, 64> Components;
/// AddressPoints - Address points for the vtable being built.
- CGVtableInfo::AddressPointsMapTy AddressPoints;
-
- /// ReturnAdjustment - A return adjustment.
- struct ReturnAdjustment {
- /// NonVirtual - The non-virtual adjustment from the derived object to its
- /// nearest virtual base.
- int64_t NonVirtual;
-
- /// VBaseOffsetOffset - The offset (in bytes), relative to the address point
- /// of the virtual base class offset.
- int64_t VBaseOffsetOffset;
-
- ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
-
- bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+ AddressPointsMapTy AddressPoints;
- friend bool operator==(const ReturnAdjustment &LHS,
- const ReturnAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
- }
- };
-
/// MethodInfo - Contains information about a method in a vtable.
/// (Used for computing 'this' pointer adjustment thunks.
struct MethodInfo {
@@ -1185,62 +1174,21 @@ private:
/// currently building.
MethodInfoMapTy MethodInfoMap;
- /// ThisAdjustment - A 'this' pointer adjustment thunk.
- struct ThisAdjustment {
- /// NonVirtual - The non-virtual adjustment from the derived object to its
- /// nearest virtual base.
- int64_t NonVirtual;
-
- /// VCallOffsetOffset - The offset (in bytes), relative to the address point,
- /// of the virtual call offset.
- int64_t VCallOffsetOffset;
-
- ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
-
- bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
-
- friend bool operator==(const ThisAdjustment &LHS,
- const ThisAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
- }
- };
-
- /// ThunkInfo - The 'this' pointer adjustment as well as an optional return
- /// adjustment for a thunk.
- struct ThunkInfo {
- /// This - The 'this' pointer adjustment.
- ThisAdjustment This;
-
- /// Return - The return adjustment.
- ReturnAdjustment Return;
-
- ThunkInfo() { }
-
- ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
- : This(This), Return(Return) { }
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy;
- friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
- return LHS.This == RHS.This && LHS.Return == RHS.Return;
- }
+ /// VTableThunks - The thunks by vtable index in the vtable currently being
+ /// built.
+ VtableThunksMapTy VTableThunks;
- bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
- };
-
- typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
+ typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
- /// Thunks - The thunks by vtable index in the vtable currently being built.
- ThunksInfoMapTy Thunks;
-
- typedef llvm::DenseMap<const CXXMethodDecl *,
- llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy;
-
- /// MethodThunks - A map that contains all the thunks needed for all methods
- /// in the vtable currently being built.
- MethodThunksMapTy MethodThunks;
+ /// Thunks - A map that contains all the thunks needed for all methods in the
+ /// most derived class for which the vtable is currently being built.
+ ThunksMapTy Thunks;
/// AddThunk - Add a thunk for the given method.
- void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk);
+ void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk);
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building.
@@ -1341,10 +1289,10 @@ private:
}
public:
- VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass,
+ VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass)
- : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass),
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
MostDerivedClassOffset(MostDerivedClassOffset),
MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
@@ -1353,15 +1301,57 @@ public:
LayoutVtable();
}
+ ThunksMapTy::const_iterator thunks_begin() const {
+ return Thunks.begin();
+ }
+
+ ThunksMapTy::const_iterator thunks_end() const {
+ return Thunks.end();
+ }
+
+ const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+ return VBaseOffsetOffsets;
+ }
+
+ /// getNumVTableComponents - Return the number of components in the vtable
+ /// currently built.
+ uint64_t getNumVTableComponents() const {
+ return Components.size();
+ }
+
+ const uint64_t *vtable_components_data_begin() const {
+ return reinterpret_cast<const uint64_t *>(Components.begin());
+ }
+
+ const uint64_t *vtable_components_data_end() const {
+ return reinterpret_cast<const uint64_t *>(Components.end());
+ }
+
+ AddressPointsMapTy::const_iterator address_points_begin() const {
+ return AddressPoints.begin();
+ }
+
+ AddressPointsMapTy::const_iterator address_points_end() const {
+ return AddressPoints.end();
+ }
+
+ VtableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ return VTableThunks.begin();
+ }
+
+ VtableThunksMapTy::const_iterator vtable_thunks_end() const {
+ return VTableThunks.end();
+ }
+
/// dumpLayout - Dump the vtable layout.
void dumpLayout(llvm::raw_ostream&);
};
-void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) {
- if (isBuildingConstructorVtable())
- return;
+void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ assert(!isBuildingConstructorVtable() &&
+ "Can't add thunks for construction vtable");
- llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+ llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
// Check if we have this thunk already.
if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
@@ -1410,6 +1400,17 @@ void VtableBuilder::ComputeThisAdjustments() {
Overriders.getOverrider(BaseSubobject(MD->getParent(),
MethodInfo.BaseOffset), MD);
+ // Check if we need an adjustment at all.
+ if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
+ // When a return thunk is needed by a derived class that overrides a
+ // virtual base, gcc uses a virtual 'this' adjustment as well.
+ // 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())
+ continue;
+ }
+
ThisAdjustment ThisAdjustment =
ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
@@ -1417,22 +1418,48 @@ void VtableBuilder::ComputeThisAdjustments() {
continue;
// Add it.
- Thunks[VtableIndex].This = ThisAdjustment;
+ VTableThunks[VtableIndex].This = ThisAdjustment;
if (isa<CXXDestructorDecl>(MD)) {
// Add an adjustment for the deleting destructor as well.
- Thunks[VtableIndex + 1].This = ThisAdjustment;
+ VTableThunks[VtableIndex + 1].This = ThisAdjustment;
}
-
- AddThunk(Overrider.Method, Thunks[VtableIndex]);
}
/// Clear the method info map.
MethodInfoMap.clear();
+
+ if (isBuildingConstructorVtable()) {
+ // We don't need to store thunk information for construction vtables.
+ return;
+ }
+
+ for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(),
+ E = VTableThunks.end(); I != E; ++I) {
+ 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:
+ MD = Component.getFunctionDecl();
+ break;
+ case VtableComponent::CK_CompleteDtorPointer:
+ MD = Component.getDestructorDecl();
+ break;
+ case VtableComponent::CK_DeletingDtorPointer:
+ // We've already added the thunk when we saw the complete dtor pointer.
+ continue;
+ }
+
+ if (MD->getParent() == MostDerivedClass)
+ AddThunk(MD, Thunk);
+ }
}
-VtableBuilder::ReturnAdjustment
-VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1444,8 +1471,8 @@ VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
VBaseOffsetOffsets.lookup(Offset.VirtualBase);
} else {
Adjustment.VBaseOffsetOffset =
- VtableInfo.getVirtualBaseOffsetOffset(Offset.DerivedClass,
- Offset.VirtualBase);
+ VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
+ Offset.VirtualBase);
}
// FIXME: Once the assert in getVirtualBaseOffsetOffset is back again,
@@ -1512,14 +1539,10 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
return BaseOffset();
}
-VtableBuilder::ThisAdjustment
+ThisAdjustment
VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
uint64_t BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider) {
- // Check if we need an adjustment at all.
- if (BaseOffsetInLayoutClass == Overrider.Offset)
- return ThisAdjustment();
-
// Ignore adjustments for pure virtual member functions.
if (Overrider.Method->isPure())
return ThisAdjustment();
@@ -1576,7 +1599,7 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
- Thunks[Components.size()].Return = ReturnAdjustment;
+ VTableThunks[Components.size()].Return = ReturnAdjustment;
// Add the function.
Components.push_back(VtableComponent::MakeFunction(MD));
@@ -1776,6 +1799,25 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
MethodInfoMap.erase(OverriddenMD);
+
+ // If the overridden method exists in a virtual base class or a direct
+ // 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) {
+ // Compute the this adjustment.
+ ThisAdjustment ThisAdjustment =
+ ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
+ Overrider);
+
+ if (ThisAdjustment.VCallOffsetOffset &&
+ Overrider.Method->getParent() == MostDerivedClass) {
+ // This is a virtual thunk for the most derived class, add it.
+ AddThunk(Overrider.Method,
+ ThunkInfo(ThisAdjustment, ReturnAdjustment()));
+ }
+ }
+
continue;
}
}
@@ -1866,20 +1908,32 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
// Compute 'this' pointer adjustments.
ComputeThisAdjustments();
- // Record the address point.
- AddressPoints.insert(std::make_pair(BaseSubobject(Base.getBase(),
- OffsetInLayoutClass),
- AddressPoint));
-
- // Record the address points for all primary bases.
- for (PrimaryBasesSetVectorTy::const_iterator I = PrimaryBases.begin(),
- E = PrimaryBases.end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = *I;
+ // Add all address points.
+ const CXXRecordDecl *RD = Base.getBase();
+ while (true) {
+ AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
+ AddressPoint));
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- // We know that all the primary bases have the same offset as the base
- // subobject.
- BaseSubobject PrimaryBase(BaseDecl, OffsetInLayoutClass);
- AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
+ if (!PrimaryBase)
+ break;
+
+ if (Layout.getPrimaryBaseWasVirtual()) {
+ // Check if this virtual primary base is a primary base in the layout
+ // class. If it's not, we don't want to add it.
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
+ OffsetInLayoutClass) {
+ // We don't want to add this class (or any of its primary bases).
+ break;
+ }
+ }
+
+ RD = PrimaryBase;
}
bool BaseIsMorallyVirtual = BaseIsVirtual;
@@ -2062,8 +2116,8 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
// Since an address point can be shared by multiple subobjects, we use an
// STL multimap.
std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
- for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
- AddressPoints.begin(), E = AddressPoints.end(); I != E; ++I) {
+ for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(),
+ E = AddressPoints.end(); I != E; ++I) {
const BaseSubobject& Base = I->first;
uint64_t Index = I->second;
@@ -2106,7 +2160,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (MD->isPure())
Out << " [pure]";
- ThunkInfo Thunk = Thunks.lookup(I);
+ ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this function pointer has a return adjustment, dump it.
if (!Thunk.Return.isEmpty()) {
@@ -2154,7 +2208,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (DD->isPure())
Out << " [pure]";
- ThunkInfo Thunk = Thunks.lookup(I);
+ ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this destructor has a 'this' pointer adjustment, dump it.
if (!Thunk.This.isEmpty()) {
@@ -2253,13 +2307,12 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << "\n";
}
- if (!MethodThunks.empty()) {
-
+ if (!Thunks.empty()) {
// We store the method names in a map to get a stable order.
std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
- for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(),
- E = MethodThunks.end(); I != E; ++I) {
+ for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
+ I != E; ++I) {
const CXXMethodDecl *MD = I->first;
std::string MethodName =
PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
@@ -2273,7 +2326,9 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
I != E; ++I) {
const std::string &MethodName = I->first;
const CXXMethodDecl *MD = I->second;
- const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+
+ ThunkInfoVectorTy ThunksVector = Thunks[MD];
+ std::sort(ThunksVector.begin(), ThunksVector.end());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2283,1099 +2338,42 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << llvm::format("%4d | ", I);
+ // If this function pointer has a return pointer adjustment, dump it.
+ if (!Thunk.Return.isEmpty()) {
+ Out << "return adjustment: " << Thunk.This.NonVirtual;
+ Out << " non-virtual";
+ if (Thunk.Return.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ Out << " vbase offset offset";
+ }
+
+ if (!Thunk.This.isEmpty())
+ Out << "\n ";
+ }
+
// If this function pointer has a 'this' pointer adjustment, dump it.
if (!Thunk.This.isEmpty()) {
- Out << "this: ";
- Out << Thunk.This.NonVirtual << " nv";
+ Out << "this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
if (Thunk.This.VCallOffsetOffset) {
Out << ", " << Thunk.This.VCallOffsetOffset;
- Out << " v";
+ Out << " vcall offset offset";
}
}
Out << '\n';
}
- }
- }
-}
-
-}
-
-namespace {
-class OldVtableBuilder {
-public:
- /// Index_t - Vtable index type.
- typedef uint64_t Index_t;
- typedef std::vector<std::pair<GlobalDecl,
- std::pair<GlobalDecl, ThunkAdjustment> > >
- SavedAdjustmentsVectorTy;
-private:
-
- // VtableComponents - The components of the vtable being built.
- typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy;
- VtableComponentsVectorTy VtableComponents;
-
- const bool BuildVtable;
-
- llvm::Type *Ptr8Ty;
-
- /// MostDerivedClass - The most derived class that this vtable is being
- /// built for.
- const CXXRecordDecl *MostDerivedClass;
-
- /// LayoutClass - The most derived class used for virtual base layout
- /// information.
- const CXXRecordDecl *LayoutClass;
- /// LayoutOffset - The offset for Class in LayoutClass.
- uint64_t LayoutOffset;
- /// BLayout - Layout for the most derived class that this vtable is being
- /// built for.
- const ASTRecordLayout &BLayout;
- llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary;
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
- llvm::Constant *rtti;
- llvm::LLVMContext &VMContext;
- CodeGenModule &CGM; // Per-module state.
-
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
- llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
- llvm::DenseMap<GlobalDecl, Index_t> VCallOffsetForVCall;
- // This is the offset to the nearest virtual base
- llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset;
- llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
-
- /// PureVirtualFunction - Points to __cxa_pure_virtual.
- llvm::Constant *PureVirtualFn;
-
- /// VtableMethods - A data structure for keeping track of methods in a vtable.
- /// Can add methods, override methods and iterate in vtable order.
- class VtableMethods {
- // MethodToIndexMap - Maps from a global decl to the index it has in the
- // Methods vector.
- llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap;
-
- /// Methods - The methods, in vtable order.
- typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy;
- MethodsVectorTy Methods;
- MethodsVectorTy OrigMethods;
-
- public:
- /// AddMethod - Add a method to the vtable methods.
- void AddMethod(GlobalDecl GD) {
- assert(!MethodToIndexMap.count(GD) &&
- "Method has already been added!");
-
- MethodToIndexMap[GD] = Methods.size();
- Methods.push_back(GD);
- OrigMethods.push_back(GD);
- }
-
- /// OverrideMethod - Replace a method with another.
- void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) {
- llvm::DenseMap<GlobalDecl, uint64_t>::iterator i
- = MethodToIndexMap.find(OverriddenGD);
- assert(i != MethodToIndexMap.end() && "Did not find entry!");
-
- // Get the index of the old decl.
- uint64_t Index = i->second;
-
- // Replace the old decl with the new decl.
- Methods[Index] = GD;
-
- // And add the new.
- MethodToIndexMap[GD] = Index;
- }
-
- /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if
- /// the index couldn't be found.
- bool getIndex(GlobalDecl GD, uint64_t &Index) const {
- llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i
- = MethodToIndexMap.find(GD);
-
- if (i == MethodToIndexMap.end())
- return false;
-
- Index = i->second;
- return true;
- }
-
- GlobalDecl getOrigMethod(uint64_t Index) const {
- return OrigMethods[Index];
- }
-
- MethodsVectorTy::size_type size() const {
- return Methods.size();
- }
-
- void clear() {
- MethodToIndexMap.clear();
- Methods.clear();
- OrigMethods.clear();
- }
-
- GlobalDecl operator[](uint64_t Index) const {
- return Methods[Index];
- }
- };
-
- /// Methods - The vtable methods we're currently building.
- VtableMethods Methods;
-
- /// ThisAdjustments - For a given index in the vtable, contains the 'this'
- /// pointer adjustment needed for a method.
- typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy;
- ThisAdjustmentsMapTy ThisAdjustments;
-
- SavedAdjustmentsVectorTy SavedAdjustments;
-
- /// BaseReturnTypes - Contains the base return types of methods who have been
- /// overridden with methods whose return types require adjustment. Used for
- /// generating covariant thunk information.
- typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy;
- BaseReturnTypesMapTy BaseReturnTypes;
-
- std::vector<Index_t> VCalls;
-
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- // subAddressPoints - Used to hold the AddressPoints (offsets) into the built
- // vtable for use in computing the initializers for the VTT.
- llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
-
- /// AddressPoints - Address points for this vtable.
- CGVtableInfo::AddressPointsMapTy& AddressPoints;
-
- typedef CXXRecordDecl::method_iterator method_iter;
- const uint32_t LLVMPointerWidth;
- Index_t extra;
- typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
- static llvm::DenseMap<CtorVtable_t, int64_t>&
- AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
- const CXXRecordDecl *c) {
- CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l];
- if (oref == 0)
- oref = new CGVtableInfo::AddrMap_t;
-
- llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
- if (ref == 0)
- ref = new llvm::DenseMap<CtorVtable_t, int64_t>;
- return *ref;
- }
-
- bool DclIsSame(const FunctionDecl *New, const FunctionDecl *Old) {
- FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
- FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
-
- // C++ [temp.fct]p2:
- // A function template can be overloaded with other function templates
- // and with normal (non-template) functions.
- if ((OldTemplate == 0) != (NewTemplate == 0))
- return false;
-
- // Is the function New an overload of the function Old?
- QualType OldQType = CGM.getContext().getCanonicalType(Old->getType());
- QualType NewQType = CGM.getContext().getCanonicalType(New->getType());
-
- // Compare the signatures (C++ 1.3.10) of the two functions to
- // determine whether they are overloads. If we find any mismatch
- // in the signature, they are overloads.
-
- // If either of these functions is a K&R-style function (no
- // prototype), then we consider them to have matching signatures.
- if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
- isa<FunctionNoProtoType>(NewQType.getTypePtr()))
- return true;
-
- FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
- FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
-
- // The signature of a function includes the types of its
- // parameters (C++ 1.3.10), which includes the presence or absence
- // of the ellipsis; see C++ DR 357).
- if (OldQType != NewQType &&
- (OldType->getNumArgs() != NewType->getNumArgs() ||
- OldType->isVariadic() != NewType->isVariadic() ||
- !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
- NewType->arg_type_begin())))
- return false;
-
-#if 0
- // C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
- // signature, its return type and its template parameter list. The names
- // of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
- // signature.
- //
- // We check the return type and template parameter lists for function
- // templates first; the remaining checks follow.
- if (NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- TPL_TemplateMatch) ||
- OldType->getResultType() != NewType->getResultType()))
- return false;
-#endif
-
- // If the function is a class member, its signature includes the
- // cv-qualifiers (if any) on the function itself.
- //
- // As part of this, also check whether one of the member functions
- // is static, in which case they are not overloads (C++
- // 13.1p2). While not part of the definition of the signature,
- // this check is important to determine whether these functions
- // can be overloaded.
- const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
- !OldMethod->isStatic() && !NewMethod->isStatic() &&
- OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
- return false;
-
- // The signatures match; this is not an overload.
- return true;
- }
-
- typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl*>
- ForwardUnique_t;
- ForwardUnique_t ForwardUnique;
- llvm::DenseMap<const CXXMethodDecl*, const CXXMethodDecl*> UniqueOverrider;
-
- void BuildUniqueOverrider(const CXXMethodDecl *U, const CXXMethodDecl *MD) {
- const CXXMethodDecl *PrevU = UniqueOverrider[MD];
- assert(U && "no unique overrider");
- if (PrevU == U)
- return;
- if (PrevU != U && PrevU != 0) {
- // If already set, note the two sets as the same
- if (0)
- printf("%s::%s same as %s::%s\n",
- PrevU->getParent()->getNameAsString().c_str(),
- PrevU->getNameAsString().c_str(),
- U->getParent()->getNameAsString().c_str(),
- U->getNameAsString().c_str());
- ForwardUnique[PrevU] = U;
- return;
- }
-
- // Not set, set it now
- if (0)
- printf("marking %s::%s %p override as %s::%s\n",
- MD->getParent()->getNameAsString().c_str(),
- MD->getNameAsString().c_str(),
- (void*)MD,
- U->getParent()->getNameAsString().c_str(),
- U->getNameAsString().c_str());
- UniqueOverrider[MD] = U;
-
- for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
- me = MD->end_overridden_methods(); mi != me; ++mi) {
- BuildUniqueOverrider(U, *mi);
- }
- }
-
- void BuildUniqueOverriders(const CXXRecordDecl *RD) {
- if (0) printf("walking %s\n", RD->getNameAsCString());
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
- if (!MD->isVirtual())
- continue;
-
- if (UniqueOverrider[MD] == 0) {
- // Only set this, if it hasn't been set yet.
- BuildUniqueOverrider(MD, MD);
- if (0)
- printf("top set is %s::%s %p\n",
- MD->getParent()->getNameAsString().c_str(),
- MD->getNameAsString().c_str(),
- (void*)MD);
- ForwardUnique[MD] = MD;
- }
- }
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- BuildUniqueOverriders(Base);
- }
- }
-
- static int DclCmp(const void *p1, const void *p2) {
- const CXXMethodDecl *MD1 = *(const CXXMethodDecl *const *)p1;
- const CXXMethodDecl *MD2 = *(const CXXMethodDecl *const *)p2;
-
- return (DeclarationName::compare(MD1->getDeclName(), MD2->getDeclName()));
- }
-
- void MergeForwarding() {
- typedef llvm::SmallVector<const CXXMethodDecl *, 100> A_t;
- A_t A;
- for (ForwardUnique_t::iterator I = ForwardUnique.begin(),
- E = ForwardUnique.end(); I != E; ++I) {
- if (I->first == I->second)
- // Only add the roots of all trees
- A.push_back(I->first);
- }
- llvm::array_pod_sort(A.begin(), A.end(), DclCmp);
- for (A_t::iterator I = A.begin(),
- E = A.end(); I != E; ++I) {
- A_t::iterator J = I;
- while (++J != E && DclCmp(I, J) == 0)
- if (DclIsSame(*I, *J)) {
- if (0) printf("connecting %s\n", (*I)->getNameAsString().c_str());
- ForwardUnique[*J] = *I;
- }
- }
- }
-
- const CXXMethodDecl *getUnique(const CXXMethodDecl *MD) {
- const CXXMethodDecl *U = UniqueOverrider[MD];
- assert(U && "unique overrider not found");
- while (ForwardUnique.count(U)) {
- const CXXMethodDecl *NU = ForwardUnique[U];
- if (NU == U) break;
- U = NU;
- }
- return U;
- }
-
- GlobalDecl getUnique(GlobalDecl GD) {
- const CXXMethodDecl *Unique = getUnique(cast<CXXMethodDecl>(GD.getDecl()));
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Unique))
- return GlobalDecl(CD, GD.getCtorType());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Unique))
- return GlobalDecl(DD, GD.getDtorType());
-
- return Unique;
- }
-
- /// getPureVirtualFn - Return the __cxa_pure_virtual function.
- llvm::Constant* getPureVirtualFn() {
- if (!PureVirtualFn) {
- const llvm::FunctionType *Ty =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- /*isVarArg=*/false);
- PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"));
- }
-
- return PureVirtualFn;
- }
-
-public:
- OldVtableBuilder(const CXXRecordDecl *MostDerivedClass,
- const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
- bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
- : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
- LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)),
- rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm),
- PureVirtualFn(0),
- subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)),
- AddressPoints(AddressPoints),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0))
- {
- Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- if (BuildVtable) {
- QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
- rtti = CGM.GetAddrOfRTTIDescriptor(ClassType);
- }
- BuildUniqueOverriders(MostDerivedClass);
- MergeForwarding();
- }
-
- // getVtableComponents - Returns a reference to the vtable components.
- const VtableComponentsVectorTy &getVtableComponents() const {
- return VtableComponents;
- }
-
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex()
- { return VBIndex; }
-
- SavedAdjustmentsVectorTy &getSavedAdjustments()
- { return SavedAdjustments; }
-
- llvm::Constant *wrap(Index_t i) {
- llvm::Constant *m;
- m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
- return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
- }
-
- llvm::Constant *wrap(llvm::Constant *m) {
- return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
- }
-
-//#define D1(x)
-#define D1(X) do { if (getenv("CLANG_VTABLE_DEBUG")) { X; } } while (0)
-
- void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
- bool updateVBIndex, Index_t current_vbindex) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- Index_t next_vbindex = current_vbindex;
- if (i->isVirtual() && !SeenVBase.count(Base)) {
- SeenVBase.insert(Base);
- if (updateVBIndex) {
- next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8)
- - 3*LLVMPointerWidth/8);
- VBIndex[Base] = next_vbindex;
- }
- int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
- VCalls.push_back((0?700:0) + BaseOffset);
- D1(printf(" vbase for %s at %d delta %d most derived %s\n",
- Base->getNameAsCString(),
- (int)-VCalls.size()-3, (int)BaseOffset,
- MostDerivedClass->getNameAsCString()));
- }
- // We also record offsets for non-virtual bases to closest enclosing
- // virtual base. We do this so that we don't have to search
- // for the nearst virtual base class when generating thunks.
- if (updateVBIndex && VBIndex.count(Base) == 0)
- VBIndex[Base] = next_vbindex;
- GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex);
- }
- }
-
- void StartNewTable() {
- SeenVBase.clear();
- }
-
- Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B,
- Index_t Offset = 0) {
-
- if (B == D)
- return Offset;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D);
- for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(),
- e = D->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- int64_t BaseOffset = 0;
- if (!i->isVirtual())
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- int64_t o = getNVOffset_1(Base, B, BaseOffset);
- if (o >= 0)
- return o;
- }
-
- return -1;
- }
-
- /// getNVOffset - Returns the non-virtual offset for the given (B) base of the
- /// derived class D.
- Index_t getNVOffset(QualType qB, QualType qD) {
- qD = qD->getPointeeType();
- qB = qB->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- int64_t o = getNVOffset_1(D, B);
- if (o >= 0)
- return o;
-
- assert(false && "FIXME: non-virtual base not found");
- return 0;
- }
-
- /// getVbaseOffset - Returns the index into the vtable for the virtual base
- /// offset for the given (B) virtual base of the derived class D.
- Index_t getVbaseOffset(QualType qB, QualType qD) {
- qD = qD->getPointeeType();
- qB = qB->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- if (D != MostDerivedClass)
- return CGM.getVtableInfo().getVirtualBaseOffsetOffset(D, B);
- llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
- i = VBIndex.find(B);
- if (i != VBIndex.end())
- return i->second;
-
- assert(false && "FIXME: Base not found");
- return 0;
- }
-
- bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
- Index_t OverrideOffset, Index_t Offset,
- int64_t CurrentVBaseOffset);
-
- /// AppendMethods - Append the current methods to the vtable.
- void AppendMethodsToVtable();
-
- llvm::Constant *WrapAddrOf(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
-
- return wrap(CGM.GetAddrOfFunction(GD, Ty));
- }
-
- void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
- int64_t CurrentVBaseOffset) {
- for (Path_t::reverse_iterator i = Path->rbegin(),
- e = Path->rend(); i != e; ++i) {
- const CXXRecordDecl *RD = i->first;
- int64_t OverrideOffset = i->second;
- for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- const CXXMethodDecl *MD = *mi;
-
- if (!MD->isVirtual())
- continue;
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Override both the complete and the deleting destructor.
- GlobalDecl CompDtor(DD, Dtor_Complete);
- OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
-
- GlobalDecl DeletingDtor(DD, Dtor_Deleting);
- OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
- } else {
- OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
- }
- }
- }
- }
-
- void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
- int64_t CurrentVBaseOffset) {
- // If we can find a previously allocated slot for this, reuse it.
- if (OverrideMethod(GD, MorallyVirtual, Offset, Offset,
- CurrentVBaseOffset))
- return;
-
- D1(printf(" vfn for %s at %d\n",
- dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(),
- (int)Methods.size()));
-
- // We didn't find an entry in the vtable that we could use, add a new
- // entry.
- Methods.AddMethod(GD);
-
- VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8;
-
- if (MorallyVirtual) {
- GlobalDecl UGD = getUnique(GD);
- const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
-
- assert(UMD && "final overrider not found");
-
- Index_t &idx = VCall[UMD];
- // Allocate the first one, after that, we reuse the previous one.
- if (idx == 0) {
- VCallOffsetForVCall[UGD] = Offset/8;
- NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8;
- idx = VCalls.size()+1;
- VCalls.push_back(Offset/8 - CurrentVBaseOffset/8);
- D1(printf(" vcall for %s at %d with delta %d\n",
- dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(),
- (int)-VCalls.size()-3, (int)VCalls[idx-1]));
- }
- }
- }
-
- void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, int64_t CurrentVBaseOffset) {
- for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- const CXXMethodDecl *MD = *mi;
- if (!MD->isVirtual())
- continue;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // For destructors, add both the complete and the deleting destructor
- // to the vtable.
- AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
- CurrentVBaseOffset);
- AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
- CurrentVBaseOffset);
- } else
- AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
- }
+ Out << '\n';
- void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase,
- bool PrimaryBaseWasVirtual, bool MorallyVirtual,
- int64_t Offset, int64_t CurrentVBaseOffset,
- Path_t *Path) {
- Path->push_back(std::make_pair(RD, Offset));
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (i->isVirtual())
- continue;
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- uint64_t o = Offset + Layout.getBaseClassOffset(Base);
- StartNewTable();
- GenerateVtableForBase(Base, o, MorallyVirtual, false,
- true, Base == PrimaryBase && !PrimaryBaseWasVirtual,
- CurrentVBaseOffset, Path);
}
- Path->pop_back();
}
-
-// #define D(X) do { X; } while (0)
-#define D(X)
-
- void insertVCalls(int InsertionPoint) {
- D1(printf("============= combining vbase/vcall\n"));
- D(VCalls.insert(VCalls.begin(), 673));
- D(VCalls.push_back(672));
-
- VtableComponents.insert(VtableComponents.begin() + InsertionPoint,
- VCalls.size(), 0);
- if (BuildVtable) {
- // The vcalls come first...
- for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(),
- e = VCalls.rend();
- i != e; ++i)
- VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i);
- }
- VCalls.clear();
- VCall.clear();
- VCallOffsetForVCall.clear();
- VCallOffset.clear();
- NonVirtualOffset.clear();
- }
-
- void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
- Index_t AddressPoint) {
- D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
- LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
- AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
-
- // Now also add the address point for all our primary bases.
- while (1) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- RD = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
- // FIXME: Double check this.
- if (RD == 0)
- break;
- if (PrimaryBaseWasVirtual &&
- BLayout.getVBaseClassOffset(RD) != Offset)
- break;
- D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
- LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
- AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
- }
- }
-
-
- void FinishGenerateVtable(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase,
- bool ForNPNVBases, bool WasPrimaryBase,
- bool PrimaryBaseWasVirtual,
- bool MorallyVirtual, int64_t Offset,
- bool ForVirtualBase, int64_t CurrentVBaseOffset,
- Path_t *Path) {
- bool alloc = false;
- if (Path == 0) {
- alloc = true;
- Path = new Path_t;
- }
-
- StartNewTable();
- extra = 0;
- Index_t AddressPoint = 0;
- int VCallInsertionPoint = 0;
- if (!ForNPNVBases || !WasPrimaryBase) {
- bool DeferVCalls = MorallyVirtual || ForVirtualBase;
- VCallInsertionPoint = VtableComponents.size();
- if (!DeferVCalls) {
- insertVCalls(VCallInsertionPoint);
- } else
- // FIXME: just for extra, or for all uses of VCalls.size post this?
- extra = -VCalls.size();
-
- // Add the offset to top.
- VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0);
-
- // Add the RTTI information.
- VtableComponents.push_back(rtti);
-
- AddressPoint = VtableComponents.size();
-
- AppendMethodsToVtable();
- }
-
- // and then the non-virtual bases.
- NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, CurrentVBaseOffset, Path);
-
- if (ForVirtualBase) {
- // FIXME: We're adding to VCalls in callers, we need to do the overrides
- // in the inner part, so that we know the complete set of vcalls during
- // the build and don't have to insert into methods. Saving out the
- // AddressPoint here, would need to be fixed, if we didn't do that. Also
- // retroactively adding vcalls for overrides later wind up in the wrong
- // place, the vcall slot has to be alloted during the walk of the base
- // when the function is first introduces.
- AddressPoint += VCalls.size();
- insertVCalls(VCallInsertionPoint);
- }
-
- if (!ForNPNVBases || !WasPrimaryBase)
- AddAddressPoints(RD, Offset, AddressPoint);
-
- if (alloc) {
- delete Path;
- }
- }
-
- void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
- bool updateVBIndex, Index_t current_vbindex,
- int64_t CurrentVBaseOffset) {
- if (!RD->isDynamicClass())
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- // vtables are composed from the chain of primaries.
- if (PrimaryBase && !PrimaryBaseWasVirtual) {
- D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
- Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, CurrentVBaseOffset);
- }
-
- D1(printf(" doing vcall entries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- // And add the virtuals for the class to the primary vtable.
- AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
-
- void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
- bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, int64_t CurrentVBaseOffset,
- bool bottom) {
- if (!RD->isDynamicClass())
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- // vtables are composed from the chain of primaries.
- if (PrimaryBase) {
- int BaseCurrentVBaseOffset = CurrentVBaseOffset;
- if (PrimaryBaseWasVirtual) {
- IndirectPrimary.insert(PrimaryBase);
- BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
- }
-
- D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset, false);
- }
-
- D1(printf(" doing vbase entries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
- GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex);
-
- if (RDisVirtualBase || bottom) {
- Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- CurrentVBaseOffset);
- }
- }
-
- void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
- bool MorallyVirtual = false,
- bool ForVirtualBase = false,
- bool ForNPNVBases = false,
- bool WasPrimaryBase = true,
- int CurrentVBaseOffset = 0,
- Path_t *Path = 0) {
- if (!RD->isDynamicClass())
- return;
-
- // Construction vtable don't need parts that have no virtual bases and
- // aren't morally virtual.
- if ((LayoutClass != MostDerivedClass) &&
- RD->getNumVBases() == 0 && !MorallyVirtual)
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- extra = 0;
- D1(printf("building entries for base %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- if (ForVirtualBase)
- extra = VCalls.size();
-
- if (!ForNPNVBases || !WasPrimaryBase) {
- VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0,
- ForVirtualBase, CurrentVBaseOffset, true);
-
- if (Path)
- OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
-
- FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase,
- PrimaryBaseWasVirtual, MorallyVirtual, Offset,
- ForVirtualBase, CurrentVBaseOffset, Path);
- }
-
- void GenerateVtableForVBases(const CXXRecordDecl *RD,
- int64_t Offset = 0,
- Path_t *Path = 0) {
- bool alloc = false;
- if (Path == 0) {
- alloc = true;
- Path = new Path_t;
- }
- // FIXME: We also need to override using all paths to a virtual base,
- // right now, we just process the first path
- Path->push_back(std::make_pair(RD, Offset));
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual() && !IndirectPrimary.count(Base)) {
- // Mark it so we don't output it twice.
- IndirectPrimary.insert(Base);
- StartNewTable();
- VCall.clear();
- int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- int64_t CurrentVBaseOffset = BaseOffset;
- D1(printf("vtable %s virtual base %s\n",
- MostDerivedClass->getNameAsCString(), Base->getNameAsCString()));
- GenerateVtableForBase(Base, BaseOffset, true, true, false,
- true, CurrentVBaseOffset, Path);
- }
- int64_t BaseOffset;
- if (i->isVirtual())
- BaseOffset = BLayout.getVBaseClassOffset(Base);
- else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- }
-
- if (Base->getNumVBases()) {
- GenerateVtableForVBases(Base, BaseOffset, Path);
- }
- }
- Path->pop_back();
- if (alloc)
- delete Path;
- }
-};
-} // end anonymous namespace
-
-bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
- Index_t OverrideOffset, Index_t Offset,
- int64_t CurrentVBaseOffset) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- const bool isPure = MD->isPure();
-
- // FIXME: Should OverrideOffset's be Offset?
-
- for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods(); mi != e; ++mi) {
- GlobalDecl OGD;
- GlobalDecl OGD2;
-
- const CXXMethodDecl *OMD = *mi;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
- OGD = GlobalDecl(DD, GD.getDtorType());
- else
- OGD = OMD;
-
- // Check whether this is the method being overridden in this section of
- // the vtable.
- uint64_t Index;
- if (!Methods.getIndex(OGD, Index))
- continue;
-
- OGD2 = OGD;
-
- // Get the original method, which we should be computing thunks, etc,
- // against.
- OGD = Methods.getOrigMethod(Index);
- OMD = cast<CXXMethodDecl>(OGD.getDecl());
-
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- QualType OverriddenReturnType =
- OMD->getType()->getAs<FunctionType>()->getResultType();
-
- // Check if we need a return type adjustment.
- if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
- OMD).isEmpty()) {
- CanQualType &BaseReturnType = BaseReturnTypes[Index];
-
- // Insert the base return type.
- if (BaseReturnType.isNull())
- BaseReturnType =
- CGM.getContext().getCanonicalType(OverriddenReturnType);
- }
-
- Methods.OverrideMethod(OGD, GD);
-
- GlobalDecl UGD = getUnique(GD);
- const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
- assert(UGD.getDecl() && "unique overrider not found");
- assert(UGD == getUnique(OGD) && "unique overrider not unique");
-
- ThisAdjustments.erase(Index);
- if (MorallyVirtual || VCall.count(UMD)) {
-
- Index_t &idx = VCall[UMD];
- if (idx == 0) {
- VCallOffset[GD] = VCallOffset[OGD];
- // NonVirtualOffset[UMD] = CurrentVBaseOffset/8 - OverrideOffset/8;
- NonVirtualOffset[UMD] = VCallOffset[OGD];
- VCallOffsetForVCall[UMD] = OverrideOffset/8;
- idx = VCalls.size()+1;
- VCalls.push_back(OverrideOffset/8 - CurrentVBaseOffset/8);
- D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
- } else {
- VCallOffset[GD] = NonVirtualOffset[UMD];
- VCalls[idx-1] = -VCallOffsetForVCall[UGD] + OverrideOffset/8;
- D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
- }
- int64_t NonVirtualAdjustment = -VCallOffset[OGD];
- QualType DerivedType = MD->getThisType(CGM.getContext());
- QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
- int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
- if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
- NonVirtualAdjustment = NonVirtualAdjustment2;
- }
- int64_t VirtualAdjustment =
- -((idx + extra + 2) * LLVMPointerWidth / 8);
-
- // Optimize out virtual adjustments of 0.
- if (VCalls[idx-1] == 0)
- VirtualAdjustment = 0;
-
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
- VirtualAdjustment);
-
- if (!isPure && !ThisAdjustment.isEmpty()) {
- ThisAdjustments[Index] = ThisAdjustment;
- SavedAdjustments.push_back(
- std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
- }
- return true;
- }
-
- VCallOffset[GD] = VCallOffset[OGD2] - OverrideOffset/8;
-
- int64_t NonVirtualAdjustment = -VCallOffset[GD];
- QualType DerivedType = MD->getThisType(CGM.getContext());
- QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
- int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
- if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
- NonVirtualAdjustment = NonVirtualAdjustment2;
- }
-
- if (NonVirtualAdjustment) {
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
-
- if (!isPure) {
- ThisAdjustments[Index] = ThisAdjustment;
- SavedAdjustments.push_back(
- std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
- }
- }
- return true;
- }
-
- return false;
}
-
-void OldVtableBuilder::AppendMethodsToVtable() {
- if (!BuildVtable) {
- VtableComponents.insert(VtableComponents.end(), Methods.size(),
- (llvm::Constant *)0);
- ThisAdjustments.clear();
- BaseReturnTypes.clear();
- Methods.clear();
- return;
- }
-
- // Reserve room in the vtable for our new methods.
- VtableComponents.reserve(VtableComponents.size() + Methods.size());
-
- for (unsigned i = 0, e = Methods.size(); i != e; ++i) {
- GlobalDecl GD = Methods[i];
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Get the 'this' pointer adjustment.
- ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i);
-
- // Construct the return type adjustment.
- ThunkAdjustment ReturnAdjustment;
-
- QualType BaseReturnType = BaseReturnTypes.lookup(i);
- if (!BaseReturnType.isNull() && !MD->isPure()) {
- QualType DerivedType =
- MD->getType()->getAs<FunctionType>()->getResultType();
-
- int64_t NonVirtualAdjustment =
- getNVOffset(BaseReturnType, DerivedType) / 8;
-
- int64_t VirtualAdjustment =
- getVbaseOffset(BaseReturnType, DerivedType);
-
- ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment,
- VirtualAdjustment);
- }
-
- llvm::Constant *Method = 0;
- if (!ReturnAdjustment.isEmpty()) {
- // Build a covariant thunk.
- CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment);
- Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment));
- } else if (!ThisAdjustment.isEmpty()) {
- // Build a "regular" thunk.
- Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment));
- } else if (MD->isPure()) {
- // We have a pure virtual method.
- Method = getPureVirtualFn();
- } else {
- // We have a good old regular method.
- Method = WrapAddrOf(GD);
- }
-
- // Add the method to the vtable.
- VtableComponents.push_back(Method);
- }
-
- ThisAdjustments.clear();
- BaseReturnTypes.clear();
-
- Methods.clear();
}
-void CGVtableInfo::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
@@ -3481,7 +2479,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
NumVirtualFunctionPointers[RD] = CurrentIndex;
}
-uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
NumVirtualFunctionPointers.find(RD);
if (I != NumVirtualFunctionPointers.end())
@@ -3494,7 +2492,7 @@ uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
return I->second;
}
-uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) {
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
@@ -3508,36 +2506,8 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
return I->second;
}
-CGVtableInfo::AdjustmentVectorTy*
-CGVtableInfo::getAdjustments(GlobalDecl GD) {
- SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD);
- if (I != SavedAdjustments.end())
- return &I->second;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext());
- if (!SavedAdjustmentRecords.insert(RD).second)
- return 0;
-
- AddressPointsMapTy AddressPoints;
- OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- b.GenerateVtableForBase(RD);
- b.GenerateVtableForVBases(RD);
-
- for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator
- i = b.getSavedAdjustments().begin(),
- e = b.getSavedAdjustments().end(); i != e; i++)
- SavedAdjustments[i->first].push_back(i->second);
-
- I = SavedAdjustments.find(GD);
- if (I != SavedAdjustments.end())
- return &I->second;
-
- return 0;
-}
-
-int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
VirtualBaseClassOffsetOffsetsMapTy::iterator I =
@@ -3549,7 +2519,6 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
BaseSubobject(RD, 0),
/*BaseIsVirtual=*/false,
/*OffsetInLayoutClass=*/0);
-
for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
Builder.getVBaseOffsetOffsets().begin(),
@@ -3573,128 +2542,588 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
return I->second;
}
-uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) {
- uint64_t AddressPoint =
- (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
-
+uint64_t
+CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) {
+ uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base));
+ assert(AddressPoint && "Address point must not be zero!");
+
return AddressPoint;
}
-llvm::GlobalVariable *
-CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition,
- const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset,
- bool IsVirtual,
- AddressPointsMapTy& AddressPoints) {
- if (GenerateDefinition) {
- if (LayoutClass == RD) {
- assert(!IsVirtual &&
- "Can only have a virtual base in construction vtables!");
- assert(!Offset &&
- "Can only have a base offset in construction vtables!");
- }
+llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Compute the mangled name.
+ llvm::SmallString<256> Name;
+ if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
+ getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This,
+ Name);
+ else
+ getMangleContext().mangleThunk(MD, Thunk, Name);
+
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ int64_t NonVirtualAdjustment,
+ int64_t VirtualAdjustment) {
+ if (!NonVirtualAdjustment && !VirtualAdjustment)
+ return Ptr;
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+
+ llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
+
+ if (NonVirtualAdjustment) {
+ // Do the non-virtual adjustment.
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+ }
+
+ if (VirtualAdjustment) {
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ // Do the virtual adjustment.
+ llvm::Value *VTablePtrPtr =
+ CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
+
+ llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
+
+ llvm::Value *OffsetPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+
+ OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
+
+ // Load the adjustment offset from the vtable.
+ llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
- VtableBuilder Builder(*this, RD, Offset,
- /*MostDerivedClassIsVirtual=*/IsVirtual,
- LayoutClass);
+ // Adjust our pointer.
+ V = CGF.Builder.CreateInBoundsGEP(V, Offset);
+ }
+
+ // Cast back to the original type.
+ return CGF.Builder.CreateBitCast(V, Ptr->getType());
+}
+
+void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+ QualType ThisType = MD->getThisType(getContext());
- if (CGM.getLangOptions().DumpVtableLayouts)
- Builder.dumpLayout(llvm::errs());
+ FunctionArgList FunctionArgs;
+
+ // FIXME: It would be nice if more of this code could be shared with
+ // CodeGenFunction::GenerateCode.
+
+ // Create the implicit 'this' parameter declaration.
+ CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0,
+ MD->getLocation(),
+ &getContext().Idents.get("this"),
+ ThisType);
+
+ // Add the 'this' parameter.
+ FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
+
+ // Add the rest of the parameters.
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ ParmVarDecl *Param = *I;
+
+ FunctionArgs.push_back(std::make_pair(Param, Param->getType()));
}
+
+ StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation());
- llvm::SmallString<256> OutName;
- if (LayoutClass != RD)
- CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
- RD, OutName);
- else
- CGM.getMangleContext().mangleCXXVtable(RD, OutName);
- llvm::StringRef Name = OutName.str();
+ // Adjust the 'this' pointer if necessary.
+ llvm::Value *AdjustedThisPtr =
+ PerformTypeAdjustment(*this, LoadCXXThis(),
+ Thunk.This.NonVirtual,
+ Thunk.This.VCallOffsetOffset);
+
+ CallArgList CallArgs;
+
+ // Add our adjusted 'this' pointer.
+ CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType));
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
- GV->isDeclaration()) {
- OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
- AddressPoints);
+ // Add the rest of the parameters.
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ ParmVarDecl *Param = *I;
+ QualType ArgType = Param->getType();
+
+ // FIXME: Declaring a DeclRefExpr on the stack is kinda icky.
+ DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation());
+ CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType));
+ }
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- // First comes the vtables for all the non-virtual bases...
- b.GenerateVtableForBase(RD, Offset);
+ // Get our callee.
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
- // then the vtables for all the virtual bases.
- b.GenerateVtableForVBases(RD, Offset);
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
+ FPT->getExtInfo());
+
+ // Now emit our call.
+ RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD);
+
+ if (!Thunk.Return.isEmpty()) {
+ // Emit the return adjustment.
+ bool NullCheckValue = !ResultType->isReferenceType();
+
+ llvm::BasicBlock *AdjustNull = 0;
+ llvm::BasicBlock *AdjustNotNull = 0;
+ llvm::BasicBlock *AdjustEnd = 0;
+
+ llvm::Value *ReturnValue = RV.getScalarVal();
- llvm::Constant *Init = 0;
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size());
-
- if (GenerateDefinition)
- Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0],
- b.getVtableComponents().size());
-
- llvm::GlobalVariable *OGV = GV;
-
- GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType,
- /*isConstant=*/true, Linkage, Init, Name);
- CGM.setGlobalVisibility(GV, RD);
-
- if (OGV) {
- GV->takeName(OGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OGV->getType());
- OGV->replaceAllUsesWith(NewPtr);
- OGV->eraseFromParent();
+ if (NullCheckValue) {
+ AdjustNull = createBasicBlock("adjust.null");
+ AdjustNotNull = createBasicBlock("adjust.notnull");
+ AdjustEnd = createBasicBlock("adjust.end");
+
+ llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue);
+ Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
+ EmitBlock(AdjustNotNull);
+ }
+
+ ReturnValue = PerformTypeAdjustment(*this, ReturnValue,
+ Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ if (NullCheckValue) {
+ Builder.CreateBr(AdjustEnd);
+ EmitBlock(AdjustNull);
+ Builder.CreateBr(AdjustEnd);
+ EmitBlock(AdjustEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(ReturnValue, AdjustNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
+ AdjustNull);
+ ReturnValue = PHI;
}
+
+ RV = RValue::get(ReturnValue);
}
+
+ if (!ResultType->isVoidType())
+ EmitReturnOfRValue(RV, ResultType);
+
+ FinishFunction();
+
+ // Destroy the 'this' declaration.
+ CXXThisDecl->Destroy(getContext());
- return GV;
+ // Set the right linkage.
+ Fn->setLinkage(CGM.getFunctionLinkage(MD));
+
+ // Set the right visibility.
+ CGM.setGlobalVisibility(Fn, MD);
}
-void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&Vtable = Vtables[RD];
- if (Vtable) {
- assert(Vtable->getInitializer() && "Vtable doesn't have a definition!");
+void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
+{
+ llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Strip off a bitcast if we got one back.
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ assert(CE->getOpcode() == llvm::Instruction::BitCast);
+ Entry = CE->getOperand(0);
+ }
+
+ // 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)) {
+ llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry);
+
+ // If the types mismatch then we have to rewrite the definition.
+ assert(OldThunkFn->isDeclaration() &&
+ "Shouldn't replace non-declaration");
+
+ // Remove the name from the old thunk function and get a new thunk.
+ OldThunkFn->setName(llvm::StringRef());
+ Entry = CGM.GetAddrOfThunk(GD, Thunk);
+
+ // If needed, replace the old thunk with a bitcast.
+ if (!OldThunkFn->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType());
+ OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl);
+ }
+
+ // Remove the old thunk.
+ OldThunkFn->eraseFromParent();
+ }
+
+ // Actually generate the thunk body.
+ llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+ CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk);
+}
+
+void CodeGenVTables::EmitThunks(GlobalDecl GD)
+{
+ const CXXMethodDecl *MD =
+ cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl();
+
+ // We don't need to generate thunks for the base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return;
+
+ const CXXRecordDecl *RD = MD->getParent();
+
+ // Compute VTable related info for this class.
+ ComputeVTableRelatedInformation(RD);
+
+ ThunksMapTy::const_iterator I = Thunks.find(MD);
+ if (I == Thunks.end()) {
+ // We did not find a thunk for this method.
return;
}
+
+ const ThunkInfoVectorTy &ThunkInfoVector = I->second;
+ for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
+ EmitThunk(GD, ThunkInfoVector[I]);
+}
+
+void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+ uint64_t *&LayoutData = VTableLayoutMap[RD];
- AddressPointsMapTy AddressPoints;
- Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0,
- /*IsVirtual=*/false,
- AddressPoints);
- GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+ // Check if we've computed this information before.
+ if (LayoutData)
+ return;
+
+ VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- if (!(*i)->isVirtual())
- continue;
- if(!(*i)->hasInlineBody() && !(*i)->isImplicit())
- continue;
+ // Add the VTable layout.
+ uint64_t NumVTableComponents = Builder.getNumVTableComponents();
+ LayoutData = new uint64_t[NumVTableComponents + 1];
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) {
- CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete));
- CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting));
- } else {
- CGM.BuildThunksForVirtual(GlobalDecl(*i));
+ // Store the number of components.
+ LayoutData[0] = NumVTableComponents;
+
+ // Store the components.
+ std::copy(Builder.vtable_components_data_begin(),
+ Builder.vtable_components_data_end(),
+ &LayoutData[1]);
+
+ // Add the known thunks.
+ Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+
+ // Add the thunks needed in this vtable.
+ assert(!VTableThunksMap.count(RD) &&
+ "Thunks already exists for this vtable!");
+
+ VTableThunksTy &VTableThunks = VTableThunksMap[RD];
+ VTableThunks.append(Builder.vtable_thunks_begin(),
+ Builder.vtable_thunks_end());
+
+ // Sort them.
+ std::sort(VTableThunks.begin(), VTableThunks.end());
+
+ // Add the address points.
+ for (VtableBuilder::AddressPointsMapTy::const_iterator I =
+ Builder.address_points_begin(), E = Builder.address_points_end();
+ I != E; ++I) {
+
+ uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)];
+
+ // Check if we already have the address points for this base.
+ assert(!AddressPoint && "Address point already exists for this base!");
+
+ AddressPoint = I->second;
+ }
+
+ // If we don't have the vbase information for this class, insert it.
+ // getVirtualBaseOffsetOffset will compute it separately without computing
+ // the rest of the vtable related information.
+ if (!RD->getNumVBases())
+ return;
+
+ const RecordType *VBaseRT =
+ RD->vbases_begin()->getType()->getAs<RecordType>();
+ const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+
+ if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
+ return;
+
+ for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+ // Insert all types.
+ ClassPairTy ClassPair(RD, I->first);
+
+ VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+ }
+}
+
+llvm::Constant *
+CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
+ const uint64_t *Components,
+ unsigned NumComponents,
+ const VTableThunksTy &VTableThunks) {
+ llvm::SmallVector<llvm::Constant *, 64> Inits;
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+
+ const llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ QualType ClassType = CGM.getContext().getTagDeclType(RD);
+ llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType);
+
+ unsigned NextVTableThunkIndex = 0;
+
+ llvm::Constant* PureVirtualFn = 0;
+
+ for (unsigned I = 0; I != NumComponents; ++I) {
+ VtableComponent Component =
+ VtableComponent::getFromOpaqueInteger(Components[I]);
+
+ llvm::Constant *Init = 0;
+
+ switch (Component.getKind()) {
+ case VtableComponent::CK_VCallOffset:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_VBaseOffset:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_OffsetToTop:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_RTTI:
+ Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy);
+ break;
+ 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:
+ GD = Component.getFunctionDecl();
+ break;
+ case VtableComponent::CK_CompleteDtorPointer:
+ GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
+ break;
+ case VtableComponent::CK_DeletingDtorPointer:
+ GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
+ break;
+ }
+
+ if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
+ // We have a pure virtual member function.
+ if (!PureVirtualFn) {
+ const llvm::FunctionType *Ty =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
+ /*isVarArg=*/false);
+ PureVirtualFn =
+ CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual");
+ PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
+ Int8PtrTy);
+ }
+
+ Init = PureVirtualFn;
+ } else {
+ // Check if we should use a thunk.
+ if (NextVTableThunkIndex < VTableThunks.size() &&
+ VTableThunks[NextVTableThunkIndex].first == I) {
+ const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
+
+ Init = CGM.GetAddrOfThunk(GD, Thunk);
+
+ NextVTableThunkIndex++;
+ } else {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
+
+ Init = CGM.GetAddrOfFunction(GD, Ty);
+ }
+
+ Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+ }
+ break;
+ }
+
+ case VtableComponent::CK_UnusedFunctionPointer:
+ Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
+ break;
+ };
+
+ Inits.push_back(Init);
+ }
+
+ llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents);
+ return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size());
+}
+
+/// GetGlobalVariable - Will return a global variable of the given type.
+/// If a variable with a different type already exists then a new variable
+/// with the right type will be created.
+/// FIXME: We should move this to CodeGenModule and rename it to something
+/// better and then use it in CGVTT and CGRTTI.
+static llvm::GlobalVariable *
+GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name,
+ const llvm::Type *Ty,
+ llvm::GlobalValue::LinkageTypes Linkage) {
+
+ llvm::GlobalVariable *GV = Module.getNamedGlobal(Name);
+ llvm::GlobalVariable *OldGV = 0;
+
+ if (GV) {
+ // Check if the variable has the right type.
+ if (GV->getType()->getElementType() == Ty)
+ return GV;
+
+ assert(GV->isDeclaration() && "Declaration has wrong type!");
+
+ OldGV = GV;
+ }
+
+ // Create a new variable.
+ GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true,
+ Linkage, 0, Name);
+
+ if (OldGV) {
+ // Replace occurrences of the old variable if needed.
+ GV->takeName(OldGV);
+
+ if (!OldGV->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtrForOldDecl);
}
+
+ OldGV->eraseFromParent();
}
+
+ return GV;
}
-llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
- llvm::GlobalVariable *Vtable = Vtables.lookup(RD);
+llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXVtable(RD, OutName);
+ llvm::StringRef Name = OutName.str();
+
+ ComputeVTableRelatedInformation(RD);
- if (!Vtable) {
- AddressPointsMapTy AddressPoints;
- Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage,
- /*GenerateDefinition=*/false, RD, RD, 0,
- /*IsVirtual=*/false, AddressPoints);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD));
+
+ return GetGlobalVariable(CGM.getModule(), Name, ArrayType,
+ llvm::GlobalValue::ExternalLinkage);
+}
+
+void
+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);
+
+ Builder.dumpLayout(llvm::errs());
}
- return Vtable;
+ assert(VTableThunksMap.count(RD) &&
+ "No thunk status for this record decl!");
+
+ const VTableThunksTy& Thunks = VTableThunksMap[RD];
+
+ // Create and set the initializer.
+ llvm::Constant *Init =
+ CreateVTableInitializer(RD, getVTableComponentsData(RD),
+ getNumVTableComponents(RD), Thunks);
+ VTable->setInitializer(Init);
+
+ // Set the correct linkage.
+ VTable->setLinkage(Linkage);
}
-void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
+llvm::GlobalVariable *
+CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base,
+ bool BaseIsVirtual,
+ VTableAddressPointsMapTy& AddressPoints) {
+ VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
+ /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
+
+ // Dump the vtable layout if necessary.
+ if (CGM.getLangOptions().DumpVtableLayouts)
+ Builder.dumpLayout(llvm::errs());
+
+ // Add the address points.
+ AddressPoints.insert(Builder.address_points_begin(),
+ Builder.address_points_end());
+
+ // Get the mangled construction vtable name.
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8,
+ Base.getBase(), OutName);
+ llvm::StringRef Name = OutName.str();
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents());
+
+ // Create the variable that will hold the construction vtable.
+ llvm::GlobalVariable *VTable =
+ GetGlobalVariable(CGM.getModule(), Name, ArrayType,
+ llvm::GlobalValue::InternalLinkage);
+
+ // Add the thunks.
+ VTableThunksTy VTableThunks;
+ VTableThunks.append(Builder.vtable_thunks_begin(),
+ Builder.vtable_thunks_end());
+
+ // Sort them.
+ std::sort(VTableThunks.begin(), VTableThunks.end());
+
+ // Create and set the initializer.
+ llvm::Constant *Init =
+ CreateVTableInitializer(Base.getBase(),
+ Builder.vtable_components_data_begin(),
+ Builder.getNumVTableComponents(), VTableThunks);
+ VTable->setInitializer(Init);
+
+ return VTable;
+}
+
+void
+CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *&VTable = Vtables[RD];
+ if (VTable) {
+ assert(VTable->getInitializer() && "Vtable doesn't have a definition!");
+ return;
+ }
+
+ VTable = GetAddrOfVTable(RD);
+ EmitVTableDefinition(VTable, Linkage, RD);
+
+ GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+}
+
+void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
@@ -3702,20 +3131,34 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
if (!RD->isDynamicClass())
return;
+ // Check if we need to emit thunks for this function.
+ if (MD->isVirtual())
+ EmitThunks(GD);
+
// Get the key function.
const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
+ TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind();
+ TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind();
+
if (KeyFunction) {
// We don't have the right key function.
if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
+ } else {
+ // If this is an explicit instantiation of a method, we don't need a vtable.
+ // Since we have no key function, we will emit the vtable when we see
+ // a use, and just defining a function is not an use.
+ if ((RDKind == TSK_ImplicitInstantiation ||
+ RDKind == TSK_ExplicitInstantiationDeclaration) &&
+ MDKind == TSK_ExplicitInstantiationDefinition)
+ return;
}
if (Vtables.count(RD))
return;
- TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
+ if (RDKind == TSK_ImplicitInstantiation)
CGM.DeferredVtables.push_back(RD);
else
GenerateClassData(CGM.getVtableLinkage(RD), RD);
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 5a146ab97c99..60735554d56e 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -15,7 +15,6 @@
#define CLANG_CODEGEN_CGVTABLE_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/GlobalVariable.h"
#include "GlobalDecl.h"
@@ -25,41 +24,93 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
-/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks.
-class ThunkAdjustment {
-public:
- ThunkAdjustment(int64_t NonVirtual, int64_t Virtual)
- : NonVirtual(NonVirtual),
- Virtual(Virtual) { }
-
- ThunkAdjustment()
- : NonVirtual(0), Virtual(0) { }
+/// ReturnAdjustment - A return adjustment.
+struct ReturnAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// VBaseOffsetOffset - The offset (in bytes), relative to the address point
+ /// of the virtual base class offset.
+ int64_t VBaseOffsetOffset;
+
+ ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
- // isEmpty - Return whether this thunk adjustment is empty.
- bool isEmpty() const {
- return NonVirtual == 0 && Virtual == 0;
+ friend bool operator==(const ReturnAdjustment &LHS,
+ const ReturnAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
}
- /// NonVirtual - The non-virtual adjustment.
+ friend bool operator<(const ReturnAdjustment &LHS,
+ const ReturnAdjustment &RHS) {
+ if (LHS.NonVirtual < RHS.NonVirtual)
+ return true;
+
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
+ }
+};
+
+/// ThisAdjustment - A 'this' pointer adjustment.
+struct ThisAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
int64_t NonVirtual;
- /// Virtual - The virtual adjustment.
- int64_t Virtual;
+ /// VCallOffsetOffset - The offset (in bytes), relative to the address point,
+ /// of the virtual call offset.
+ int64_t VCallOffsetOffset;
+
+ ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
+
+ friend bool operator==(const ThisAdjustment &LHS,
+ const ThisAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
+ }
+
+ friend bool operator<(const ThisAdjustment &LHS,
+ const ThisAdjustment &RHS) {
+ if (LHS.NonVirtual < RHS.NonVirtual)
+ return true;
+
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VCallOffsetOffset < RHS.VCallOffsetOffset;
+ }
};
-/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the
-/// return pointer for covariant thunks.
-class CovariantThunkAdjustment {
-public:
- CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment,
- const ThunkAdjustment &ReturnAdjustment)
- : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { }
+/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
+/// adjustment for a thunk.
+struct ThunkInfo {
+ /// This - The 'this' pointer adjustment.
+ ThisAdjustment This;
+
+ /// Return - The return adjustment.
+ ReturnAdjustment Return;
- CovariantThunkAdjustment() { }
+ ThunkInfo() { }
- ThunkAdjustment ThisAdjustment;
- ThunkAdjustment ReturnAdjustment;
-};
+ ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
+ : This(This), Return(Return) { }
+
+ friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ return LHS.This == RHS.This && LHS.Return == RHS.Return;
+ }
+
+ friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ if (LHS.This < RHS.This)
+ return true;
+
+ return LHS.This == RHS.This && LHS.Return < RHS.Return;
+ }
+
+ bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+};
// BaseSubobject - Uniquely identifies a direct or indirect base class.
// Stores both the base class decl and the offset from the most derived class to
@@ -126,19 +177,7 @@ template <> struct isPodLike<clang::CodeGen::BaseSubobject> {
namespace clang {
namespace CodeGen {
-class CGVtableInfo {
-public:
- typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> >
- AdjustmentVectorTy;
-
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t;
- typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t;
- llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
-
- typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
-
-private:
+class CodeGenVTables {
CodeGenModule &CGM;
/// MethodVtableIndices - Contains the index (relative to the vtable address
@@ -163,31 +202,97 @@ private:
/// pointers in the vtable for a given record decl.
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
- typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy;
- SavedAdjustmentsTy SavedAdjustments;
- llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+ typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - Contains all thunks that a given method decl will need.
+ ThunksMapTy Thunks;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t *> VTableLayoutMapTy;
+
+ /// VTableLayoutMap - Stores the vtable layout for all record decls.
+ /// The layout is stored as an array of 64-bit integers, where the first
+ /// integer is the number of vtable entries in the layout, and the subsequent
+ /// integers are the vtable components.
+ VTableLayoutMapTy VTableLayoutMap;
+
+ typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
+ BaseSubobject>, uint64_t> AddressPointsMapTy;
+
+ /// Address points - Address points for all vtables.
+ AddressPointsMapTy AddressPoints;
+
+ /// VTableAddressPointsMapTy - Address points for a single vtable.
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
+
+ typedef llvm::SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
+ VTableThunksTy;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, VTableThunksTy>
+ VTableThunksMapTy;
+
+ /// VTableThunksMap - Contains thunks needed by vtables.
+ VTableThunksMapTy VTableThunksMap;
+
+ uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const {
+ assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
+
+ return VTableLayoutMap.lookup(RD)[0];
+ }
+
+ const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const {
+ assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
+
+ uint64_t *Components = VTableLayoutMap.lookup(RD);
+ return &Components[1];
+ }
+
+ typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy;
+
+ /// SubVTTIndicies - Contains indices into the various sub-VTTs.
+ SubVTTIndiciesMapTy SubVTTIndicies;
+
+
+ typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
+ BaseSubobject>, uint64_t>
+ SecondaryVirtualPointerIndicesMapTy;
- typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
- SubVTTIndiciesTy SubVTTIndicies;
+ /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
+ /// indices.
+ SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
-
- llvm::GlobalVariable *
- GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition, const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset, bool IsVirtual,
- AddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
const CXXRecordDecl *RD);
+ /// EmitThunk - Emit a single thunk.
+ void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk);
+
+ /// EmitThunks - Emit the associated thunks for the given global decl.
+ void EmitThunks(GlobalDecl GD);
+
+ /// ComputeVTableRelatedInformation - Compute and store all vtable related
+ /// information (vtable layout, vbase offset offsets, thunks etc) for the
+ /// given record decl.
+ void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
+
+ /// CreateVTableInitializer - Create a vtable initializer for the given record
+ /// decl.
+ /// \param Components - The vtable components; this is really an array of
+ /// VTableComponents.
+ llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
+ const uint64_t *Components,
+ unsigned NumComponents,
+ const VTableThunksTy &VTableThunks);
+
public:
- CGVtableInfo(CodeGenModule &CGM)
+ CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM) { }
/// needsVTTParameter - Return whether the given global decl needs a VTT
@@ -199,6 +304,11 @@ public:
/// given record decl.
uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *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
/// point) where the function pointer for the given virtual function is
/// stored.
@@ -212,35 +322,32 @@ public:
int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
- AdjustmentVectorTy *getAdjustments(GlobalDecl GD);
-
- /// getVtableAddressPoint - returns the address point of the vtable for the
- /// given record decl.
- /// FIXME: This should return a list of address points.
- uint64_t getVtableAddressPoint(const CXXRecordDecl *RD);
-
- llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD);
-
- /// CtorVtableInfo - Information about a constructor vtable.
- struct CtorVtableInfo {
- /// Vtable - The vtable itself.
- llvm::GlobalVariable *Vtable;
+ /// getAddressPoint - Get the address point of the given subobject in the
+ /// class decl.
+ uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD);
- /// AddressPoints - The address points in this constructor vtable.
- AddressPointsMapTy AddressPoints;
-
- CtorVtableInfo() : Vtable(0) { }
- };
+ /// GetAddrOfVTable - Get the address of the vtable for the given record decl.
+ llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD);
+
+ /// EmitVTableDefinition - Emit the definition of the given vtable.
+ void EmitVTableDefinition(llvm::GlobalVariable *VTable,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD);
- CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD,
- const BaseSubobject &Base,
- bool BaseIsVirtual);
+ /// GenerateConstructionVTable - Generate a construction vtable for the given
+ /// base subobject.
+ llvm::GlobalVariable *
+ GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base,
+ bool BaseIsVirtual,
+ VTableAddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
- void MaybeEmitVtable(GlobalDecl GD);
+ // EmitVTableRelatedData - Will emit any thunks that the global decl might
+ // have, as well as the vtable itself if the global decl is the key function.
+ void EmitVTableRelatedData(GlobalDecl GD);
- /// GenerateClassData - Generate all the class data requires to be generated
+ /// GenerateClassData - Generate all the class data required to be generated
/// upon definition of a KeyFunction. This includes the vtable, the
/// rtti data structure and the VTT.
///
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f45582705618..b863aff23612 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -199,8 +199,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0,
false, false, 0, 0,
- /*FIXME?*/false,
- /*FIXME?*/CC_Default);
+ /*FIXME?*/
+ FunctionType::ExtInfo());
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
@@ -211,7 +211,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// FIXME: Leaked.
// CC info is ignored, hopefully?
CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
- CC_Default, false);
+ FunctionType::ExtInfo());
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -279,7 +279,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
// Check if we need a VTT parameter as well.
- if (CGVtableInfo::needsVTTParameter(GD)) {
+ if (CodeGenVTables::needsVTTParameter(GD)) {
// FIXME: The comment about using a fake decl above applies here too.
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
CXXVTTDecl =
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index bd12c4a87c29..f21350d0f2d9 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -22,7 +22,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
-#include <map>
#include "CodeGenModule.h"
#include "CGBlocks.h"
#include "CGBuilder.h"
@@ -254,6 +253,27 @@ public:
}
};
+ /// CXXTemporariesCleanupScope - Enters a new scope for catching live
+ /// temporaries, all of which will be popped once the scope is exited.
+ class CXXTemporariesCleanupScope {
+ CodeGenFunction &CGF;
+ size_t NumLiveTemporaries;
+
+ // DO NOT IMPLEMENT
+ CXXTemporariesCleanupScope(const CXXTemporariesCleanupScope &);
+ CXXTemporariesCleanupScope &operator=(const CXXTemporariesCleanupScope &);
+
+ public:
+ explicit CXXTemporariesCleanupScope(CodeGenFunction &CGF)
+ : CGF(CGF), NumLiveTemporaries(CGF.LiveTemporaries.size()) { }
+
+ ~CXXTemporariesCleanupScope() {
+ while (CGF.LiveTemporaries.size() > NumLiveTemporaries)
+ CGF.PopCXXTemporary();
+ }
+ };
+
+
/// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup
/// blocks that have been added.
void EmitCleanupBlocks(size_t OldCleanupStackSize);
@@ -504,30 +524,29 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
- /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an
- /// object pointer to alter the dynamic type of the pointer. Used by
- /// GenerateCovariantThunk for building thunks.
- llvm::Value *DynamicTypeAdjust(llvm::Value *V,
- const ThunkAdjustment &Adjustment);
-
- /// GenerateThunk - Generate a thunk for the given method
- llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const ThunkAdjustment &ThisAdjustment);
- llvm::Constant *
- GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const CovariantThunkAdjustment &Adjustment);
-
+ /// GenerateThunk - Generate a thunk for the given method.
+ void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk);
+
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
- void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl);
+ /// 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,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass);
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+ void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ bool BaseIsNonVirtualPrimaryBase,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy& VBases);
+
+ void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
- void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CGVtableInfo::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset);
void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
void SynthesizeCXXCopyAssignment(const FunctionArgList &Args);
@@ -1272,6 +1291,10 @@ public:
/// getTrapBB - Create a basic block that will call the trap intrinsic. We'll
/// generate a branch around the created basic block as necessary.
llvm::BasicBlock* getTrapBB();
+
+ /// EmitCallArg - Emit a single call argument.
+ RValue EmitCallArg(const Expr *E, QualType ArgType);
+
private:
void EmitReturnOfRValue(RValue RV, QualType Ty);
@@ -1303,9 +1326,6 @@ private:
/// current cleanup scope.
void AddBranchFixup(llvm::BranchInst *BI);
- /// EmitCallArg - Emit a single call argument.
- RValue EmitCallArg(const Expr *E, QualType ArgType);
-
/// EmitCallArgs - Emit call arguments for a function.
/// The CallArgTypeInfo parameter is used for iterating over the known
/// argument types of the function being called.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index b4b5bbdb99aa..3c872c8560d2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -47,7 +47,7 @@ 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), VtableInfo(*this), Runtime(0),
+ MangleCtx(C), VTables(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
VMContext(M.getContext()) {
@@ -79,6 +79,7 @@ void CodeGenModule::createObjCRuntime() {
}
void CodeGenModule::Release() {
+ EmitFundamentalRTTIDescriptors();
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
@@ -495,7 +496,7 @@ void CodeGenModule::EmitDeferred() {
if (!DeferredVtables.empty()) {
const CXXRecordDecl *RD = DeferredVtables.back();
DeferredVtables.pop_back();
- getVtableInfo().GenerateClassData(getVtableLinkage(RD), RD);
+ getVTables().GenerateClassData(getVtableLinkage(RD), RD);
continue;
}
@@ -714,20 +715,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- getVtableInfo().MaybeEmitVtable(GD);
- if (MD->isVirtual() && MD->isOutOfLine() &&
- (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) {
- if (isa<CXXDestructorDecl>(D)) {
- GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()),
- GD.getDtorType());
- BuildThunksForVirtual(CanonGD);
- } else {
- BuildThunksForVirtual(MD->getCanonicalDecl());
- }
- }
- }
-
+ if (isa<CXXMethodDecl>(D))
+ getVTables().EmitVTableRelatedData(GD);
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
@@ -758,7 +748,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
if (WeakRefReferences.count(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
if (FD && !FD->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
+ Entry->setLinkage(llvm::Function::ExternalLinkage);
WeakRefReferences.erase(Entry);
}
@@ -873,7 +863,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
if (Entry) {
if (WeakRefReferences.count(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
+ Entry->setLinkage(llvm::Function::ExternalLinkage);
WeakRefReferences.erase(Entry);
}
@@ -1255,9 +1245,9 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
if (!CI->use_empty())
CI->replaceAllUsesWith(NewCall);
- // Copy any custom metadata attached with CI.
- if (llvm::MDNode *DbgNode = CI->getMetadata("dbg"))
- NewCall->setMetadata("dbg", DbgNode);
+ // Copy debug location attached to CI.
+ if (!CI->getDebugLoc().isUnknown())
+ NewCall->setDebugLoc(CI->getDebugLoc());
CI->eraseFromParent();
}
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index febb8560367b..3c57c0b8cbfc 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -31,7 +31,6 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ValueHandle.h"
-#include <list>
namespace llvm {
class Module;
@@ -93,8 +92,8 @@ class CodeGenModule : public BlockModule {
CodeGenTypes Types;
MangleContext MangleCtx;
- /// VtableInfo - Holds information about C++ vtables.
- CGVtableInfo VtableInfo;
+ /// VTables - Holds information about C++ vtables.
+ CodeGenVTables VTables;
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
@@ -181,7 +180,7 @@ public:
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
MangleContext &getMangleContext() { return MangleCtx; }
- CGVtableInfo &getVtableInfo() { return VtableInfo; }
+ CodeGenVTables &getVTables() { return VTables; }
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getT