From 8aaf5818a64e9f7687798852af5945b053c68a54 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Tue, 4 May 2010 16:12:48 +0000 Subject: Update clang to r103004. --- CMakeLists.txt | 21 + Makefile | 27 - VER | 2 +- bindings/python/README.txt | 5 +- bindings/python/clang/cindex.py | 6 +- clang.xcodeproj/project.pbxproj | 343 ++- docs/Block-ABI-Apple.txt | 11 +- docs/InternalsManual.html | 12 +- docs/LanguageExtensions.html | 43 +- docs/UsersManual.html | 6 + examples/clang-interpreter/main.cpp | 8 +- include/Makefile | 2 +- include/clang-c/Index.h | 37 +- include/clang-c/Makefile | 31 + include/clang/AST/APValue.h | 8 +- include/clang/AST/ASTContext.h | 48 +- include/clang/AST/ASTVector.h | 397 +++ include/clang/AST/CanonicalType.h | 1 + include/clang/AST/Decl.h | 96 +- include/clang/AST/DeclAccessPair.h | 72 + include/clang/AST/DeclBase.h | 99 +- include/clang/AST/DeclCXX.h | 40 +- include/clang/AST/DeclContextInternals.h | 4 +- include/clang/AST/DeclFriend.h | 10 +- include/clang/AST/DeclNodes.def | 8 +- include/clang/AST/DeclObjC.h | 75 +- include/clang/AST/DeclTemplate.h | 109 +- include/clang/AST/DeclarationName.h | 11 +- include/clang/AST/DependentDiagnostic.h | 9 + include/clang/AST/Expr.h | 331 +- include/clang/AST/ExprCXX.h | 104 +- include/clang/AST/ExprObjC.h | 485 ++- include/clang/AST/ExternalASTSource.h | 7 + include/clang/AST/Stmt.h | 8 +- include/clang/AST/StmtNodes.def | 3 +- include/clang/AST/StmtObjC.h | 137 +- include/clang/AST/TemplateName.h | 6 + include/clang/AST/Type.h | 84 +- include/clang/AST/TypeNodes.def | 4 +- include/clang/AST/UnresolvedSet.h | 51 +- include/clang/AST/UsuallyTinyPtrVector.h | 105 + include/clang/Analysis/Support/Optional.h | 66 - include/clang/Basic/Builtins.def | 12 +- include/clang/Basic/BuiltinsPPC.def | 92 +- include/clang/Basic/BuiltinsX86.def | 2 +- include/clang/Basic/Diagnostic.h | 49 +- include/clang/Basic/DiagnosticCommonKinds.td | 10 +- include/clang/Basic/DiagnosticDriverKinds.td | 2 + include/clang/Basic/DiagnosticFrontendKinds.td | 19 +- include/clang/Basic/DiagnosticGroups.td | 13 +- include/clang/Basic/DiagnosticParseKinds.td | 4 +- include/clang/Basic/DiagnosticSemaKinds.td | 319 +- include/clang/Basic/LangOptions.h | 19 +- include/clang/Basic/SourceLocation.h | 11 +- include/clang/Basic/SourceManager.h | 19 +- include/clang/Basic/TargetInfo.h | 34 + include/clang/Basic/Version.h | 4 +- include/clang/Checker/BugReporter/BugReporter.h | 1 - .../clang/Checker/PathSensitive/AnalysisManager.h | 8 +- include/clang/Checker/PathSensitive/GRCoreEngine.h | 27 +- include/clang/Checker/PathSensitive/GRExprEngine.h | 24 + include/clang/Checker/PathSensitive/MemRegion.h | 6 +- include/clang/Checker/PathSensitive/Store.h | 3 + include/clang/Checker/PathSensitive/ValueManager.h | 6 + include/clang/CodeGen/CodeGenOptions.h | 19 +- include/clang/Driver/CC1Options.td | 40 +- include/clang/Driver/Options.td | 14 +- include/clang/Driver/Tool.h | 4 + include/clang/Driver/ToolChain.h | 7 + include/clang/Frontend/ASTConsumers.h | 4 - include/clang/Frontend/Analyses.def | 25 +- include/clang/Frontend/AnalysisConsumer.h | 1 + include/clang/Frontend/DiagnosticOptions.h | 5 + include/clang/Frontend/FixItRewriter.h | 59 +- include/clang/Frontend/FrontendActions.h | 8 +- include/clang/Frontend/FrontendOptions.h | 9 +- include/clang/Frontend/PCHBitCodes.h | 6 +- include/clang/Frontend/PCHReader.h | 5 +- include/clang/Frontend/StmtXML.def | 9 +- include/clang/Frontend/TextDiagnosticPrinter.h | 2 +- include/clang/Frontend/VerifyDiagnosticsClient.h | 19 +- include/clang/Lex/PPCallbacks.h | 15 + include/clang/Lex/Preprocessor.h | 10 +- include/clang/Lex/TokenConcatenation.h | 4 +- include/clang/Makefile | 27 + include/clang/Parse/Action.h | 284 +- include/clang/Parse/AttributeList.h | 4 + include/clang/Parse/DeclSpec.h | 35 +- include/clang/Parse/Parser.h | 62 +- include/clang/Parse/Scope.h | 41 +- include/clang/Rewrite/Rewriter.h | 30 +- lib/AST/APValue.cpp | 3 +- lib/AST/ASTContext.cpp | 211 +- lib/AST/ASTDiagnostic.cpp | 6 - lib/AST/ASTImporter.cpp | 28 +- lib/AST/Decl.cpp | 193 +- lib/AST/DeclBase.cpp | 38 +- lib/AST/DeclCXX.cpp | 48 +- lib/AST/DeclObjC.cpp | 18 +- lib/AST/DeclPrinter.cpp | 69 +- lib/AST/DeclTemplate.cpp | 22 +- lib/AST/DeclarationName.cpp | 59 +- lib/AST/Expr.cpp | 444 ++- lib/AST/ExprCXX.cpp | 53 +- lib/AST/ExprConstant.cpp | 112 +- lib/AST/RecordLayoutBuilder.cpp | 568 +++- lib/AST/RecordLayoutBuilder.h | 8 +- lib/AST/Stmt.cpp | 89 +- lib/AST/StmtDumper.cpp | 78 +- lib/AST/StmtPrinter.cpp | 73 +- lib/AST/StmtProfile.cpp | 28 + lib/AST/TemplateName.cpp | 18 +- lib/AST/Type.cpp | 20 +- lib/AST/TypePrinter.cpp | 4 +- lib/Analysis/CFG.cpp | 68 +- lib/Basic/Diagnostic.cpp | 70 +- lib/Basic/IdentifierTable.cpp | 6 +- lib/Basic/SourceManager.cpp | 100 +- lib/Basic/TargetInfo.cpp | 12 +- lib/Basic/Targets.cpp | 33 + lib/Checker/BasicObjCFoundationChecks.cpp | 41 +- lib/Checker/BasicStore.cpp | 2 +- lib/Checker/BugReporter.cpp | 2 +- lib/Checker/BugReporterVisitors.cpp | 14 +- lib/Checker/CFRefCount.cpp | 115 +- lib/Checker/CMakeLists.txt | 1 + lib/Checker/CallAndMessageChecker.cpp | 19 +- lib/Checker/CastToStructChecker.cpp | 2 +- lib/Checker/CheckObjCDealloc.cpp | 30 +- lib/Checker/CheckObjCInstMethSignature.cpp | 6 +- lib/Checker/CheckSecuritySyntaxOnly.cpp | 12 +- lib/Checker/Environment.cpp | 7 + lib/Checker/GRCXXExprEngine.cpp | 246 ++ lib/Checker/GRCoreEngine.cpp | 27 + lib/Checker/GRExprEngine.cpp | 369 +-- lib/Checker/MemRegion.cpp | 21 +- lib/Checker/NSAutoreleasePoolChecker.cpp | 2 +- lib/Checker/NSErrorChecker.cpp | 2 +- lib/Checker/ObjCUnusedIVarsChecker.cpp | 3 +- lib/Checker/RegionStore.cpp | 44 +- lib/Checker/SVals.cpp | 3 +- lib/Checker/SimpleSValuator.cpp | 22 +- lib/Checker/Store.cpp | 22 +- lib/Checker/UnixAPIChecker.cpp | 85 +- lib/CodeGen/CGBlocks.cpp | 24 +- lib/CodeGen/CGBlocks.h | 3 +- lib/CodeGen/CGBuiltin.cpp | 91 +- lib/CodeGen/CGCXX.cpp | 12 +- lib/CodeGen/CGCall.cpp | 11 +- lib/CodeGen/CGClass.cpp | 664 ++-- lib/CodeGen/CGDebugInfo.cpp | 209 +- lib/CodeGen/CGDebugInfo.h | 10 +- lib/CodeGen/CGDecl.cpp | 62 +- lib/CodeGen/CGDeclCXX.cpp | 11 +- lib/CodeGen/CGException.cpp | 235 +- lib/CodeGen/CGExpr.cpp | 335 ++- lib/CodeGen/CGExprAgg.cpp | 25 +- lib/CodeGen/CGExprCXX.cpp | 50 +- lib/CodeGen/CGExprConstant.cpp | 579 ++-- lib/CodeGen/CGExprScalar.cpp | 133 +- lib/CodeGen/CGObjC.cpp | 216 +- lib/CodeGen/CGObjCGNU.cpp | 230 +- lib/CodeGen/CGObjCMac.cpp | 341 ++- lib/CodeGen/CGObjCRuntime.h | 5 +- lib/CodeGen/CGRTTI.cpp | 101 +- lib/CodeGen/CGRecordLayout.h | 134 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 306 +- lib/CodeGen/CGStmt.cpp | 64 +- lib/CodeGen/CGTemporaries.cpp | 12 +- lib/CodeGen/CGVTT.cpp | 24 +- lib/CodeGen/CGVTables.cpp | 3167 +++++++++++++++++++ lib/CodeGen/CGVTables.h | 368 +++ lib/CodeGen/CGValue.h | 67 +- lib/CodeGen/CGVtable.cpp | 3170 -------------------- lib/CodeGen/CGVtable.h | 361 --- lib/CodeGen/CMakeLists.txt | 2 +- lib/CodeGen/CodeGenFunction.cpp | 24 +- lib/CodeGen/CodeGenFunction.h | 93 +- lib/CodeGen/CodeGenModule.cpp | 239 +- lib/CodeGen/CodeGenModule.h | 37 +- lib/CodeGen/CodeGenTypes.h | 5 +- lib/CodeGen/Mangle.cpp | 239 +- lib/CodeGen/Mangle.h | 12 +- lib/CodeGen/TargetInfo.cpp | 83 +- lib/Driver/Driver.cpp | 6 +- lib/Driver/ToolChains.cpp | 21 + lib/Driver/ToolChains.h | 17 +- lib/Driver/Tools.cpp | 129 +- lib/Driver/Tools.h | 5 + lib/Frontend/ASTConsumers.cpp | 191 +- lib/Frontend/ASTUnit.cpp | 18 +- lib/Frontend/AnalysisConsumer.cpp | 209 +- lib/Frontend/CacheTokens.cpp | 5 +- lib/Frontend/CodeGenAction.cpp | 313 +- lib/Frontend/CompilerInstance.cpp | 19 +- lib/Frontend/CompilerInvocation.cpp | 135 +- lib/Frontend/FixItRewriter.cpp | 105 +- lib/Frontend/FrontendActions.cpp | 71 +- lib/Frontend/InitHeaderSearch.cpp | 59 +- lib/Frontend/InitPreprocessor.cpp | 30 +- lib/Frontend/LangStandards.cpp | 2 +- lib/Frontend/PCHReader.cpp | 34 +- lib/Frontend/PCHReaderDecl.cpp | 17 +- lib/Frontend/PCHReaderStmt.cpp | 135 +- lib/Frontend/PCHWriter.cpp | 15 +- lib/Frontend/PCHWriterDecl.cpp | 10 +- lib/Frontend/PCHWriterStmt.cpp | 83 +- lib/Frontend/PrintParserCallbacks.cpp | 9 +- lib/Frontend/PrintPreprocessedOutput.cpp | 50 +- lib/Frontend/RewriteMacros.cpp | 3 +- lib/Frontend/RewriteObjC.cpp | 528 ++-- lib/Frontend/StmtXML.cpp | 5 + lib/Frontend/TextDiagnosticPrinter.cpp | 24 +- lib/Frontend/VerifyDiagnosticsClient.cpp | 463 ++- lib/Frontend/Warnings.cpp | 6 + lib/Headers/CMakeLists.txt | 2 + lib/Headers/altivec.h | 1483 +++++++++ lib/Headers/arm_neon.h | 537 ++++ lib/Headers/nmmintrin.h | 2 +- lib/Headers/stdint.h | 7 + lib/Headers/tmmintrin.h | 2 +- lib/Index/ASTLocation.cpp | 4 +- lib/Index/Analyzer.cpp | 79 +- lib/Lex/Lexer.cpp | 6 +- lib/Lex/LiteralSupport.cpp | 5 +- lib/Lex/PPDirectives.cpp | 24 +- lib/Lex/PPLexerChange.cpp | 20 +- lib/Lex/PPMacroExpansion.cpp | 31 +- lib/Lex/Preprocessor.cpp | 8 +- lib/Lex/TokenConcatenation.cpp | 6 +- lib/Parse/AttributeList.cpp | 3 +- lib/Parse/DeclSpec.cpp | 1 + lib/Parse/MinimalAction.cpp | 37 +- lib/Parse/ParseCXXInlineMethods.cpp | 50 +- lib/Parse/ParseDecl.cpp | 112 +- lib/Parse/ParseDeclCXX.cpp | 16 +- lib/Parse/ParseExpr.cpp | 106 +- lib/Parse/ParseExprCXX.cpp | 33 +- lib/Parse/ParseInit.cpp | 132 +- lib/Parse/ParseObjc.cpp | 350 ++- lib/Parse/ParseStmt.cpp | 13 +- lib/Parse/ParseTentative.cpp | 13 + lib/Parse/Parser.cpp | 12 +- lib/Rewrite/HTMLRewrite.cpp | 4 +- lib/Rewrite/Rewriter.cpp | 8 +- lib/Runtime/Makefile | 2 + lib/Sema/AnalysisBasedWarnings.cpp | 93 +- lib/Sema/AnalysisBasedWarnings.h | 4 +- lib/Sema/CodeCompleteConsumer.cpp | 4 +- lib/Sema/JumpDiagnostics.cpp | 4 +- lib/Sema/Lookup.h | 25 +- lib/Sema/ParseAST.cpp | 27 +- lib/Sema/Sema.cpp | 22 +- lib/Sema/Sema.h | 807 ++--- lib/Sema/SemaAccess.cpp | 706 +++-- lib/Sema/SemaCXXCast.cpp | 239 +- lib/Sema/SemaCXXScopeSpec.cpp | 110 +- lib/Sema/SemaChecking.cpp | 198 +- lib/Sema/SemaCodeComplete.cpp | 584 +++- lib/Sema/SemaDecl.cpp | 868 ++++-- lib/Sema/SemaDeclAttr.cpp | 58 +- lib/Sema/SemaDeclCXX.cpp | 2088 +++++++------ lib/Sema/SemaDeclObjC.cpp | 237 +- lib/Sema/SemaExpr.cpp | 768 +++-- lib/Sema/SemaExprCXX.cpp | 537 ++-- lib/Sema/SemaExprObjC.cpp | 1004 +++++-- lib/Sema/SemaInit.cpp | 428 ++- lib/Sema/SemaInit.h | 60 +- lib/Sema/SemaLookup.cpp | 501 +++- lib/Sema/SemaObjCProperty.cpp | 61 +- lib/Sema/SemaOverload.cpp | 798 +++-- lib/Sema/SemaOverload.h | 35 +- lib/Sema/SemaStmt.cpp | 214 +- lib/Sema/SemaTemplate.cpp | 496 ++- lib/Sema/SemaTemplateDeduction.cpp | 160 +- lib/Sema/SemaTemplateInstantiate.cpp | 274 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 336 ++- lib/Sema/SemaType.cpp | 124 +- lib/Sema/TreeTransform.h | 817 ++++- test/ASTMerge/category.m | 2 +- test/ASTMerge/enum.c | 2 +- test/ASTMerge/function.c | 2 +- test/ASTMerge/interface.m | 2 +- test/ASTMerge/property.m | 2 +- test/ASTMerge/struct.c | 2 +- test/ASTMerge/typedef.c | 2 +- test/ASTMerge/var.c | 2 +- test/Analysis/inline.c | 4 +- test/Analysis/inline2.c | 3 +- test/Analysis/inline3.c | 4 +- test/Analysis/inline4.c | 4 +- test/Analysis/method-call.cpp | 18 + test/Analysis/misc-ps-region-store.m | 59 + test/Analysis/misc-ps.m | 24 + test/Analysis/new.cpp | 14 + ...il-receiver-undefined-larger-than-voidptr-ret.m | 6 +- test/Analysis/null-deref-ps.c | 4 +- test/Analysis/override-werror.c | 2 +- test/Analysis/unix-fns.c | 37 +- .../basic/basic.lookup/basic.lookup.argdep/p2.cpp | 15 + .../basic/basic.lookup/basic.lookup.elab/p2.cpp | 60 + .../basic.lookup.qual/namespace.qual/p2.cpp | 2 +- .../basic/basic.lookup/basic.lookup.unqual/p7.cpp | 4 +- test/CXX/class.access/class.access.base/p1.cpp | 2 +- test/CXX/class.access/class.access.base/p5.cpp | 2 +- test/CXX/class.access/class.access.nest/p1.cpp | 2 +- test/CXX/class.access/class.friend/p1.cpp | 97 +- test/CXX/class.access/class.friend/p2-cxx03.cpp | 13 + test/CXX/class.access/class.friend/p3-cxx0x.cpp | 29 + test/CXX/class.access/class.protected/p1.cpp | 387 +++ test/CXX/class.access/p4.cpp | 99 +- test/CXX/class.access/p6.cpp | 69 +- test/CXX/class/class.friend/p2.cpp | 4 +- test/CXX/class/class.local/p2.cpp | 2 +- .../class/class.mfct/class.mfct.non-static/p3.cpp | 2 +- test/CXX/conv/conv.mem/p4.cpp | 2 +- .../namespace.def/namespace.memdef/p3.cpp | 12 + .../dcl.dcl/basic.namespace/namespace.udecl/p1.cpp | 7 +- .../dcl.dcl/basic.namespace/namespace.udecl/p4.cpp | 2 +- .../dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp | 2 +- .../dcl.init.ref/p16-cxx0x-no-extra-copy.cpp | 50 + .../dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp | 61 + .../dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp | 8 +- test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp | 16 + .../dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp | 3 +- .../dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp | 1 + test/CXX/dcl.decl/dcl.meaning/dcl.ref/p5.cpp | 6 +- test/CXX/except/except.handle/p16.cpp | 4 +- test/CXX/expr/expr.unary/expr.delete/p5.cpp | 2 +- test/CXX/expr/expr.unary/expr.new/p19.cpp | 2 +- test/CXX/expr/expr.unary/expr.new/p20-0x.cpp | 2 +- test/CXX/expr/expr.unary/expr.new/p20.cpp | 2 +- .../over.best.ics/over.ics.user/p3-0x.cpp | 14 + test/CXX/stmt.stmt/stmt.select/p3.cpp | 8 + .../temp.class.spec/temp.class.order/p2.cpp | 38 +- test/CXX/temp/temp.decls/temp.friend/p1.cpp | 83 +- test/CXX/temp/temp.decls/temp.friend/p3.cpp | 3 +- test/CXX/temp/temp.decls/temp.mem/p1.cpp | 6 +- test/CXX/temp/temp.param/p3.cpp | 12 + test/CXX/temp/temp.res/temp.local/p3.cpp | 32 + test/CXX/temp/temp.spec/p5.cpp | 17 + test/CXX/temp/temp.spec/temp.explicit/p3.cpp | 16 +- test/CXX/temp/temp.spec/temp.explicit/p4.cpp | 22 +- test/CXX/temp/temp.spec/temp.inst/p11.cpp | 15 + test/CodeCompletion/call.cpp | 1 + test/CodeCompletion/macros.c | 4 - test/CodeCompletion/ordinary-name.cpp | 18 +- test/CodeGen/2009-10-20-GlobalDebug.c | 8 +- test/CodeGen/arm-arguments.c | 30 +- test/CodeGen/arm_asm_clobber.c | 21 - test/CodeGen/asm-errors.c | 8 + test/CodeGen/asm.c | 21 + test/CodeGen/asm_arm.c | 32 + test/CodeGen/bitfield-2.c | 368 +++ test/CodeGen/blocks.c | 2 +- test/CodeGen/builtins-ppc-altivec.c | 332 ++ test/CodeGen/catch-undef-behavior.c | 7 + test/CodeGen/const-unordered-compare.c | 7 + test/CodeGen/decl.c | 32 +- test/CodeGen/designated-initializers.c | 37 +- test/CodeGen/functions.c | 12 + test/CodeGen/global-init.c | 30 +- test/CodeGen/init.c | 6 +- test/CodeGen/libcalls.c | 50 +- test/CodeGen/palignr.c | 19 +- test/CodeGen/struct-passing.c | 4 +- test/CodeGen/union-init2.c | 11 +- test/CodeGen/x86_32-arguments.c | 126 +- test/CodeGen/x86_64-arguments.c | 81 +- test/CodeGenCXX/PR6747.cpp | 11 + test/CodeGenCXX/address-of-fntemplate.cpp | 14 + .../anonymous-union-member-initializer.cpp | 26 +- test/CodeGenCXX/arm.cpp | 20 + test/CodeGenCXX/assign-operator.cpp | 14 +- test/CodeGenCXX/bitfield-layout.cpp | 43 + test/CodeGenCXX/block-destruct.cpp | 9 + test/CodeGenCXX/c-linkage.cpp | 13 + test/CodeGenCXX/constructor-init-reference.cpp | 2 +- test/CodeGenCXX/constructors.cpp | 14 +- test/CodeGenCXX/default-arg-temps.cpp | 50 +- test/CodeGenCXX/default-destructor-nested.cpp | 2 +- test/CodeGenCXX/delete.cpp | 26 +- test/CodeGenCXX/destructor-debug-info.cpp | 21 + test/CodeGenCXX/eh.cpp | 87 +- test/CodeGenCXX/empty-classes.cpp | 69 + test/CodeGenCXX/exceptions-no-rtti.cpp | 48 + test/CodeGenCXX/field-access-debug-info.cpp | 11 + test/CodeGenCXX/implicit-copy-assign-operator.cpp | 56 + test/CodeGenCXX/instantiate-init-list.cpp | 2 +- test/CodeGenCXX/mangle-template.cpp | 40 + test/CodeGenCXX/mangle.cpp | 11 +- test/CodeGenCXX/member-function-pointer-calls.cpp | 11 +- test/CodeGenCXX/member-function-pointers.cpp | 37 +- test/CodeGenCXX/member-initializers.cpp | 2 +- test/CodeGenCXX/namespace-aliases.cpp | 6 + test/CodeGenCXX/new-operator-phi.cpp | 2 +- test/CodeGenCXX/new.cpp | 12 +- test/CodeGenCXX/operator-new.cpp | 1 + test/CodeGenCXX/reference-in-blocks.cpp | 21 + test/CodeGenCXX/rtti-fundamental.cpp | 4 +- test/CodeGenCXX/static-init.cpp | 11 + test/CodeGenCXX/static-local-in-local-class.cpp | 21 + ...template-anonymous-union-member-initializer.cpp | 1 + test/CodeGenCXX/template-instantiation.cpp | 1 + test/CodeGenCXX/temporaries.cpp | 19 + test/CodeGenCXX/value-init.cpp | 26 + test/CodeGenCXX/virt-template-vtable.cpp | 1 + test/CodeGenCXX/virt.cpp | 696 ----- test/CodeGenCXX/vtable-layout.cpp | 334 +++ test/CodeGenCXX/x86_32-arguments.cpp | 4 +- test/CodeGenObjC/atomic-aggregate-property.m | 28 + test/CodeGenObjC/blocks.m | 2 +- test/CodeGenObjC/encode-cstyle-method.m | 11 + test/CodeGenObjC/exceptions.m | 18 + test/CodeGenObjC/image-info.m | 10 +- test/CodeGenObjC/metadata-symbols-64.m | 2 +- test/CodeGenObjC/metadata_symbols.m | 51 +- test/CodeGenObjC/next-objc-dispatch.m | 73 + test/CodeGenObjC/non-lazy-classes.m | 2 +- test/CodeGenObjC/ns-constant-strings.m | 33 + test/CodeGenObjC/objc-gc-aggr-assign.m | 46 - test/CodeGenObjC/objc2-legacy-dispatch.m | 4 +- test/CodeGenObjC/x86_64-struct-return-gc.m | 2 +- test/CodeGenObjCXX/ivar-objects.mm | 71 + test/CodeGenObjCXX/mangle.mm | 12 + test/Coverage/ast-printing.cpp | 2 +- test/Driver/darwin-ld.c | 2 +- test/Driver/darwin-objc-defaults.m | 88 + test/Driver/darwin-objc-gc.m | 19 + test/Driver/darwin-objc-options.m | 19 + test/FixIt/fixit-at.c | 5 - test/FixIt/fixit-c90.c | 8 +- test/FixIt/fixit-cxx0x.cpp | 10 +- test/FixIt/fixit-errors-1.c | 5 +- test/FixIt/fixit-errors.c | 5 +- test/FixIt/fixit-objc.m | 7 +- test/FixIt/fixit-pmem.cpp | 5 +- test/FixIt/fixit-suffix.c | 5 + test/FixIt/fixit-unrecoverable.c | 10 + test/FixIt/fixit-unrecoverable.cpp | 11 + test/FixIt/fixit.c | 19 +- test/FixIt/fixit.cpp | 15 +- test/FixIt/typo.c | 4 +- test/FixIt/typo.cpp | 5 +- test/FixIt/typo.m | 60 +- test/Index/Inputs/complete-pch.h | 10 + test/Index/annotate-tokens.m | 18 +- test/Index/complete-at-directives.m | 4 +- test/Index/complete-at-exprstmt.m | 4 +- test/Index/complete-exprs.c | 15 + test/Index/complete-method-decls.m | 82 + test/Index/complete-objc-message-id.m | 42 + test/Index/complete-objc-message.m | 78 + test/Index/complete-pch.m | 26 + test/Index/invalid-code-rdar_7833619.m | 4 + test/Index/load-exprs.c | 39 +- test/Index/local-symbols.m | 26 + test/Index/print-usrs.c | 4 +- test/Index/usrs.m | 87 + test/Lexer/gnu_keywords.c | 12 + test/Lexer/utf-16.c | 6 + test/Lexer/utf-16.c.txt | Bin 0 -> 48 bytes test/Misc/message-length.c | 16 +- test/Misc/tabstop.c | 3 - test/Misc/verify.c | 14 + test/PCH/exprs.c | 4 + test/PCH/exprs.h | 13 + test/PCH/functions.c | 4 +- test/PCH/functions.h | 5 +- test/PCH/objc_stmts.h | 22 + test/PCH/objc_stmts.m | 12 + test/PCH/pr4489.c | 7 + test/PCH/types.c | 2 +- test/Parser/altivec.c | 8 +- test/Parser/attributes.c | 4 + test/Parser/builtin_types_compatible.c | 2 +- test/Parser/check-syntax-1.m | 4 +- test/Parser/cxx-altivec.cpp | 9 +- test/Parser/cxx-casting.cpp | 9 +- test/Parser/cxx-class.cpp | 2 +- test/Parser/cxx-friend.cpp | 6 +- test/Parser/cxx-template-decl.cpp | 2 +- test/Parser/declarators.c | 2 +- test/Parser/implicit-casts.c | 2 +- test/Parser/objc-init.m | 3 +- test/Parser/objc-quirks.m | 18 + test/Preprocessor/expr_usual_conversions.c | 5 +- test/Preprocessor/if_warning.c | 6 + test/Preprocessor/init.c | 10 +- test/Preprocessor/line-directive-output.c | 71 + test/Preprocessor/non_fragile_feature.m | 4 + test/Preprocessor/output_paste_avoid.c | 5 +- test/Rewriter/dllimport-typedef.c | 4 +- test/Rewriter/missing-dllimport.c | 4 +- test/Rewriter/rewrite-super-message.mm | 2 +- test/Sema/address_spaces.c | 2 +- test/Sema/altivec-init.c | 4 +- test/Sema/anonymous-struct-union.c | 12 +- test/Sema/arm-layout.c | 49 +- test/Sema/array-constraint.c | 4 +- test/Sema/array-init.c | 14 +- test/Sema/attr-format.c | 2 +- test/Sema/attr-noreturn.c | 2 + test/Sema/attr-section.c | 2 +- test/Sema/bitfield.c | 4 +- test/Sema/block-call.c | 12 +- test/Sema/block-misc.c | 12 +- test/Sema/block-return.c | 14 +- test/Sema/builtin-prefetch.c | 4 +- test/Sema/builtin-stackaddress.c | 4 +- test/Sema/builtins.c | 2 +- test/Sema/cast-to-union.c | 2 +- test/Sema/compare.c | 5 + test/Sema/compound-literal.c | 2 +- test/Sema/conditional-expr.c | 8 +- test/Sema/conditional.c | 4 +- test/Sema/decl-invalid.c | 12 +- test/Sema/declspec.c | 2 +- test/Sema/enum.c | 3 +- test/Sema/exprs.c | 8 +- test/Sema/ext_vector_casts.c | 2 +- test/Sema/format-strings.c | 4 +- test/Sema/function-ptr.c | 6 +- test/Sema/function-redecl.c | 2 +- test/Sema/incompatible-sign.c | 4 +- test/Sema/invalid-init-diag.c | 2 +- test/Sema/offsetof.c | 13 +- test/Sema/parentheses.c | 12 +- test/Sema/pointer-conversion.c | 6 +- test/Sema/predef.c | 2 +- test/Sema/predefined-function.c | 5 +- test/Sema/return.c | 2 +- test/Sema/statements.c | 12 +- test/Sema/struct-compat.c | 2 +- test/Sema/transparent-union.c | 2 +- test/Sema/typedef-retain.c | 4 +- test/Sema/unused-expr.c | 6 + test/Sema/vector-assign.c | 44 +- test/Sema/vector-cast.c | 4 +- test/Sema/warn-missing-braces.c | 2 +- test/Sema/warn-unused-function.c | 7 + test/Sema/warn-unused-parameters.c | 15 +- test/Sema/warn-unused-value.c | 15 + test/Sema/warn-write-strings.c | 2 +- test/Sema/x86-builtin-palignr.c | 10 + test/SemaCXX/abstract.cpp | 9 +- test/SemaCXX/access-base-class.cpp | 2 +- test/SemaCXX/access-control-check.cpp | 2 +- test/SemaCXX/addr-of-overloaded-function.cpp | 32 + test/SemaCXX/aggregate-initialization.cpp | 17 +- test/SemaCXX/anonymous-union.cpp | 2 +- test/SemaCXX/bitfield-layout.cpp | 30 + test/SemaCXX/class-base-member-init.cpp | 23 + test/SemaCXX/class.cpp | 2 +- test/SemaCXX/conditional-expr.cpp | 10 +- test/SemaCXX/constant-expression.cpp | 10 +- test/SemaCXX/constructor-initializer.cpp | 48 +- test/SemaCXX/conversion-function.cpp | 88 +- test/SemaCXX/copy-assignment.cpp | 2 +- test/SemaCXX/copy-initialization.cpp | 21 +- test/SemaCXX/cstyle-cast.cpp | 2 +- test/SemaCXX/default-assignment-operator.cpp | 22 +- test/SemaCXX/default-constructor-initializers.cpp | 6 +- test/SemaCXX/default1.cpp | 9 +- test/SemaCXX/default2.cpp | 3 +- test/SemaCXX/derived-to-base-ambig.cpp | 4 +- test/SemaCXX/direct-initializer.cpp | 2 +- test/SemaCXX/elaborated-type-specifier.cpp | 2 +- test/SemaCXX/exceptions.cpp | 23 + test/SemaCXX/functional-cast.cpp | 2 +- test/SemaCXX/illegal-member-initialization.cpp | 6 +- test/SemaCXX/implicit-member-functions.cpp | 35 +- test/SemaCXX/inc-decrement-qualifiers.cpp | 9 + test/SemaCXX/libstdcxx_is_pod_hack.cpp | 6 + test/SemaCXX/libstdcxx_map_base_hack.cpp | 25 + test/SemaCXX/local-classes.cpp | 9 + test/SemaCXX/member-expr.cpp | 22 +- test/SemaCXX/member-location.cpp | 5 +- test/SemaCXX/member-pointer.cpp | 16 +- test/SemaCXX/missing-header.cpp | 9 + test/SemaCXX/namespace-alias.cpp | 10 + test/SemaCXX/nested-name-spec.cpp | 16 +- test/SemaCXX/new-delete.cpp | 23 +- test/SemaCXX/no-exceptions.cpp | 21 + test/SemaCXX/offsetof.cpp | 37 +- test/SemaCXX/overload-call.cpp | 30 +- test/SemaCXX/overloaded-operator.cpp | 30 +- test/SemaCXX/qual-id-test.cpp | 6 +- test/SemaCXX/qualified-id-lookup.cpp | 22 + test/SemaCXX/ref-init-ambiguous.cpp | 2 +- test/SemaCXX/references.cpp | 4 +- test/SemaCXX/static-cast.cpp | 2 +- test/SemaCXX/storage-class.cpp | 4 + test/SemaCXX/typedef-redecl.cpp | 13 +- test/SemaCXX/typeid-ref.cpp | 12 + test/SemaCXX/typeid.cpp | 1 - test/SemaCXX/unused-functions.cpp | 8 + test/SemaCXX/user-defined-conversions.cpp | 15 + test/SemaCXX/value-initialization.cpp | 6 +- test/SemaCXX/virtual-override.cpp | 2 +- test/SemaCXX/warn-assignment-condition.cpp | 49 +- test/SemaCXX/warn-missing-noreturn.cpp | 14 + test/SemaCXX/warn-reorder-ctor-initialization.cpp | 57 +- test/SemaCXX/warn-unused-parameters.cpp | 26 + test/SemaCXX/warn-unused-variables.cpp | 8 + test/SemaCXX/warn-weak-vtables.cpp | 2 +- test/SemaObjC/argument-checking.m | 19 +- test/SemaObjC/block-type-safety.m | 18 +- test/SemaObjC/blocks.m | 12 +- test/SemaObjC/call-super-2.m | 2 +- test/SemaObjC/catch-stmt.m | 4 +- test/SemaObjC/class-bitfield.m | 2 +- test/SemaObjC/class-method-lookup.m | 2 +- test/SemaObjC/class-method-self.m | 6 +- .../SemaObjC/compatible-protocol-qualified-types.m | 4 +- test/SemaObjC/compound-init.m | 7 + test/SemaObjC/comptypes-1.m | 12 +- test/SemaObjC/comptypes-3.m | 18 +- test/SemaObjC/comptypes-6.m | 2 +- test/SemaObjC/comptypes-7.m | 32 +- test/SemaObjC/comptypes-legal.m | 4 +- test/SemaObjC/conditional-expr-2.m | 2 +- test/SemaObjC/conditional-expr-3.m | 4 +- test/SemaObjC/conditional-expr-4.m | 2 +- test/SemaObjC/conditional-expr.m | 4 +- test/SemaObjC/continuation-class-err.m | 6 +- test/SemaObjC/default-synthesize.m | 24 + test/SemaObjC/ibaction.m | 15 + test/SemaObjC/id.m | 4 +- .../incompatible-protocol-qualified-types.m | 8 +- test/SemaObjC/invalid-code.m | 7 + test/SemaObjC/invalid-objc-decls-1.m | 4 +- test/SemaObjC/invalid-receiver.m | 2 +- test/SemaObjC/ivar-in-class-extension-error.m | 8 +- test/SemaObjC/ivar-in-class-extension.m | 6 +- test/SemaObjC/ivar-lookup.m | 19 + test/SemaObjC/message.m | 2 +- test/SemaObjC/method-arg-qualifier-warning.m | 6 +- test/SemaObjC/method-bad-param.m | 12 +- test/SemaObjC/objc-cstyle-args-in-methods.m | 20 + test/SemaObjC/pedantic-dynamic-test.m | 16 + test/SemaObjC/property-9.m | 4 +- test/SemaObjC/property-typecheck-1.m | 6 +- test/SemaObjC/protocol-id-test-3.m | 14 +- test/SemaObjC/protocol-typecheck.m | 4 +- test/SemaObjC/protocol-warn.m | 2 +- test/SemaObjC/stmts.m | 4 + test/SemaObjC/super-class-protocol-conformance.m | 47 + test/SemaObjC/super.m | 47 +- test/SemaObjC/synthesized-ivar.m | 3 + test/SemaObjC/transparent-union.m | 22 + test/SemaObjC/unused.m | 4 +- test/SemaObjC/warn-incompatible-builtin-types.m | 20 +- test/SemaObjC/warn-selector-selection.m | 2 +- test/SemaObjC/warn-superclass-method-mismatch.m | 2 +- test/SemaObjC/warn-unused-exception-param.m | 4 + test/SemaObjC/warn-write-strings.m | 2 +- test/SemaObjCXX/blocks.mm | 4 +- test/SemaObjCXX/instantiate-expr.mm | 73 + test/SemaObjCXX/instantiate-message.mm | 50 + test/SemaObjCXX/instantiate-stmt.mm | 77 + test/SemaObjCXX/ivar-lookup.mm | 18 + test/SemaObjCXX/ivar-reference-type.mm | 5 + test/SemaObjCXX/linkage-spec.mm | 8 + test/SemaObjCXX/message.mm | 77 +- test/SemaObjCXX/objc-pointer-conv.mm | 4 +- test/SemaObjCXX/overload-1.mm | 25 + test/SemaObjCXX/parameters.mm | 12 + test/SemaObjCXX/void_to_obj.mm | 2 +- test/SemaTemplate/class-template-decl.cpp | 5 + test/SemaTemplate/constructor-template.cpp | 15 + test/SemaTemplate/default-expr-arguments-2.cpp | 19 + test/SemaTemplate/default-expr-arguments.cpp | 30 +- test/SemaTemplate/dependent-names.cpp | 4 + test/SemaTemplate/destructor-template.cpp | 8 + test/SemaTemplate/elaborated-type-specifier.cpp | 36 + .../explicit-specialization-member.cpp | 2 +- test/SemaTemplate/friend-template.cpp | 80 + test/SemaTemplate/friend.cpp | 19 + test/SemaTemplate/fun-template-def.cpp | 2 +- test/SemaTemplate/injected-class-name.cpp | 12 + test/SemaTemplate/instantiate-complete.cpp | 20 +- .../instantiate-default-assignment-operator.cpp | 8 +- test/SemaTemplate/instantiate-expr-2.cpp | 19 + test/SemaTemplate/instantiate-expr-5.cpp | 36 +- test/SemaTemplate/instantiate-function-1.cpp | 5 + test/SemaTemplate/instantiate-function-params.cpp | 41 +- test/SemaTemplate/instantiate-local-class.cpp | 4 +- test/SemaTemplate/instantiate-member-class.cpp | 9 +- test/SemaTemplate/instantiate-member-expr.cpp | 2 +- .../instantiate-member-initializers.cpp | 5 +- test/SemaTemplate/instantiate-member-template.cpp | 2 +- test/SemaTemplate/instantiate-method.cpp | 60 +- .../instantiate-non-type-template-parameter.cpp | 24 +- test/SemaTemplate/instantiate-typedef.cpp | 3 +- test/SemaTemplate/instantiate-using-decl.cpp | 2 +- test/SemaTemplate/instantiation-depth.cpp | 10 +- test/SemaTemplate/nested-name-spec-template.cpp | 13 + test/SemaTemplate/qualified-id.cpp | 1 + test/SemaTemplate/temp_arg.cpp | 3 +- test/SemaTemplate/temp_arg_nontype.cpp | 39 +- test/SemaTemplate/temp_arg_type.cpp | 24 +- test/SemaTemplate/template-decl-fail.cpp | 4 +- test/SemaTemplate/typename-specifier-4.cpp | 2 +- test/SemaTemplate/typename-specifier.cpp | 15 +- tools/CIndex/CIndex.cpp | 108 +- tools/CIndex/CIndex.darwin.exports | 81 + tools/CIndex/CIndex.exports | 161 +- tools/CIndex/CIndexCodeCompletion.cpp | 92 + tools/CIndex/CIndexDiagnostic.cpp | 1 + tools/CIndex/CIndexDiagnostic.h | 15 +- tools/CIndex/CIndexInclusionStack.cpp | 2 + tools/CIndex/CIndexUSRs.cpp | 211 +- tools/CIndex/CIndexer.cpp | 1 - tools/CIndex/CIndexer.h | 4 - tools/CIndex/CMakeLists.txt | 6 +- tools/CIndex/CXCursor.cpp | 2 +- tools/CIndex/CXSourceLocation.h | 5 +- tools/CIndex/Makefile | 3 +- tools/CMakeLists.txt | 2 +- tools/Makefile | 4 +- tools/c-index-test/CMakeLists.txt | 2 +- tools/c-index-test/Makefile | 3 +- tools/c-index-test/c-index-test.c | 9 +- tools/driver/CMakeLists.txt | 3 +- tools/driver/cc1_main.cpp | 18 +- tools/libclang/CIndex.cpp | 2598 ++++++++++++++++ tools/libclang/CIndexCodeCompletion.cpp | 512 ++++ tools/libclang/CIndexDiagnostic.cpp | 285 ++ tools/libclang/CIndexDiagnostic.h | 53 + tools/libclang/CIndexInclusionStack.cpp | 67 + tools/libclang/CIndexUSRs.cpp | 477 +++ tools/libclang/CIndexer.cpp | 154 + tools/libclang/CIndexer.h | 78 + tools/libclang/CMakeLists.txt | 57 + tools/libclang/CXCursor.cpp | 370 +++ tools/libclang/CXCursor.h | 112 + tools/libclang/CXSourceLocation.h | 75 + tools/libclang/Makefile | 55 + tools/libclang/libclang.darwin.exports | 81 + tools/libclang/libclang.exports | 81 + tools/scan-build/ccc-analyzer | 7 +- utils/CIndex/completion_logger_server.py | 44 + www/analyzer/latest_checker.html.incl | 2 +- www/clang_video-05-25-2007.html | 2 +- www/clang_video-07-25-2007.html | 2 +- www/cxx_compatibility.html | 48 + www/cxx_status.html | 31 +- www/menu.css | 2 +- 749 files changed, 37446 insertions(+), 15343 deletions(-) create mode 100644 include/clang-c/Makefile create mode 100644 include/clang/AST/ASTVector.h create mode 100644 include/clang/AST/DeclAccessPair.h create mode 100644 include/clang/AST/UsuallyTinyPtrVector.h delete mode 100644 include/clang/Analysis/Support/Optional.h create mode 100644 lib/Checker/GRCXXExprEngine.cpp create mode 100644 lib/CodeGen/CGVTables.cpp create mode 100644 lib/CodeGen/CGVTables.h delete mode 100644 lib/CodeGen/CGVtable.cpp delete mode 100644 lib/CodeGen/CGVtable.h create mode 100644 lib/Headers/altivec.h create mode 100644 lib/Headers/arm_neon.h create mode 100644 test/Analysis/method-call.cpp create mode 100644 test/Analysis/new.cpp create mode 100644 test/CXX/basic/basic.lookup/basic.lookup.elab/p2.cpp create mode 100644 test/CXX/class.access/class.friend/p2-cxx03.cpp create mode 100644 test/CXX/class.access/class.friend/p3-cxx0x.cpp create mode 100644 test/CXX/class.access/class.protected/p1.cpp create mode 100644 test/CXX/dcl.decl/dcl.init/dcl.init.ref/p16-cxx0x-no-extra-copy.cpp create mode 100644 test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp create mode 100644 test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.user/p3-0x.cpp create mode 100644 test/CXX/temp/temp.res/temp.local/p3.cpp create mode 100644 test/CXX/temp/temp.spec/temp.inst/p11.cpp delete mode 100644 test/CodeGen/arm_asm_clobber.c create mode 100644 test/CodeGen/asm-errors.c create mode 100644 test/CodeGen/asm_arm.c create mode 100644 test/CodeGen/bitfield-2.c create mode 100644 test/CodeGen/builtins-ppc-altivec.c create mode 100644 test/CodeGen/catch-undef-behavior.c create mode 100644 test/CodeGen/const-unordered-compare.c create mode 100644 test/CodeGenCXX/PR6747.cpp create mode 100644 test/CodeGenCXX/arm.cpp create mode 100644 test/CodeGenCXX/bitfield-layout.cpp create mode 100644 test/CodeGenCXX/block-destruct.cpp create mode 100644 test/CodeGenCXX/c-linkage.cpp create mode 100644 test/CodeGenCXX/destructor-debug-info.cpp create mode 100644 test/CodeGenCXX/empty-classes.cpp create mode 100644 test/CodeGenCXX/exceptions-no-rtti.cpp create mode 100644 test/CodeGenCXX/field-access-debug-info.cpp create mode 100644 test/CodeGenCXX/implicit-copy-assign-operator.cpp create mode 100644 test/CodeGenCXX/reference-in-blocks.cpp create mode 100644 test/CodeGenCXX/static-local-in-local-class.cpp delete mode 100644 test/CodeGenCXX/virt.cpp create mode 100644 test/CodeGenObjC/atomic-aggregate-property.m create mode 100644 test/CodeGenObjC/encode-cstyle-method.m create mode 100644 test/CodeGenObjC/exceptions.m create mode 100644 test/CodeGenObjC/next-objc-dispatch.m create mode 100644 test/CodeGenObjC/ns-constant-strings.m delete mode 100644 test/CodeGenObjC/objc-gc-aggr-assign.m create mode 100644 test/CodeGenObjCXX/ivar-objects.mm create mode 100644 test/Driver/darwin-objc-defaults.m create mode 100644 test/Driver/darwin-objc-gc.m create mode 100644 test/Driver/darwin-objc-options.m delete mode 100644 test/FixIt/fixit-at.c create mode 100644 test/FixIt/fixit-suffix.c create mode 100644 test/FixIt/fixit-unrecoverable.c create mode 100644 test/FixIt/fixit-unrecoverable.cpp create mode 100644 test/Index/Inputs/complete-pch.h create mode 100644 test/Index/complete-exprs.c create mode 100644 test/Index/complete-method-decls.m create mode 100644 test/Index/complete-objc-message-id.m create mode 100644 test/Index/complete-pch.m create mode 100644 test/Index/invalid-code-rdar_7833619.m create mode 100644 test/Index/local-symbols.m create mode 100644 test/Index/usrs.m create mode 100644 test/Lexer/gnu_keywords.c create mode 100644 test/Lexer/utf-16.c create mode 100644 test/Lexer/utf-16.c.txt create mode 100644 test/Misc/verify.c create mode 100644 test/PCH/objc_stmts.h create mode 100644 test/PCH/objc_stmts.m create mode 100644 test/Preprocessor/line-directive-output.c create mode 100644 test/Sema/x86-builtin-palignr.c create mode 100644 test/SemaCXX/bitfield-layout.cpp create mode 100644 test/SemaCXX/inc-decrement-qualifiers.cpp create mode 100644 test/SemaCXX/libstdcxx_map_base_hack.cpp create mode 100644 test/SemaCXX/missing-header.cpp create mode 100644 test/SemaCXX/no-exceptions.cpp create mode 100644 test/SemaCXX/storage-class.cpp create mode 100644 test/SemaCXX/typeid-ref.cpp create mode 100644 test/SemaCXX/unused-functions.cpp create mode 100644 test/SemaCXX/warn-unused-parameters.cpp create mode 100644 test/SemaObjC/compound-init.m create mode 100644 test/SemaObjC/ibaction.m create mode 100644 test/SemaObjC/objc-cstyle-args-in-methods.m create mode 100644 test/SemaObjC/pedantic-dynamic-test.m create mode 100644 test/SemaObjC/super-class-protocol-conformance.m create mode 100644 test/SemaObjC/transparent-union.m create mode 100644 test/SemaObjC/warn-unused-exception-param.m create mode 100644 test/SemaObjCXX/instantiate-expr.mm create mode 100644 test/SemaObjCXX/instantiate-message.mm create mode 100644 test/SemaObjCXX/instantiate-stmt.mm create mode 100644 test/SemaObjCXX/ivar-lookup.mm create mode 100644 test/SemaObjCXX/ivar-reference-type.mm create mode 100644 test/SemaObjCXX/overload-1.mm create mode 100644 test/SemaObjCXX/parameters.mm create mode 100644 test/SemaTemplate/default-expr-arguments-2.cpp create mode 100644 test/SemaTemplate/elaborated-type-specifier.cpp create mode 100644 tools/CIndex/CIndex.darwin.exports create mode 100644 tools/libclang/CIndex.cpp create mode 100644 tools/libclang/CIndexCodeCompletion.cpp create mode 100644 tools/libclang/CIndexDiagnostic.cpp create mode 100644 tools/libclang/CIndexDiagnostic.h create mode 100644 tools/libclang/CIndexInclusionStack.cpp create mode 100644 tools/libclang/CIndexUSRs.cpp create mode 100644 tools/libclang/CIndexer.cpp create mode 100644 tools/libclang/CIndexer.h create mode 100644 tools/libclang/CMakeLists.txt create mode 100644 tools/libclang/CXCursor.cpp create mode 100644 tools/libclang/CXCursor.h create mode 100644 tools/libclang/CXSourceLocation.h create mode 100644 tools/libclang/Makefile create mode 100644 tools/libclang/libclang.darwin.exports create mode 100644 tools/libclang/libclang.exports create mode 100755 utils/CIndex/completion_logger_server.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 2001c71..1be646d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,26 @@ configure_file( set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +if( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE ) + message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite " +"the makefiles distributed with LLVM. Please create a directory and run cmake " +"from there, passing the path to this source directory as the last argument. " +"This process created the file `CMakeCache.txt' and the directory " +"`CMakeFiles'. Please delete them.") +endif() + +if( NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) + file(GLOB_RECURSE + tablegenned_files_on_include_dir + "${CLANG_SOURCE_DIR}/include/clang/*.inc") + if( tablegenned_files_on_include_dir ) + message(FATAL_ERROR "Apparently there is a previous in-source build, " +"probably as the result of running `configure' and `make' on " +"${CLANG_SOURCE_DIR}. This may cause problems. The suspicious files are:\n" +"${tablegenned_files_on_include_dir}\nPlease clean the source directory.") + endif() +endif() + # Compute the Clang version from the contents of VER file(READ ${CMAKE_CURRENT_SOURCE_DIR}/VER CLANG_VERSION_DATA) string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION @@ -95,6 +115,7 @@ install(DIRECTORY include/ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ DESTINATION include FILES_MATCHING + PATTERN "CMakeFiles" EXCLUDE PATTERN "*.inc" ) diff --git a/Makefile b/Makefile index f7e9e85..39cf9c6 100644 --- a/Makefile +++ b/Makefile @@ -37,30 +37,3 @@ cscope.files: -or -name '*.h' > cscope.files .PHONY: test report clean cscope.files - -install-local:: - $(Echo) Installing include files - $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) - $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \ - cd $(PROJ_SRC_ROOT)/tools/clang/include && \ - for hdr in `find . -type f '!' '(' -name '*~' \ - -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ - -o -name 'Makefile' -o -name '*.td' ')' -print \ - | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ - instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ - if test \! -d "$$instdir" ; then \ - $(EchoCmd) Making install directory $$instdir ; \ - $(MKDIR) $$instdir ;\ - fi ; \ - $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ - done ; \ - fi -ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) - $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include" ; then \ - cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ - for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \ - | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ - $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ - done ; \ - fi -endif diff --git a/VER b/VER index c239c60..cd5ac03 100644 --- a/VER +++ b/VER @@ -1 +1 @@ -1.5 +2.0 diff --git a/bindings/python/README.txt b/bindings/python/README.txt index ccc2619..742cf8f 100644 --- a/bindings/python/README.txt +++ b/bindings/python/README.txt @@ -2,10 +2,9 @@ // Clang Python Bindings //===----------------------------------------------------------------------===// -This directory implements Python bindings for Clang. Currently, only bindings -for the CIndex C API exist. +This directory implements Python bindings for Clang. -You may need to alter LD_LIBRARY_PATH so that the CIndex library can be +You may need to alter LD_LIBRARY_PATH so that the Clang library can be found. The unit tests are designed to be run with 'nosetests'. For example: -- $ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \ diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index f4409ae..f0f81b5 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -71,11 +71,11 @@ def get_cindex_library(): import platform name = platform.system() if name == 'Darwin': - return cdll.LoadLibrary('libCIndex.dylib') + return cdll.LoadLibrary('libclang.dylib') elif name == 'Windows': - return cdll.LoadLibrary('libCIndex.dll') + return cdll.LoadLibrary('libclang.dll') else: - return cdll.LoadLibrary('libCIndex.so') + return cdll.LoadLibrary('libclang.so') # ctypes doesn't implicitly convert c_void_p to the appropriate wrapper # object. This is a problem, because it means that from_parameter will see an diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index efdc3b3..6556bb4 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F50AC50D416EAA00B9CF60 /* Targets.cpp */; }; - 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */; }; 1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; }; 1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; }; 1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; }; @@ -26,11 +25,9 @@ 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B30FD1DD1C00F4CE45 /* StmtXML.cpp */; }; 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */; }; 1A30A9E90B93A4C800201A91 /* ExprCXX.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A30A9E80B93A4C800201A91 /* ExprCXX.h */; }; - 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */; }; 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */; }; 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */; }; 1A4C41BF105B4C0B0047B5E7 /* CGClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */; }; - 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */; }; 1A5D5E580E5E81010023C059 /* CGCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5D5E570E5E81010023C059 /* CGCXX.cpp */; }; 1A621BB7110FE6AA009E6834 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */; }; 1A621C4211111D61009E6834 /* CIndexCodeCompletion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A621C3A11111D61009E6834 /* CIndexCodeCompletion.cpp */; }; @@ -45,15 +42,48 @@ 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */; }; 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */; }; 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; }; - 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; }; + 1A81AA19108144F40094E50B /* CGVTables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVTables.cpp */; }; 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; }; 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; - 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A96785111486FDC00F24372 /* RecordLayout.cpp */; }; 1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A97825A1108BA18002B98FC /* CGVTT.cpp */; }; 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; }; - 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; }; - 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA963C310D85A7300786C86 /* FullExpr.cpp */; }; 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; + 1ABD23D61182449800A48E65 /* APValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B11182449800A48E65 /* APValue.cpp */; }; + 1ABD23D71182449800A48E65 /* ASTConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */; }; + 1ABD23D81182449800A48E65 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B31182449800A48E65 /* ASTContext.cpp */; }; + 1ABD23D91182449800A48E65 /* ASTDiagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */; }; + 1ABD23DA1182449800A48E65 /* ASTImporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B51182449800A48E65 /* ASTImporter.cpp */; }; + 1ABD23DB1182449800A48E65 /* AttrImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B61182449800A48E65 /* AttrImpl.cpp */; }; + 1ABD23DC1182449800A48E65 /* CXXInheritance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */; }; + 1ABD23DD1182449800A48E65 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B81182449800A48E65 /* Decl.cpp */; }; + 1ABD23DE1182449800A48E65 /* DeclarationName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23B91182449800A48E65 /* DeclarationName.cpp */; }; + 1ABD23DF1182449800A48E65 /* DeclBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BA1182449800A48E65 /* DeclBase.cpp */; }; + 1ABD23E01182449800A48E65 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */; }; + 1ABD23E11182449800A48E65 /* DeclFriend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */; }; + 1ABD23E21182449800A48E65 /* DeclGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */; }; + 1ABD23E31182449800A48E65 /* DeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */; }; + 1ABD23E41182449800A48E65 /* DeclPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */; }; + 1ABD23E51182449800A48E65 /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */; }; + 1ABD23E61182449800A48E65 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C11182449800A48E65 /* Expr.cpp */; }; + 1ABD23E71182449800A48E65 /* ExprConstant.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C21182449800A48E65 /* ExprConstant.cpp */; }; + 1ABD23E81182449800A48E65 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C31182449800A48E65 /* ExprCXX.cpp */; }; + 1ABD23E91182449800A48E65 /* FullExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C41182449800A48E65 /* FullExpr.cpp */; }; + 1ABD23EA1182449800A48E65 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C51182449800A48E65 /* InheritViz.cpp */; }; + 1ABD23EB1182449800A48E65 /* NestedNameSpecifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */; }; + 1ABD23EC1182449800A48E65 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C71182449800A48E65 /* ParentMap.cpp */; }; + 1ABD23ED1182449800A48E65 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C81182449800A48E65 /* RecordLayout.cpp */; }; + 1ABD23EE1182449800A48E65 /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */; }; + 1ABD23EF1182449800A48E65 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CB1182449800A48E65 /* Stmt.cpp */; }; + 1ABD23F01182449800A48E65 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */; }; + 1ABD23F11182449800A48E65 /* StmtIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */; }; + 1ABD23F21182449800A48E65 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */; }; + 1ABD23F31182449800A48E65 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */; }; + 1ABD23F41182449800A48E65 /* StmtViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D01182449800A48E65 /* StmtViz.cpp */; }; + 1ABD23F51182449800A48E65 /* TemplateBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D11182449800A48E65 /* TemplateBase.cpp */; }; + 1ABD23F61182449800A48E65 /* TemplateName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D21182449800A48E65 /* TemplateName.cpp */; }; + 1ABD23F71182449800A48E65 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D31182449800A48E65 /* Type.cpp */; }; + 1ABD23F81182449800A48E65 /* TypeLoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D41182449800A48E65 /* TypeLoc.cpp */; }; + 1ABD23F91182449800A48E65 /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABD23D51182449800A48E65 /* TypePrinter.cpp */; }; 1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */; }; 1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */; }; 1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57DD1105820D0047B991 /* DeclXML.cpp */; }; @@ -63,11 +93,7 @@ 1ACB57EA1105820D0047B991 /* LangStandards.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E11105820D0047B991 /* LangStandards.cpp */; }; 1ACB57EB1105820D0047B991 /* TypeXML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E21105820D0047B991 /* TypeXML.cpp */; }; 1ACB57EC1105820D0047B991 /* VerifyDiagnosticsClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */; }; - 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795110A90C6100741BBA /* TypePrinter.cpp */; }; - 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795210A90C6100741BBA /* TypeLoc.cpp */; }; - 1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADD795310A90C6100741BBA /* TemplateBase.cpp */; }; 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; }; - 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; }; 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; }; 1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8701161085D00AE030A /* ASTMerge.cpp */; }; 1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */; }; @@ -78,12 +104,10 @@ 352246EA0F5C6BE000D0D279 /* PlistDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */; }; 352246EB0F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */; }; 352246EC0F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */; }; - 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; }; 352712510DAFE54700C76352 /* IdentifierResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352712500DAFE54700C76352 /* IdentifierResolver.cpp */; }; 3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3534A01C0E129849002709B2 /* ParseCXXInlineMethods.cpp */; }; 3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3536456A0E23EBF7009C6509 /* Environment.cpp */; }; 3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */; }; - 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */; }; 353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */; }; 35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35475B1F0E79973F0000BFE4 /* CGCall.cpp */; }; 355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355106850E9A8507006A4E44 /* MemRegion.cpp */; }; @@ -94,17 +118,14 @@ 35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B850F5C7FD700D92AA9 /* RangeConstraintManager.cpp */; }; 35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */; }; 35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */; }; - 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3557D1A80EB136B100C59739 /* InheritViz.cpp */; }; 35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */; }; 3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3558F76C0E267C8300A5B0DF /* BasicStore.cpp */; }; 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; }; 35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */; }; 357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 357EA27C0F2526F300439B60 /* SemaLookup.cpp */; }; - 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */; }; 35862B0D0E3628CB0009F542 /* CheckDeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */; }; 35862B120E3629850009F542 /* GRExprEngineInternalChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */; }; 358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */; }; - 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */; }; 358F51520E529AA4007F2102 /* GRState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 358F51510E529AA4007F2102 /* GRState.cpp */; }; 3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3591853E0EFB1088000039AF /* SemaTemplate.cpp */; }; 3593790A0DA48ABA0043B19C /* BugReporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 359379090DA48ABA0043B19C /* BugReporter.cpp */; }; @@ -115,20 +136,15 @@ 35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */; }; 35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */; }; 35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */; }; - 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */; }; - 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */; }; 35D55B270D81D8C60092E734 /* BasicValueFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B240D81D8C60092E734 /* BasicValueFactory.cpp */; }; 35D55B280D81D8C60092E734 /* CFRefCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35D55B250D81D8C60092E734 /* CFRefCount.cpp */; }; 35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */; }; 35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */; }; 35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */; }; - 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */; }; - 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */; }; 35EF67700DAD1D2C00B19414 /* SemaDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */; }; 35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */; }; 35F2A01E0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F2A01D0E36AFF100D17527 /* CheckObjCUnusedIVars.cpp */; }; 35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */; }; - 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */; }; 72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */; }; 84AF36A10CB17A3B00C820A5 /* DeclObjC.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */; }; 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; }; @@ -162,8 +178,6 @@ DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06D42F0A8BB52D0050E87E /* Parser.cpp */; }; DE06E8140A8FF9330050E87E /* Action.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06E8130A8FF9330050E87E /* Action.h */; }; DE0FCA630A95859D00248FD5 /* Expr.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE0FCA620A95859D00248FD5 /* Expr.h */; }; - DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE0FCB330A9C21F100248FD5 /* Expr.cpp */; }; - DE1733000B068B700080B521 /* ASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE1732FF0B068B700080B521 /* ASTContext.cpp */; }; DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE17336D0B068DC20080B521 /* DeclSpec.cpp */; }; DE1733700B068DC60080B521 /* DeclSpec.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE17336F0B068DC60080B521 /* DeclSpec.h */; }; DE1F22030A7D852A00FBF588 /* Parser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE1F22020A7D852A00FBF588 /* Parser.h */; }; @@ -174,7 +188,6 @@ DE344AB80AE5DF6D00DBC861 /* HeaderSearch.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */; }; DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */; }; DE3450D70AEB543100DBC861 /* DirectoryLookup.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3450D60AEB543100DBC861 /* DirectoryLookup.h */; }; - DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3452400AEF1A2D00DBC861 /* Stmt.cpp */; }; DE3452810AEF1B1800DBC861 /* Stmt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3452800AEF1B1800DBC861 /* Stmt.h */; }; DE345C1A0AFC658B00DBC861 /* StmtVisitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345C190AFC658B00DBC861 /* StmtVisitor.h */; }; DE345F220AFD347900DBC861 /* StmtNodes.def in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE345F210AFD347900DBC861 /* StmtNodes.def */; }; @@ -184,11 +197,9 @@ DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */; }; DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */; }; DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */; }; - DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */; }; DE3464220B03040900DBC861 /* Type.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3464210B03040900DBC861 /* Type.h */; }; DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE37252D0FE481AD00CF2CC2 /* Builtins.cpp */; }; DE38CD500D794D0100A273B6 /* CGObjCGNU.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */; }; - DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */; }; DE3986F00CB8D4B300223765 /* IdentifierTable.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE3986EF0CB8D4B300223765 /* IdentifierTable.h */; }; DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */; }; DE4121350D7F1C1C0080F80A /* SymbolManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4121270D7F1C1C0080F80A /* SymbolManager.cpp */; }; @@ -218,13 +229,11 @@ DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */; }; DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE704DD10D1668A4009C7762 /* HeaderMap.cpp */; }; DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; }; - DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; }; DE85CD810D8380B10070E26E /* TokenLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CD800D8380B10070E26E /* TokenLexer.cpp */; }; DE85CDA30D8383B20070E26E /* MacroArgs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDA20D8383B20070E26E /* MacroArgs.cpp */; }; DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAB0D838C120070E26E /* PPMacroExpansion.cpp */; }; DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDAF0D838C390070E26E /* PPDirectives.cpp */; }; DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */; }; - DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE8823CA0ED0046600CBC30A /* APValue.cpp */; }; DE928B130C05659200231DA4 /* ModuleBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B120C05659200231DA4 /* ModuleBuilder.cpp */; }; DE928B200C0565B000231DA4 /* ModuleBuilder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B1F0C0565B000231DA4 /* ModuleBuilder.h */; }; DE928B7D0C0A615100231DA4 /* CodeGenModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE928B7C0C0A615100231DA4 /* CodeGenModule.h */; }; @@ -233,7 +242,6 @@ DE928B830C0A616000231DA4 /* CodeGenFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */; }; DEAEE98B0A5A2B970045101B /* MultipleIncludeOpt.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */; }; DEAEED4B0A5AF89A0045101B /* NOTES.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEAEED4A0A5AF89A0045101B /* NOTES.txt */; }; - DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */; }; DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */; }; DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */; }; DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; }; @@ -246,7 +254,6 @@ DECB77F70FA5850200F5FBC7 /* PCHWriterDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */; }; DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */; }; DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED626C80AE0C065001E80A4 /* TargetInfo.cpp */; }; - DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */; }; DED7D7410A524295003AD0FB /* Diagnostic.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7310A524295003AD0FB /* Diagnostic.h */; }; DED7D7430A524295003AD0FB /* FileManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7330A524295003AD0FB /* FileManager.h */; }; DED7D7450A524295003AD0FB /* SourceLocation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7350A524295003AD0FB /* SourceLocation.h */; }; @@ -269,7 +276,6 @@ DED7D7D80A524302003AD0FB /* README.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D7D70A524302003AD0FB /* README.txt */; }; DED7D9180A52518C003AD0FB /* ScratchBuffer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DED7D9170A52518C003AD0FB /* ScratchBuffer.h */; }; DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; }; - DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */; }; DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6450F7B3B4E0035BD10 /* driver.cpp */; }; DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6480F7B3B830035BD10 /* Types.cpp */; }; DEDFE65B0F7B3B830035BD10 /* Tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE64A0F7B3B830035BD10 /* Tools.cpp */; }; @@ -286,7 +292,6 @@ DEDFE6660F7B3B830035BD10 /* Tool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6570F7B3B830035BD10 /* Tool.cpp */; }; DEDFE6670F7B3B830035BD10 /* HostInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */; }; DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFE6590F7B3B830035BD10 /* Driver.cpp */; }; - DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEDFF8870F848CF80035BD10 /* TemplateName.cpp */; }; DEEBBD440C19C5D200A9FE82 /* TODO.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBBD430C19C5D200A9FE82 /* TODO.txt */; }; DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEEBC3B90C2363B800A9FE82 /* CodeGenTypes.h */; }; DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEEBC3BB0C2363BC00A9FE82 /* CodeGenTypes.cpp */; }; @@ -294,7 +299,6 @@ DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF165740F8FB3510098507F /* PCHReader.cpp */; }; DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF1683F0F9548DC0098507F /* FixItRewriter.cpp */; }; DEF2E95F0C5FBD74000C4259 /* InternalsManual.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */; }; - DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */; }; DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */; }; DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */; }; DEF7D9F70C9C8B1A0001F598 /* Rewriter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */; }; @@ -365,7 +369,15 @@ /* Begin PBXFileReference section */ 035611470DA6A45C00D2EF2A /* DeclBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclBase.h; path = clang/AST/DeclBase.h; sourceTree = ""; tabWidth = 2; }; 03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = ""; tabWidth = 2; }; - 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclPrinter.cpp; path = lib/AST/DeclPrinter.cpp; sourceTree = ""; tabWidth = 2; }; + 1A15C407118226980092260D /* ASTImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTImporter.h; path = clang/AST/ASTImporter.h; sourceTree = ""; tabWidth = 2; }; + 1A15C408118226980092260D /* ASTVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTVector.h; path = clang/AST/ASTVector.h; sourceTree = ""; tabWidth = 2; }; + 1A15C409118226980092260D /* CharUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CharUnits.h; path = clang/AST/CharUnits.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40A118226980092260D /* DeclAccessPair.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclAccessPair.h; path = clang/AST/DeclAccessPair.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40B118226980092260D /* DeclFriend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclFriend.h; path = clang/AST/DeclFriend.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40C118226980092260D /* DependentDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DependentDiagnostic.h; path = clang/AST/DependentDiagnostic.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40D118226980092260D /* TemplateBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateBase.h; path = clang/AST/TemplateBase.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40E118226980092260D /* UnresolvedSet.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UnresolvedSet.h; path = clang/AST/UnresolvedSet.h; sourceTree = ""; tabWidth = 2; }; + 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = UsuallyTinyPtrVector.h; path = clang/AST/UsuallyTinyPtrVector.h; sourceTree = ""; tabWidth = 2; }; 1A2193CB0F45EEB700C0713D /* ABIInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ABIInfo.h; path = lib/CodeGen/ABIInfo.h; sourceTree = ""; tabWidth = 2; }; 1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = ""; tabWidth = 2; }; 1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = ""; tabWidth = 2; }; @@ -386,12 +398,10 @@ 1A2A54B40FD1DD1C00F4CE45 /* Warnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Warnings.cpp; path = lib/Frontend/Warnings.cpp; sourceTree = ""; }; 1A30A9E80B93A4C800201A91 /* ExprCXX.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprCXX.h; path = clang/AST/ExprCXX.h; sourceTree = ""; tabWidth = 2; }; 1A31B27210ACE6DA009E0C8B /* GlobalDecl.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = GlobalDecl.h; path = lib/CodeGen/GlobalDecl.h; sourceTree = ""; tabWidth = 2; }; - 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprConstant.cpp; path = lib/AST/ExprConstant.cpp; sourceTree = ""; tabWidth = 2; }; 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = ""; tabWidth = 2; }; 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = ""; tabWidth = 2; }; 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGClass.cpp; path = lib/CodeGen/CGClass.cpp; sourceTree = ""; tabWidth = 2; }; - 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = ""; }; - 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = ""; }; + 1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = ""; tabWidth = 2; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = ""; tabWidth = 2; }; 1A621BB5110FE6AA009E6834 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = TargetInfo.cpp; path = lib/CodeGen/TargetInfo.cpp; sourceTree = ""; tabWidth = 2; }; 1A621BB6110FE6AA009E6834 /* TargetInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetInfo.h; path = lib/CodeGen/TargetInfo.h; sourceTree = ""; tabWidth = 2; }; @@ -422,19 +432,52 @@ 1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAccess.cpp; path = lib/Sema/SemaAccess.cpp; sourceTree = ""; tabWidth = 2; }; 1A72BEAC0D641E9400B085E9 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Attr.h; path = clang/AST/Attr.h; sourceTree = ""; tabWidth = 2; }; 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = ""; tabWidth = 2; }; - 1A81AA18108144F40094E50B /* CGVtable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVtable.cpp; path = lib/CodeGen/CGVtable.cpp; sourceTree = ""; tabWidth = 2; }; - 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = ""; tabWidth = 2; }; + 1A81AA18108144F40094E50B /* CGVTables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTables.cpp; path = lib/CodeGen/CGVTables.cpp; sourceTree = ""; tabWidth = 2; }; + 1A81AA5D108278A20094E50B /* CGVTables.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVTables.h; path = lib/CodeGen/CGVTables.h; sourceTree = ""; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = ""; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = ""; }; - 1A96785111486FDC00F24372 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayout.cpp; path = lib/AST/RecordLayout.cpp; sourceTree = ""; tabWidth = 2; }; 1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = ""; tabWidth = 2; }; 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = ""; tabWidth = 2; }; - 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; - 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; 1AA963AB10D8576800786C86 /* FullExpr.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = FullExpr.h; path = clang/AST/FullExpr.h; sourceTree = ""; tabWidth = 2; }; - 1AA963C310D85A7300786C86 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = FullExpr.cpp; path = lib/AST/FullExpr.cpp; sourceTree = ""; tabWidth = 2; }; 1AB290021045858B00FE33D8 /* PartialDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = PartialDiagnostic.h; sourceTree = ""; tabWidth = 2; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = ""; tabWidth = 2; }; + 1ABD23B11182449800A48E65 /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = APValue.cpp; sourceTree = ""; }; + 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTConsumer.cpp; sourceTree = ""; }; + 1ABD23B31182449800A48E65 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTContext.cpp; sourceTree = ""; }; + 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTDiagnostic.cpp; sourceTree = ""; }; + 1ABD23B51182449800A48E65 /* ASTImporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTImporter.cpp; sourceTree = ""; }; + 1ABD23B61182449800A48E65 /* AttrImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AttrImpl.cpp; sourceTree = ""; }; + 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CXXInheritance.cpp; sourceTree = ""; }; + 1ABD23B81182449800A48E65 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Decl.cpp; sourceTree = ""; }; + 1ABD23B91182449800A48E65 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarationName.cpp; sourceTree = ""; }; + 1ABD23BA1182449800A48E65 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclBase.cpp; sourceTree = ""; }; + 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclCXX.cpp; sourceTree = ""; }; + 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclFriend.cpp; sourceTree = ""; }; + 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclGroup.cpp; sourceTree = ""; }; + 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclObjC.cpp; sourceTree = ""; }; + 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclPrinter.cpp; sourceTree = ""; }; + 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclTemplate.cpp; sourceTree = ""; }; + 1ABD23C11182449800A48E65 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expr.cpp; sourceTree = ""; }; + 1ABD23C21182449800A48E65 /* ExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprConstant.cpp; sourceTree = ""; }; + 1ABD23C31182449800A48E65 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExprCXX.cpp; sourceTree = ""; }; + 1ABD23C41182449800A48E65 /* FullExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FullExpr.cpp; sourceTree = ""; }; + 1ABD23C51182449800A48E65 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InheritViz.cpp; sourceTree = ""; }; + 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NestedNameSpecifier.cpp; sourceTree = ""; }; + 1ABD23C71182449800A48E65 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentMap.cpp; sourceTree = ""; }; + 1ABD23C81182449800A48E65 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayout.cpp; sourceTree = ""; }; + 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordLayoutBuilder.cpp; sourceTree = ""; }; + 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordLayoutBuilder.h; sourceTree = ""; }; + 1ABD23CB1182449800A48E65 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Stmt.cpp; sourceTree = ""; }; + 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtDumper.cpp; sourceTree = ""; }; + 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtIterator.cpp; sourceTree = ""; }; + 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtPrinter.cpp; sourceTree = ""; }; + 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtProfile.cpp; sourceTree = ""; }; + 1ABD23D01182449800A48E65 /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StmtViz.cpp; sourceTree = ""; }; + 1ABD23D11182449800A48E65 /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateBase.cpp; sourceTree = ""; }; + 1ABD23D21182449800A48E65 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemplateName.cpp; sourceTree = ""; }; + 1ABD23D31182449800A48E65 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Type.cpp; sourceTree = ""; }; + 1ABD23D41182449800A48E65 /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypeLoc.cpp; sourceTree = ""; }; + 1ABD23D51182449800A48E65 /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TypePrinter.cpp; sourceTree = ""; }; 1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInstance.cpp; path = lib/Frontend/CompilerInstance.cpp; sourceTree = ""; }; 1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CompilerInvocation.cpp; path = lib/Frontend/CompilerInvocation.cpp; sourceTree = ""; }; 1ACB57DD1105820D0047B991 /* DeclXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclXML.cpp; path = lib/Frontend/DeclXML.cpp; sourceTree = ""; }; @@ -444,12 +487,8 @@ 1ACB57E11105820D0047B991 /* LangStandards.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LangStandards.cpp; path = lib/Frontend/LangStandards.cpp; sourceTree = ""; }; 1ACB57E21105820D0047B991 /* TypeXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeXML.cpp; path = lib/Frontend/TypeXML.cpp; sourceTree = ""; }; 1ACB57E31105820D0047B991 /* VerifyDiagnosticsClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDiagnosticsClient.cpp; path = lib/Frontend/VerifyDiagnosticsClient.cpp; sourceTree = ""; }; - 1ADD795110A90C6100741BBA /* TypePrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypePrinter.cpp; path = lib/AST/TypePrinter.cpp; sourceTree = ""; }; - 1ADD795210A90C6100741BBA /* TypeLoc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeLoc.cpp; path = lib/AST/TypeLoc.cpp; sourceTree = ""; }; - 1ADD795310A90C6100741BBA /* TemplateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateBase.cpp; path = lib/AST/TemplateBase.cpp; sourceTree = ""; }; 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = ""; tabWidth = 2; }; 1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = ""; tabWidth = 2; }; - 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = ""; tabWidth = 2; }; 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = ""; tabWidth = 2; }; 1AFDD8701161085D00AE030A /* ASTMerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTMerge.cpp; path = lib/Frontend/ASTMerge.cpp; sourceTree = ""; }; 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenAction.cpp; path = lib/Frontend/CodeGenAction.cpp; sourceTree = ""; }; @@ -460,7 +499,6 @@ 352246E40F5C6BE000D0D279 /* PlistDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlistDiagnostics.cpp; path = lib/Frontend/PlistDiagnostics.cpp; sourceTree = ""; }; 352246E50F5C6BE000D0D279 /* TextDiagnosticBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticBuffer.cpp; path = lib/Frontend/TextDiagnosticBuffer.cpp; sourceTree = ""; }; 352246E60F5C6BE000D0D279 /* TextDiagnosticPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextDiagnosticPrinter.cpp; path = lib/Frontend/TextDiagnosticPrinter.cpp; sourceTree = ""; }; - 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = lib/AST/ExprCXX.cpp; sourceTree = ""; tabWidth = 2; }; 3527124F0DAFE54700C76352 /* IdentifierResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = IdentifierResolver.h; path = lib/Sema/IdentifierResolver.h; sourceTree = ""; tabWidth = 2; }; 352712500DAFE54700C76352 /* IdentifierResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = IdentifierResolver.cpp; path = lib/Sema/IdentifierResolver.cpp; sourceTree = ""; tabWidth = 2; }; 352C19DC0CA321C80045DB98 /* CFGRecStmtDeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFGRecStmtDeclVisitor.h; path = clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h; sourceTree = ""; }; @@ -473,7 +511,6 @@ 3537AA0C0ECD088F008F7CDC /* BlkExprDeclBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlkExprDeclBitVector.h; path = clang/Analysis/Support/BlkExprDeclBitVector.h; sourceTree = ""; }; 3537AA0D0ECD08A4008F7CDC /* PreprocessorLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreprocessorLexer.cpp; sourceTree = ""; }; 3538FDB60ED24A2C005EC283 /* DeclarationName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclarationName.h; path = clang/AST/DeclarationName.h; sourceTree = ""; tabWidth = 2; }; - 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclarationName.cpp; path = lib/AST/DeclarationName.cpp; sourceTree = ""; }; 353959D40EE5F88A00E82461 /* ParseTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseTemplate.cpp; path = lib/Parse/ParseTemplate.cpp; sourceTree = ""; tabWidth = 2; }; 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = ""; tabWidth = 2; }; 35475B1F0E79973F0000BFE4 /* CGCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCall.cpp; path = lib/CodeGen/CGCall.cpp; sourceTree = ""; tabWidth = 2; }; @@ -492,7 +529,6 @@ 35544B860F5C7FD700D92AA9 /* SimpleConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SimpleConstraintManager.cpp; path = lib/Analysis/SimpleConstraintManager.cpp; sourceTree = ""; }; 35544B870F5C7FD700D92AA9 /* SimpleConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SimpleConstraintManager.h; path = lib/Analysis/SimpleConstraintManager.h; sourceTree = ""; }; 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiate.cpp; path = lib/Sema/SemaTemplateInstantiate.cpp; sourceTree = ""; tabWidth = 2; }; - 3557D1A80EB136B100C59739 /* InheritViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = InheritViz.cpp; path = lib/AST/InheritViz.cpp; sourceTree = ""; tabWidth = 2; }; 35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXFieldCollector.h; path = lib/Sema/CXXFieldCollector.h; sourceTree = ""; tabWidth = 2; }; 35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaOverload.cpp; path = lib/Sema/SemaOverload.cpp; sourceTree = ""; tabWidth = 2; }; 35585DBF0EAFBC4500D0A97A /* SemaOverload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaOverload.h; path = lib/Sema/SemaOverload.h; sourceTree = ""; tabWidth = 2; }; @@ -504,12 +540,10 @@ 35707EFD0CD0F5CC000B2204 /* SourceLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = SourceLocation.cpp; sourceTree = ""; tabWidth = 2; }; 357EA27C0F2526F300439B60 /* SemaLookup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaLookup.cpp; path = lib/Sema/SemaLookup.cpp; sourceTree = ""; tabWidth = 2; }; 35847BE30CC7DB9000C40FFF /* StmtIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtIterator.h; path = clang/AST/StmtIterator.h; sourceTree = ""; tabWidth = 2; }; - 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtIterator.cpp; path = lib/AST/StmtIterator.cpp; sourceTree = ""; tabWidth = 2; }; 35862B0C0E3628CB0009F542 /* CheckDeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckDeadStores.cpp; path = lib/Analysis/CheckDeadStores.cpp; sourceTree = ""; }; 35862B110E3629850009F542 /* GRExprEngineInternalChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRExprEngineInternalChecks.cpp; path = lib/Analysis/GRExprEngineInternalChecks.cpp; sourceTree = ""; }; 358CFBB70E65AB04002A8E19 /* BasicConstraintManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicConstraintManager.cpp; path = lib/Analysis/BasicConstraintManager.cpp; sourceTree = ""; }; 358D23090E8BEB850003DDCC /* DeclGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclGroup.h; path = clang/AST/DeclGroup.h; sourceTree = ""; tabWidth = 2; }; - 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclGroup.cpp; path = lib/AST/DeclGroup.cpp; sourceTree = ""; tabWidth = 2; }; 358F514F0E529A87007F2102 /* GRState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRState.h; path = clang/Analysis/PathSensitive/GRState.h; sourceTree = ""; }; 358F51510E529AA4007F2102 /* GRState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRState.cpp; path = lib/Analysis/GRState.cpp; sourceTree = ""; }; 3591853E0EFB1088000039AF /* SemaTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplate.cpp; path = lib/Sema/SemaTemplate.cpp; sourceTree = ""; tabWidth = 2; }; @@ -528,10 +562,8 @@ 35A8FCF80D9B4B29001C2F97 /* PathDiagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathDiagnostic.cpp; path = lib/Analysis/PathDiagnostic.cpp; sourceTree = ""; }; 35B820740ECB811A0020BEC0 /* PreprocessorLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreprocessorLexer.h; sourceTree = ""; }; 35BAC1E70E82C5B7003FB76F /* CheckNSError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckNSError.cpp; path = lib/Analysis/CheckNSError.cpp; sourceTree = ""; }; - 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumer.cpp; path = lib/AST/ASTConsumer.cpp; sourceTree = ""; tabWidth = 2; }; 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTConsumer.h; path = clang/AST/ASTConsumer.h; sourceTree = ""; tabWidth = 2; }; 35CEA05A0DF9E82700A41296 /* ExprObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExprObjC.h; path = clang/AST/ExprObjC.h; sourceTree = ""; tabWidth = 2; }; - 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtViz.cpp; path = lib/AST/StmtViz.cpp; sourceTree = ""; tabWidth = 2; }; 35CFFE010CA1CBDD00E6F2BE /* StmtGraphTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtGraphTraits.h; path = clang/AST/StmtGraphTraits.h; sourceTree = ""; tabWidth = 2; }; 35D1DDD10CA9C6D50096E967 /* DataflowSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowSolver.h; path = clang/Analysis/FlowSensitive/DataflowSolver.h; sourceTree = ""; }; 35D1DDD20CA9C6D50096E967 /* DataflowValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataflowValues.h; path = clang/Analysis/FlowSensitive/DataflowValues.h; sourceTree = ""; }; @@ -543,8 +575,6 @@ 35E1946C0ECB83C100F21733 /* PTHLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PTHLexer.cpp; sourceTree = ""; }; 35EE48AD0E0C4CB200715C54 /* DeclCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclCXX.h; path = clang/AST/DeclCXX.h; sourceTree = ""; tabWidth = 2; }; 35EE48AE0E0C4CB200715C54 /* ParentMap.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ParentMap.h; path = clang/AST/ParentMap.h; sourceTree = ""; tabWidth = 2; }; - 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclCXX.cpp; path = lib/AST/DeclCXX.cpp; sourceTree = ""; tabWidth = 2; }; - 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParentMap.cpp; path = lib/AST/ParentMap.cpp; sourceTree = ""; tabWidth = 2; }; 35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclCXX.cpp; path = lib/Sema/SemaDeclCXX.cpp; sourceTree = ""; tabWidth = 2; }; 35EFEFB50DB67ED60020783D /* GRTransferFuncs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GRTransferFuncs.cpp; path = lib/Analysis/GRTransferFuncs.cpp; sourceTree = ""; }; 35F1ACE60E66166C001F4532 /* ConstraintManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConstraintManager.h; path = clang/Analysis/PathSensitive/ConstraintManager.h; sourceTree = ""; }; @@ -555,7 +585,6 @@ 35F8D0D50D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BasicObjCFoundationChecks.cpp; path = lib/Analysis/BasicObjCFoundationChecks.cpp; sourceTree = ""; }; 35F9B1550D1C6B2E00DDFDAE /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/Analyses/LiveVariables.h; sourceTree = ""; }; 35F9B1560D1C6B2E00DDFDAE /* UninitializedValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UninitializedValues.h; path = clang/Analysis/Analyses/UninitializedValues.h; sourceTree = ""; }; - 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclBase.cpp; path = lib/AST/DeclBase.cpp; sourceTree = ""; tabWidth = 2; }; 72D16C1E0D9975C400E6DA4A /* HTMLRewrite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLRewrite.cpp; path = lib/Rewrite/HTMLRewrite.cpp; sourceTree = ""; }; 7F270AFE107A90010031B377 /* CodeCompleteConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeCompleteConsumer.h; path = clang/Sema/CodeCompleteConsumer.h; sourceTree = ""; }; 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = ""; tabWidth = 2; }; @@ -565,13 +594,13 @@ 9012911510470FCE0083456D /* Index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Index.h; path = "clang-c/Index.h"; sourceTree = ""; }; 9012911C1048068D0083456D /* ASTUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTUnit.cpp; path = lib/Frontend/ASTUnit.cpp; sourceTree = ""; }; 9012911F104812F90083456D /* CIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CIndex.cpp; path = tools/CIndex/CIndex.cpp; sourceTree = ""; }; - 904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = ""; }; - 9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = ""; }; - 9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = ""; }; - 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = ""; }; - 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = ""; }; - 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = ""; }; - 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = ""; }; + 904753791096376F00CBDDDD /* CXXInheritance.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CXXInheritance.h; path = clang/AST/CXXInheritance.h; sourceTree = ""; tabWidth = 2; }; + 9047537A1096376F00CBDDDD /* Redeclarable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Redeclarable.h; path = clang/AST/Redeclarable.h; sourceTree = ""; tabWidth = 2; }; + 9047537B1096376F00CBDDDD /* TypeLoc.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLoc.h; path = clang/AST/TypeLoc.h; sourceTree = ""; tabWidth = 2; }; + 9047537C1096376F00CBDDDD /* TypeLocBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocBuilder.h; path = clang/AST/TypeLocBuilder.h; sourceTree = ""; tabWidth = 2; }; + 9047537D1096376F00CBDDDD /* TypeLocNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeLocNodes.def; path = clang/AST/TypeLocNodes.def; sourceTree = ""; tabWidth = 2; }; + 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeLocVisitor.h; path = clang/AST/TypeLocVisitor.h; sourceTree = ""; tabWidth = 2; }; + 9047537F1096376F00CBDDDD /* TypeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeVisitor.h; path = clang/AST/TypeVisitor.h; sourceTree = ""; tabWidth = 2; }; 9063F2210F9E8BDF002F7251 /* ExternalSemaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalSemaSource.h; path = clang/Sema/ExternalSemaSource.h; sourceTree = ""; }; 9063F2220F9E8BDF002F7251 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = ""; }; 9063F2280F9E911F002F7251 /* OnDiskHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnDiskHashTable.h; sourceTree = ""; }; @@ -580,9 +609,9 @@ 906BF4AE0F83BA16001071FA /* ConvertUTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertUTF.h; sourceTree = ""; }; 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConvertUTF.c; sourceTree = ""; }; 90F9EFA9104ABDED00D09A15 /* c-index-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "c-index-test.c"; path = "tools/c-index-test/c-index-test.c"; sourceTree = ""; }; - 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = ""; }; - 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = ""; }; - 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = ""; }; + 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = ""; tabWidth = 2; }; + 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = ""; tabWidth = 2; }; + 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = ""; tabWidth = 2; }; 90FD6D5F103C3D21005F5B73 /* Analyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Analyzer.h; path = clang/Index/Analyzer.h; sourceTree = ""; }; 90FD6D60103C3D21005F5B73 /* ASTLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTLocation.h; path = clang/Index/ASTLocation.h; sourceTree = ""; }; 90FD6D61103C3D21005F5B73 /* DeclReferenceMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclReferenceMap.h; path = clang/Index/DeclReferenceMap.h; sourceTree = ""; }; @@ -640,9 +669,7 @@ DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = lib/Parse/Parser.cpp; sourceTree = ""; tabWidth = 2; }; DE06E8130A8FF9330050E87E /* Action.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Action.h; path = clang/Parse/Action.h; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; DE0FCA620A95859D00248FD5 /* Expr.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Expr.h; path = clang/AST/Expr.h; sourceTree = ""; tabWidth = 2; }; - DE0FCB330A9C21F100248FD5 /* Expr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Expr.cpp; path = lib/AST/Expr.cpp; sourceTree = ""; tabWidth = 2; }; DE1263C20EF2341900F56D2B /* Ownership.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Ownership.h; path = clang/Parse/Ownership.h; sourceTree = ""; tabWidth = 2; }; - DE1732FF0B068B700080B521 /* ASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTContext.cpp; path = lib/AST/ASTContext.cpp; sourceTree = ""; tabWidth = 2; }; DE17336D0B068DC20080B521 /* DeclSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclSpec.cpp; path = lib/Parse/DeclSpec.cpp; sourceTree = ""; tabWidth = 2; }; DE17336F0B068DC60080B521 /* DeclSpec.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclSpec.h; path = clang/Parse/DeclSpec.h; sourceTree = ""; tabWidth = 2; }; DE1F22020A7D852A00FBF588 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Parser.h; path = clang/Parse/Parser.h; sourceTree = ""; tabWidth = 2; }; @@ -653,7 +680,6 @@ DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HeaderSearch.h; sourceTree = ""; }; DE344B530AE5E46C00DBC861 /* HeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderSearch.cpp; sourceTree = ""; }; DE3450D60AEB543100DBC861 /* DirectoryLookup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DirectoryLookup.h; sourceTree = ""; }; - DE3452400AEF1A2D00DBC861 /* Stmt.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Stmt.cpp; path = lib/AST/Stmt.cpp; sourceTree = ""; tabWidth = 2; }; DE3452800AEF1B1800DBC861 /* Stmt.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Stmt.h; path = clang/AST/Stmt.h; sourceTree = ""; tabWidth = 2; }; DE345C190AFC658B00DBC861 /* StmtVisitor.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtVisitor.h; path = clang/AST/StmtVisitor.h; sourceTree = ""; tabWidth = 2; }; DE345F210AFD347900DBC861 /* StmtNodes.def */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = text; name = StmtNodes.def; path = clang/AST/StmtNodes.def; sourceTree = ""; tabWidth = 2; }; @@ -663,7 +689,6 @@ DE34600E0AFDCCCE00DBC861 /* ParseDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseDecl.cpp; path = lib/Parse/ParseDecl.cpp; sourceTree = ""; tabWidth = 2; }; DE3460120AFDCCDA00DBC861 /* ParseExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExpr.cpp; path = lib/Parse/ParseExpr.cpp; sourceTree = ""; tabWidth = 2; }; DE3461260AFE68BE00DBC861 /* MinimalAction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = MinimalAction.cpp; path = lib/Parse/MinimalAction.cpp; sourceTree = ""; tabWidth = 2; }; - DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtPrinter.cpp; path = lib/AST/StmtPrinter.cpp; sourceTree = ""; tabWidth = 2; }; DE3464210B03040900DBC861 /* Type.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Type.h; path = clang/AST/Type.h; sourceTree = ""; tabWidth = 2; }; DE37251C0FE4818000CF2CC2 /* Builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Builtins.h; sourceTree = ""; }; DE37252A0FE4818F00CF2CC2 /* Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Builtins.def; sourceTree = ""; }; @@ -673,7 +698,6 @@ DE3725330FE4827200CF2CC2 /* BuiltinsPPC.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BuiltinsPPC.def; sourceTree = ""; }; DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGObjCRuntime.h; path = lib/CodeGen/CGObjCRuntime.h; sourceTree = ""; tabWidth = 2; }; DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjCGNU.cpp; path = lib/CodeGen/CGObjCGNU.cpp; sourceTree = ""; tabWidth = 2; }; - DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclObjC.cpp; path = lib/AST/DeclObjC.cpp; sourceTree = ""; tabWidth = 2; }; DE3986EF0CB8D4B300223765 /* IdentifierTable.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IdentifierTable.h; sourceTree = ""; tabWidth = 2; }; DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = ""; tabWidth = 2; }; DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = ""; tabWidth = 2; }; @@ -717,7 +741,6 @@ DE704BD10D1647E7009C7762 /* HeaderMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeaderMap.h; sourceTree = ""; }; DE704DD10D1668A4009C7762 /* HeaderMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeaderMap.cpp; sourceTree = ""; }; DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = ""; tabWidth = 2; }; - DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = lib/AST/Type.cpp; sourceTree = ""; tabWidth = 2; }; DE85CD800D8380B10070E26E /* TokenLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenLexer.cpp; sourceTree = ""; }; DE85CD840D8380F20070E26E /* TokenLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenLexer.h; sourceTree = ""; }; DE85CD9E0D8382DD0070E26E /* MacroArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroArgs.h; sourceTree = ""; }; @@ -726,7 +749,6 @@ DE85CDAF0D838C390070E26E /* PPDirectives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPDirectives.cpp; sourceTree = ""; }; DE85CDB50D839BAE0070E26E /* PPLexerChange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PPLexerChange.cpp; sourceTree = ""; }; DE8822350EC80C0A00CBC30A /* CGBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGBuilder.h; path = lib/CodeGen/CGBuilder.h; sourceTree = ""; tabWidth = 2; }; - DE8823CA0ED0046600CBC30A /* APValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = APValue.cpp; path = lib/AST/APValue.cpp; sourceTree = ""; }; DE8823DE0ED0B78600CBC30A /* PTHLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHLexer.h; sourceTree = ""; }; DE8824530ED1243E00CBC30A /* OperatorKinds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OperatorKinds.h; sourceTree = ""; }; DE8824560ED1244600CBC30A /* OperatorKinds.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OperatorKinds.def; sourceTree = ""; }; @@ -744,7 +766,6 @@ DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = ""; }; DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = ""; }; DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = ""; tabWidth = 2; }; - DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = ""; tabWidth = 2; }; DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = ""; }; DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = ""; }; DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = ""; tabWidth = 2; }; @@ -755,15 +776,13 @@ DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = ""; tabWidth = 2; }; DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitPreprocessor.h; path = clang/Frontend/InitPreprocessor.h; sourceTree = ""; }; DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitPreprocessor.cpp; path = lib/Frontend/InitPreprocessor.cpp; sourceTree = ""; }; - DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = ""; }; - DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = ""; }; + DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = ""; tabWidth = 2; }; + DECB73550FA3EE5A00F5FBC7 /* StmtCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = StmtCXX.h; path = clang/AST/StmtCXX.h; sourceTree = ""; tabWidth = 2; }; DECB77120FA5752300F5FBC7 /* PCHReaderStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderStmt.cpp; path = lib/Frontend/PCHReaderStmt.cpp; sourceTree = ""; tabWidth = 2; }; DECB77780FA579B000F5FBC7 /* PCHReaderDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHReaderDecl.cpp; path = lib/Frontend/PCHReaderDecl.cpp; sourceTree = ""; }; DECB77F60FA5850200F5FBC7 /* PCHWriterDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterDecl.cpp; path = lib/Frontend/PCHWriterDecl.cpp; sourceTree = ""; }; DECB78160FA5882F00F5FBC7 /* PCHWriterStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PCHWriterStmt.cpp; path = lib/Frontend/PCHWriterStmt.cpp; sourceTree = ""; }; - DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AccessSpecifier.h; path = clang/Parse/AccessSpecifier.h; sourceTree = ""; }; DED626C80AE0C065001E80A4 /* TargetInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = TargetInfo.cpp; sourceTree = ""; tabWidth = 2; }; - DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Decl.cpp; path = lib/AST/Decl.cpp; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; DED7D7310A524295003AD0FB /* Diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = Diagnostic.h; sourceTree = ""; tabWidth = 2; }; DED7D7330A524295003AD0FB /* FileManager.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = FileManager.h; sourceTree = ""; tabWidth = 2; }; DED7D7350A524295003AD0FB /* SourceLocation.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = SourceLocation.h; sourceTree = ""; tabWidth = 2; }; @@ -787,8 +806,7 @@ DED7D9170A52518C003AD0FB /* ScratchBuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScratchBuffer.h; sourceTree = ""; }; DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScratchBuffer.cpp; sourceTree = ""; }; DEDFE5270F63A9230035BD10 /* DeclNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = DeclNodes.def; path = clang/AST/DeclNodes.def; sourceTree = ""; tabWidth = 2; }; - DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = ""; }; - DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NestedNameSpecifier.cpp; path = lib/AST/NestedNameSpecifier.cpp; sourceTree = ""; }; + DEDFE5CB0F7206CC0035BD10 /* NestedNameSpecifier.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = NestedNameSpecifier.h; path = clang/AST/NestedNameSpecifier.h; sourceTree = ""; tabWidth = 2; }; DEDFE6450F7B3B4E0035BD10 /* driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = driver.cpp; path = tools/driver/driver.cpp; sourceTree = ""; }; DEDFE6480F7B3B830035BD10 /* Types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Types.cpp; path = lib/Driver/Types.cpp; sourceTree = ""; }; DEDFE6490F7B3B830035BD10 /* Tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Tools.h; path = lib/Driver/Tools.h; sourceTree = ""; }; @@ -808,8 +826,7 @@ DEDFE6570F7B3B830035BD10 /* Tool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tool.cpp; path = lib/Driver/Tool.cpp; sourceTree = ""; }; DEDFE6580F7B3B830035BD10 /* HostInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HostInfo.cpp; path = lib/Driver/HostInfo.cpp; sourceTree = ""; }; DEDFE6590F7B3B830035BD10 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = lib/Driver/Driver.cpp; sourceTree = ""; }; - DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = ""; }; - DEDFF8870F848CF80035BD10 /* TemplateName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateName.cpp; path = lib/AST/TemplateName.cpp; sourceTree = ""; }; + DEDFF87F0F848CE30035BD10 /* TemplateName.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TemplateName.h; path = clang/AST/TemplateName.h; sourceTree = ""; tabWidth = 2; }; DEDFFF070F959EE60035BD10 /* Diagnostic.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Diagnostic.td; sourceTree = ""; }; DEDFFF530F9704580035BD10 /* DiagnosticGroups.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticGroups.td; sourceTree = ""; }; DEEBBD430C19C5D200A9FE82 /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO.txt; sourceTree = ""; }; @@ -847,10 +864,9 @@ DEF168620F9549250098507F /* FixItRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FixItRewriter.h; path = clang/Frontend/FixItRewriter.h; sourceTree = ""; }; DEF169220F9645960098507F /* FrontendDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FrontendDiagnostic.h; path = clang/Frontend/FrontendDiagnostic.h; sourceTree = ""; }; DEF1692C0F9645BF0098507F /* AnalysisDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisDiagnostic.h; path = clang/Analysis/AnalysisDiagnostic.h; sourceTree = ""; }; - DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = ""; }; - DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = ""; }; + DEF16BE40FA13A5B0098507F /* TypeNodes.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = TypeNodes.def; path = clang/AST/TypeNodes.def; sourceTree = ""; tabWidth = 2; }; + DEF16BE50FA13A650098507F /* TypeOrdering.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TypeOrdering.h; path = clang/AST/TypeOrdering.h; sourceTree = ""; tabWidth = 2; }; DEF2E95E0C5FBD74000C4259 /* InternalsManual.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; name = InternalsManual.html; path = docs/InternalsManual.html; sourceTree = ""; }; - DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtDumper.cpp; path = lib/AST/StmtDumper.cpp; sourceTree = ""; tabWidth = 2; }; DEF2EFF20C6CDD74000C4259 /* CGExprAgg.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprAgg.cpp; path = lib/CodeGen/CGExprAgg.cpp; sourceTree = ""; tabWidth = 2; }; DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaChecking.cpp; path = lib/Sema/SemaChecking.cpp; sourceTree = ""; tabWidth = 2; }; DEF7D9F60C9C8B1A0001F598 /* Rewriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Rewriter.h; path = clang/Rewrite/Rewriter.h; sourceTree = ""; }; @@ -1363,8 +1379,8 @@ DE4772F90C10EAE5002239E8 /* CGStmt.cpp */, 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */, 35475B230E7997680000BFE4 /* CGValue.h */, - 1A81AA18108144F40094E50B /* CGVtable.cpp */, - 1A81AA5D108278A20094E50B /* CGVtable.h */, + 1A81AA18108144F40094E50B /* CGVTables.cpp */, + 1A81AA5D108278A20094E50B /* CGVTables.h */, 1A97825A1108BA18002B98FC /* CGVTT.cpp */, DE928B800C0A615B00231DA4 /* CodeGenFunction.h */, DE928B820C0A616000231DA4 /* CodeGenFunction.cpp */, @@ -1393,6 +1409,15 @@ DEC8D98B0A9433BC00353FCA /* AST */ = { isa = PBXGroup; children = ( + 1A15C407118226980092260D /* ASTImporter.h */, + 1A15C408118226980092260D /* ASTVector.h */, + 1A15C409118226980092260D /* CharUnits.h */, + 1A15C40A118226980092260D /* DeclAccessPair.h */, + 1A15C40B118226980092260D /* DeclFriend.h */, + 1A15C40C118226980092260D /* DependentDiagnostic.h */, + 1A15C40D118226980092260D /* TemplateBase.h */, + 1A15C40E118226980092260D /* UnresolvedSet.h */, + 1A15C40F118226980092260D /* UsuallyTinyPtrVector.h */, 904753791096376F00CBDDDD /* CXXInheritance.h */, 9047537A1096376F00CBDDDD /* Redeclarable.h */, 9047537B1096376F00CBDDDD /* TypeLoc.h */, @@ -1400,7 +1425,6 @@ 9047537D1096376F00CBDDDD /* TypeLocNodes.def */, 9047537E1096376F00CBDDDD /* TypeLocVisitor.h */, 9047537F1096376F00CBDDDD /* TypeVisitor.h */, - DECB78540FA58F5500F5FBC7 /* AccessSpecifier.h */, DE613EF30E0E148D00B05B79 /* APValue.h */, DEC8D9A30A94346E00353FCA /* AST.h */, 35BFBD2B0C9EDE1E006CB644 /* ASTConsumer.h */, @@ -1445,41 +1469,46 @@ DEC8D9920A9433F400353FCA /* AST */ = { isa = PBXGroup; children = ( - DE8823CA0ED0046600CBC30A /* APValue.cpp */, - 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */, - DE1732FF0B068B700080B521 /* ASTContext.cpp */, - 1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */, - 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */, - DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */, - 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */, - 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */, - 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */, - 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */, - DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */, - DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */, - DE0FCB330A9C21F100248FD5 /* Expr.cpp */, - 1A32C17E0E1C87AD00A6B483 /* ExprConstant.cpp */, - 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */, - 1AA963C310D85A7300786C86 /* FullExpr.cpp */, - 3557D1A80EB136B100C59739 /* InheritViz.cpp */, - DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */, - 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */, - 1A96785111486FDC00F24372 /* RecordLayout.cpp */, - 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */, - 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */, - DE3452400AEF1A2D00DBC861 /* Stmt.cpp */, - DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */, - 35847BE40CC7DBAF00C40FFF /* StmtIterator.cpp */, - DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */, - 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */, - 35CFFDFF0CA1CBCB00E6F2BE /* StmtViz.cpp */, - 1ADD795310A90C6100741BBA /* TemplateBase.cpp */, - DEDFF8870F848CF80035BD10 /* TemplateName.cpp */, - DE75EDF00B06880E0020CF81 /* Type.cpp */, - 1ADD795210A90C6100741BBA /* TypeLoc.cpp */, - 1ADD795110A90C6100741BBA /* TypePrinter.cpp */, + 1ABD23B11182449800A48E65 /* APValue.cpp */, + 1ABD23B21182449800A48E65 /* ASTConsumer.cpp */, + 1ABD23B31182449800A48E65 /* ASTContext.cpp */, + 1ABD23B41182449800A48E65 /* ASTDiagnostic.cpp */, + 1ABD23B51182449800A48E65 /* ASTImporter.cpp */, + 1ABD23B61182449800A48E65 /* AttrImpl.cpp */, + 1ABD23B71182449800A48E65 /* CXXInheritance.cpp */, + 1ABD23B81182449800A48E65 /* Decl.cpp */, + 1ABD23B91182449800A48E65 /* DeclarationName.cpp */, + 1ABD23BA1182449800A48E65 /* DeclBase.cpp */, + 1ABD23BB1182449800A48E65 /* DeclCXX.cpp */, + 1ABD23BC1182449800A48E65 /* DeclFriend.cpp */, + 1ABD23BD1182449800A48E65 /* DeclGroup.cpp */, + 1ABD23BE1182449800A48E65 /* DeclObjC.cpp */, + 1ABD23BF1182449800A48E65 /* DeclPrinter.cpp */, + 1ABD23C01182449800A48E65 /* DeclTemplate.cpp */, + 1ABD23C11182449800A48E65 /* Expr.cpp */, + 1ABD23C21182449800A48E65 /* ExprConstant.cpp */, + 1ABD23C31182449800A48E65 /* ExprCXX.cpp */, + 1ABD23C41182449800A48E65 /* FullExpr.cpp */, + 1ABD23C51182449800A48E65 /* InheritViz.cpp */, + 1ABD23C61182449800A48E65 /* NestedNameSpecifier.cpp */, + 1ABD23C71182449800A48E65 /* ParentMap.cpp */, + 1ABD23C81182449800A48E65 /* RecordLayout.cpp */, + 1ABD23C91182449800A48E65 /* RecordLayoutBuilder.cpp */, + 1ABD23CA1182449800A48E65 /* RecordLayoutBuilder.h */, + 1ABD23CB1182449800A48E65 /* Stmt.cpp */, + 1ABD23CC1182449800A48E65 /* StmtDumper.cpp */, + 1ABD23CD1182449800A48E65 /* StmtIterator.cpp */, + 1ABD23CE1182449800A48E65 /* StmtPrinter.cpp */, + 1ABD23CF1182449800A48E65 /* StmtProfile.cpp */, + 1ABD23D01182449800A48E65 /* StmtViz.cpp */, + 1ABD23D11182449800A48E65 /* TemplateBase.cpp */, + 1ABD23D21182449800A48E65 /* TemplateName.cpp */, + 1ABD23D31182449800A48E65 /* Type.cpp */, + 1ABD23D41182449800A48E65 /* TypeLoc.cpp */, + 1ABD23D51182449800A48E65 /* TypePrinter.cpp */, ); name = AST; + path = lib/AST; sourceTree = ""; }; DED7D72E0A524295003AD0FB /* include */ = { @@ -1791,20 +1820,14 @@ DED7D7C90A5242E6003AD0FB /* Preprocessor.cpp in Sources */, DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */, DE06D4310A8BB52D0050E87E /* Parser.cpp in Sources */, - DE0FCB340A9C21F100248FD5 /* Expr.cpp in Sources */, DED626C90AE0C065001E80A4 /* TargetInfo.cpp in Sources */, - DED62ABB0AE2EDF1001E80A4 /* Decl.cpp in Sources */, DE344B540AE5E46C00DBC861 /* HeaderSearch.cpp in Sources */, - DE3452410AEF1A2D00DBC861 /* Stmt.cpp in Sources */, DE3460000AFDCC1900DBC861 /* ParseObjc.cpp in Sources */, DE3460050AFDCC6500DBC861 /* ParseInit.cpp in Sources */, DE34600B0AFDCCBF00DBC861 /* ParseStmt.cpp in Sources */, DE34600F0AFDCCCE00DBC861 /* ParseDecl.cpp in Sources */, DE3460130AFDCCDA00DBC861 /* ParseExpr.cpp in Sources */, DE3461270AFE68BE00DBC861 /* MinimalAction.cpp in Sources */, - DE34621D0AFEB19B00DBC861 /* StmtPrinter.cpp in Sources */, - DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */, - DE1733000B068B700080B521 /* ASTContext.cpp in Sources */, DE17336E0B068DC20080B521 /* DeclSpec.cpp in Sources */, 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */, DE67E70B0C020EC500F66BC5 /* SemaType.cpp in Sources */, @@ -1823,24 +1846,19 @@ DE4264FC0C113592005A861D /* CGDecl.cpp in Sources */, 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */, DEEBC3BC0C2363BC00A9FE82 /* CodeGenTypes.cpp in Sources */, - DEF2EDA70C6A4252000C4259 /* StmtDumper.cpp in Sources */, DEF2EFF30C6CDD74000C4259 /* CGExprAgg.cpp in Sources */, DEF2F0100C6CFED5000C4259 /* SemaChecking.cpp in Sources */, 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */, DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */, 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */, DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */, - 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */, DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */, 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */, DEF7D9F90C9C8B1D0001F598 /* Rewriter.cpp in Sources */, - 35CFFE000CA1CBCB00E6F2BE /* StmtViz.cpp in Sources */, DE3986F40CB8D50C00223765 /* IdentifierTable.cpp in Sources */, - 35847BE50CC7DBAF00C40FFF /* StmtIterator.cpp in Sources */, 35707EFE0CD0F5CC000B2204 /* SourceLocation.cpp in Sources */, DE704B260D0FBEBE009C7762 /* SemaDeclObjC.cpp in Sources */, DE704DD20D1668A4009C7762 /* HeaderMap.cpp in Sources */, - 35BB2D7F0D19954000944DB5 /* ASTConsumer.cpp in Sources */, DE47999C0D2EBE1A00706D2D /* SemaExprObjC.cpp in Sources */, 03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */, 1A376A2D0D4AED9B002A1C52 /* CGExprConstant.cpp in Sources */, @@ -1859,7 +1877,6 @@ DE85CDAC0D838C120070E26E /* PPMacroExpansion.cpp in Sources */, DE85CDB00D838C390070E26E /* PPDirectives.cpp in Sources */, DE85CDB60D839BAE0070E26E /* PPLexerChange.cpp in Sources */, - DE38CF270D8C9E6C00A273B6 /* DeclObjC.cpp in Sources */, 72D16C1F0D9975C400E6DA4A /* HTMLRewrite.cpp in Sources */, 35A8FCF90D9B4B2A001C2F97 /* PathDiagnostic.cpp in Sources */, 35F8D0D60D9B82CD00D91C5E /* BasicObjCFoundationChecks.cpp in Sources */, @@ -1871,12 +1888,8 @@ 35EFEFB60DB67ED60020783D /* GRTransferFuncs.cpp in Sources */, 35A3E7020DD3874400757F74 /* CGDebugInfo.cpp in Sources */, 3599299B0DE2425300A8A33E /* SemaInit.cpp in Sources */, - 35FE6BCF0DF6EE1F00739712 /* DeclBase.cpp in Sources */, - 35EE48B10E0C4CCA00715C54 /* DeclCXX.cpp in Sources */, - 35EE48B20E0C4CCA00715C54 /* ParentMap.cpp in Sources */, 3534A01D0E129849002709B2 /* ParseCXXInlineMethods.cpp in Sources */, DE22BCF20E14197E0094DC60 /* SemaDeclAttr.cpp in Sources */, - 1A32C17F0E1C87AD00A6B483 /* ExprConstant.cpp in Sources */, 3595AFB80E1C8D62004CDF09 /* CheckObjCDealloc.cpp in Sources */, 3536456B0E23EBF7009C6509 /* Environment.cpp in Sources */, 3558F76D0E267C8300A5B0DF /* BasicStore.cpp in Sources */, @@ -1891,7 +1904,6 @@ 358CFBB80E65AB04002A8E19 /* BasicConstraintManager.cpp in Sources */, 35475B200E79973F0000BFE4 /* CGCall.cpp in Sources */, 35BAC1E80E82C5B7003FB76F /* CheckNSError.cpp in Sources */, - 358D230B0E8BEB9D0003DDCC /* DeclGroup.cpp in Sources */, 355106860E9A8507006A4E44 /* MemRegion.cpp in Sources */, 3551068C0E9A8546006A4E44 /* ParsePragma.cpp in Sources */, 3551068D0E9A8546006A4E44 /* ParseTentative.cpp in Sources */, @@ -1899,17 +1911,13 @@ 35A057E20EAE2D950069249F /* RegionStore.cpp in Sources */, 35A057E30EAE2D950069249F /* SVals.cpp in Sources */, 35585DC00EAFBC4500D0A97A /* SemaOverload.cpp in Sources */, - 3557D1A90EB136B100C59739 /* InheritViz.cpp in Sources */, 35E194690ECB82FB00F21733 /* SemaCXXScopeSpec.cpp in Sources */, 35E1946A0ECB82FB00F21733 /* SemaCXXCast.cpp in Sources */, 35E1946D0ECB83C100F21733 /* PTHLexer.cpp in Sources */, 3537AA0E0ECD08A4008F7CDC /* PreprocessorLexer.cpp in Sources */, - DE8823CB0ED0046600CBC30A /* APValue.cpp in Sources */, - 3538FDB80ED24A4E005EC283 /* DeclarationName.cpp in Sources */, 353959D50EE5F88A00E82461 /* ParseTemplate.cpp in Sources */, 3591853F0EFB1088000039AF /* SemaTemplate.cpp in Sources */, 357EA27D0F2526F300439B60 /* SemaLookup.cpp in Sources */, - DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */, 1A471AB50F437BC500753CE8 /* CGBlocks.cpp in Sources */, DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */, 1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */, @@ -1922,7 +1930,6 @@ 35544B880F5C7FD700D92AA9 /* RangeConstraintManager.cpp in Sources */, 35544B890F5C7FD700D92AA9 /* SimpleConstraintManager.cpp in Sources */, 35544B8C0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp in Sources */, - DEDFE5CF0F7206E40035BD10 /* NestedNameSpecifier.cpp in Sources */, 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */, DEDFE6460F7B3B4E0035BD10 /* driver.cpp in Sources */, DEDFE65A0F7B3B830035BD10 /* Types.cpp in Sources */, @@ -1942,7 +1949,6 @@ DEDFE6680F7B3B830035BD10 /* Driver.cpp in Sources */, 1A701B640F7C8FE400FEC4D1 /* SemaAccess.cpp in Sources */, 906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */, - DEDFF8880F848CF80035BD10 /* TemplateName.cpp in Sources */, DEF165710F8FB34D0098507F /* PCHWriter.cpp in Sources */, DEF165750F8FB3510098507F /* PCHReader.cpp in Sources */, DEF168400F9548DC0098507F /* FixItRewriter.cpp in Sources */, @@ -1969,11 +1975,8 @@ 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */, 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */, BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */, - 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */, - 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */, 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */, - 1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */, 90FD6D7B103C3D49005F5B73 /* Analyzer.cpp in Sources */, 90FD6D7C103C3D49005F5B73 /* ASTLocation.cpp in Sources */, 90FD6D7D103C3D49005F5B73 /* DeclReferenceMap.cpp in Sources */, @@ -1993,16 +1996,11 @@ 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */, 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */, 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */, - 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */, 1A6C01F7108128710072DEE4 /* CGRTTI.cpp in Sources */, - 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */, + 1A81AA19108144F40094E50B /* CGVTables.cpp in Sources */, 1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */, - 1ADD795410A90C6100741BBA /* TypePrinter.cpp in Sources */, - 1ADD795510A90C6100741BBA /* TypeLoc.cpp in Sources */, - 1ADD795610A90C6100741BBA /* TemplateBase.cpp in Sources */, 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */, E16B523510D30B2400430AC9 /* cc1_main.cpp in Sources */, - 1AA963C410D85A7300786C86 /* FullExpr.cpp in Sources */, 1ACB57E41105820D0047B991 /* CompilerInstance.cpp in Sources */, 1ACB57E51105820D0047B991 /* CompilerInvocation.cpp in Sources */, 1ACB57E61105820D0047B991 /* DeclXML.cpp in Sources */, @@ -2019,7 +2017,6 @@ 1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */, 1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */, 1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */, - 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */, BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */, BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */, BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */, @@ -2027,6 +2024,42 @@ BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */, 1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */, 1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */, + 1ABD23D61182449800A48E65 /* APValue.cpp in Sources */, + 1ABD23D71182449800A48E65 /* ASTConsumer.cpp in Sources */, + 1ABD23D81182449800A48E65 /* ASTContext.cpp in Sources */, + 1ABD23D91182449800A48E65 /* ASTDiagnostic.cpp in Sources */, + 1ABD23DA1182449800A48E65 /* ASTImporter.cpp in Sources */, + 1ABD23DB1182449800A48E65 /* AttrImpl.cpp in Sources */, + 1ABD23DC1182449800A48E65 /* CXXInheritance.cpp in Sources */, + 1ABD23DD1182449800A48E65 /* Decl.cpp in Sources */, + 1ABD23DE1182449800A48E65 /* DeclarationName.cpp in Sources */, + 1ABD23DF1182449800A48E65 /* DeclBase.cpp in Sources */, + 1ABD23E01182449800A48E65 /* DeclCXX.cpp in Sources */, + 1ABD23E11182449800A48E65 /* DeclFriend.cpp in Sources */, + 1ABD23E21182449800A48E65 /* DeclGroup.cpp in Sources */, + 1ABD23E31182449800A48E65 /* DeclObjC.cpp in Sources */, + 1ABD23E41182449800A48E65 /* DeclPrinter.cpp in Sources */, + 1ABD23E51182449800A48E65 /* DeclTemplate.cpp in Sources */, + 1ABD23E61182449800A48E65 /* Expr.cpp in Sources */, + 1ABD23E71182449800A48E65 /* ExprConstant.cpp in Sources */, + 1ABD23E81182449800A48E65 /* ExprCXX.cpp in Sources */, + 1ABD23E91182449800A48E65 /* FullExpr.cpp in Sources */, + 1ABD23EA1182449800A48E65 /* InheritViz.cpp in Sources */, + 1ABD23EB1182449800A48E65 /* NestedNameSpecifier.cpp in Sources */, + 1ABD23EC1182449800A48E65 /* ParentMap.cpp in Sources */, + 1ABD23ED1182449800A48E65 /* RecordLayout.cpp in Sources */, + 1ABD23EE1182449800A48E65 /* RecordLayoutBuilder.cpp in Sources */, + 1ABD23EF1182449800A48E65 /* Stmt.cpp in Sources */, + 1ABD23F01182449800A48E65 /* StmtDumper.cpp in Sources */, + 1ABD23F11182449800A48E65 /* StmtIterator.cpp in Sources */, + 1ABD23F21182449800A48E65 /* StmtPrinter.cpp in Sources */, + 1ABD23F31182449800A48E65 /* StmtProfile.cpp in Sources */, + 1ABD23F41182449800A48E65 /* StmtViz.cpp in Sources */, + 1ABD23F51182449800A48E65 /* TemplateBase.cpp in Sources */, + 1ABD23F61182449800A48E65 /* TemplateName.cpp in Sources */, + 1ABD23F71182449800A48E65 /* Type.cpp in Sources */, + 1ABD23F81182449800A48E65 /* TypeLoc.cpp in Sources */, + 1ABD23F91182449800A48E65 /* TypePrinter.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt index 6fb75da..dd12036 100644 --- a/docs/Block-ABI-Apple.txt +++ b/docs/Block-ABI-Apple.txt @@ -31,10 +31,11 @@ THE SOFTWARE. 2008/10/30 - add __weak support 2010/3/16 - rev for stret return, signature field +2010/4/6 - improved wording This document describes the Apple ABI implementation specification of Blocks. -The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. Proposals have been made to enhance the blocks compiler and runtime, and these changes would form a new ABI called post-10.6.ABI if these changes were ever shipped in a product, which is purely speculative. +The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. As of 2010/3/16, the following describes the ABI contract with the runtime and the compiler, and, as necessary, will be referred to as ABI.2010.3.16. Since the Apple ABI references symbols from other elements of the system, any attempt to use this ABI on systems prior to SnowLeopard is undefined. @@ -54,13 +55,13 @@ struct Block_literal_1 { // optional helper functions void (*copy_helper)(void *dst, void *src); // IFF (1<<25) void (*dispose_helper)(void *src); // IFF (1<<25) - // required post 10.6.ABI + // required ABI.2010.3.16 const char *signature; // IFF (1<<30) } *descriptor; // imported variables }; -The following flags bits are in use thusly for a possible post.10.6.ABI: +The following flags bits are in use thusly for a possible ABI.2010.3.16: enum { BLOCK_HAS_COPY_DISPOSE = (1 << 25), @@ -75,8 +76,8 @@ In 10.6.ABI the (1<<29) was unconditionally set and ignored by the runtime - it switch (flags & (3<<29)) { case (0<<29): , error case (1<<29): 10.6.ABI, no signature field available - case (2<<29): post-10.6.ABI, regular calling convention, presence of signature field - case (3<<29): post-10.6.ABI, stret calling convention, presence of signature field, + case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field + case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field, } The following discussions are presented as 10.6.ABI otherwise. diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html index 5d75eaa..daec6b0 100644 --- a/docs/InternalsManual.html +++ b/docs/InternalsManual.html @@ -145,13 +145,13 @@ diagnostic :).

pieces, this section describes them and talks about best practices when adding a new diagnostic.

- -

The DiagnosticKinds.def file

- + +

The Diagnostic*Kinds.def files

+ -

Diagnostics are created by adding an entry to the DiagnosticKinds.def file. This file encodes the unique ID of the +

Diagnostics are created by adding an entry to one of the +clang/Basic/Diagnostic*Kinds.def files, depending on what library will +be using it. This file encodes the unique ID of the diagnostic (as an enum, the first argument), the severity of the diagnostic (second argument) and the English translation + format string.

diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index fe364ef..838b65f 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -199,7 +199,44 @@ is used in the file argument.

Builtin Macros

-

__BASE_FILE__, __INCLUDE_LEVEL__, __TIMESTAMP__, __COUNTER__

+
+
__BASE_FILE__
+
Defined to a string that contains the name of the main input + file passed to Clang.
+ +
__COUNTER__
+
Defined to an integer value that starts at zero and is + incremented each time the __COUNTER__ macro is + expanded.
+ +
__INCLUDE_LEVEL__
+
Defined to an integral value that is the include depth of the + file currently being translated. For the main file, this value is + zero.
+ +
__TIMESTAMP__
+
Defined to the date and time of the last modification of the + current source file.
+ +
__clang__
+
Defined when compiling with Clang
+ +
__clang_major__
+
Defined to the major version number of Clang (e.g., the 2 in + 2.0.1).
+ +
__clang_minor__
+
Defined to the minor version number of Clang (e.g., the 0 in + 2.0.1).
+ +
__clang_patchlevel__
+
Defined to the patch level of Clang (e.g., the 1 in 2.0.1).
+ +
__clang_version__
+
Defined to a string that captures the Clang version, including + the Subversion tag or revision number, e.g., "1.5 (trunk + 102332)".
+

Vectors and Extended Vectors

@@ -271,9 +308,9 @@ attribute parsing with C++0x's square bracket notation is enabled.

Use __has_feature(cxx_deleted_functions) to determine if support for deleted function definitions (with = delete) is enabled. -

C++ TR concepts

+

C++ TR concepts

-

Use __has_feature(cxx_lambdas) to determine if support for +

Use __has_feature(cxx_concepts) to determine if support for concepts is enabled. clang does not currently implement this feature.

C++0x lambdas

diff --git a/docs/UsersManual.html b/docs/UsersManual.html index e7ea133..7d7f263 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -189,6 +189,12 @@ introduces the language selection and other high level options like -c, -g, etc.

-pedantic-errors: Error on language extensions.

-Wsystem-headers: Enable warnings from system headers.

+

-ferror-limit=123: Stop emitting diagnostics after 123 errors have + been produced. The default is 20, and the error limit can be disabled with + -ferror-limit=0.

+ +

-ftemplate-backtrace-limit=123: Only emit up to 123 template instantiation notes within the template instantiation backtrace for a single warning or error. The default is 10, and the limit can be disabled with -ftemplate-backtrace-limit=0.

+

Formatting of Diagnostics

diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp index 4eaa1dd..8623954 100644 --- a/examples/clang-interpreter/main.cpp +++ b/examples/clang-interpreter/main.cpp @@ -107,8 +107,10 @@ int main(int argc, const char **argv, char * const *envp) { // Initialize a compiler invocation object from the clang (-cc1) arguments. const driver::ArgStringList &CCArgs = Cmd->getArguments(); llvm::OwningPtr CI(new CompilerInvocation); - CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(), - (const char**) CCArgs.data()+CCArgs.size(), + CompilerInvocation::CreateFromArgs(*CI, + const_cast(CCArgs.data()), + const_cast(CCArgs.data()) + + CCArgs.size(), Diags); // Show the invocation, with -v. @@ -126,7 +128,7 @@ int main(int argc, const char **argv, char * const *envp) { Clang.setInvocation(CI.take()); // Create the compilers actual diagnostics engine. - Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data()); + Clang.createDiagnostics(int(CCArgs.size()),const_cast(CCArgs.data())); if (!Clang.hasDiagnostics()) return 1; diff --git a/include/Makefile b/include/Makefile index 47daabc..f686d6a 100644 --- a/include/Makefile +++ b/include/Makefile @@ -1,4 +1,4 @@ LEVEL = ../../.. -DIRS := clang +DIRS := clang clang-c include $(LEVEL)/Makefile.common diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 6120c48..1bf5a46 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -609,7 +609,9 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); * * \param unsaved_files the files that have not yet been saved to disk * but may be required for code completion, including the contents of - * those files. + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. * * \param diag_callback callback function that will receive any diagnostics * emitted while processing this source file. If NULL, diagnostics will be @@ -698,7 +700,11 @@ enum CXCursorKind { CXCursor_ObjCCategoryImplDecl = 19, /** \brief A typedef */ CXCursor_TypedefDecl = 20, - CXCursor_LastDecl = 20, + + /** \brief A C++ class method. */ + CXCursor_CXXMethod = 21, + + CXCursor_LastDecl = 21, /* References */ CXCursor_FirstRef = 40, /* Decl references */ @@ -763,7 +769,11 @@ enum CXCursorKind { /** \brief An expression that sends a message to an Objective-C object or class. */ CXCursor_ObjCMessageExpr = 104, - CXCursor_LastExpr = 104, + + /** \brief An expression that represents a block literal. */ + CXCursor_BlockExpr = 105, + + CXCursor_LastExpr = 105, /* Statements */ CXCursor_FirstStmt = 200, @@ -930,11 +940,26 @@ enum CXLinkageKind { }; /** - * \brief Determine the linkage of the entity referred to be a given cursor. + * \brief Determine the linkage of the entity referred to by a given cursor. */ CINDEX_LINKAGE enum CXLinkageKind clang_getCursorLinkage(CXCursor cursor); /** + * \brief Describe the "language" of the entity referred to by a cursor. + */ +CINDEX_LINKAGE enum CXLanguageKind { + CXLanguage_Invalid = 0, + CXLanguage_C, + CXLanguage_ObjC, + CXLanguage_CPlusPlus +}; + +/** + * \brief Determine the "language" of the entity referred to by a given cursor. + */ +CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor); + +/** * @} */ @@ -1697,7 +1722,9 @@ typedef struct { * * \param unsaved_files the files that have not yet been saved to disk * but may be required for code completion, including the contents of - * those files. + * those files. The contents and name of these files (as specified by + * CXUnsavedFile) are copied when necessary, so the client only needs to + * guarantee their validity until the call to this function returns. * * \param complete_filename the name of the source file where code completion * should be performed. In many cases, this name will be the same as the diff --git a/include/clang-c/Makefile b/include/clang-c/Makefile new file mode 100644 index 0000000..5e3522f --- /dev/null +++ b/include/clang-c/Makefile @@ -0,0 +1,31 @@ +LEVEL = ../../../.. +DIRS := + +include $(LEVEL)/Makefile.common + +install-local:: + $(Echo) Installing Clang C API include files + $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) + $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang-c" ; then \ + cd $(PROJ_SRC_ROOT)/tools/clang/include && \ + for hdr in `find clang-c -type f '!' '(' -name '*~' \ + -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ + -o -name 'Makefile' -o -name '*.td' ')' -print \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) + $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang-c" ; then \ + cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ + for hdr in `find clang-c -type f '!' '(' -name 'Makefile' ')' -print \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +endif diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index 9d4bff8..5effa90 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -122,13 +122,17 @@ public: return const_cast(this)->getFloat(); } - APValue &getVectorElt(unsigned i) const { + APValue &getVectorElt(unsigned i) { assert(isVector() && "Invalid accessor"); return ((Vec*)(char*)Data)->Elts[i]; } + const APValue &getVectorElt(unsigned i) const { + assert(isVector() && "Invalid accessor"); + return ((const Vec*)(const char*)Data)->Elts[i]; + } unsigned getVectorLength() const { assert(isVector() && "Invalid accessor"); - return ((Vec*)(void *)Data)->NumElts; + return ((const Vec*)(const void *)Data)->NumElts; } APSInt &getComplexIntReal() { diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c41857e..f8a8f17 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -25,6 +25,7 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/CanonicalType.h" +#include "clang/AST/UsuallyTinyPtrVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/OwningPtr.h" @@ -34,6 +35,7 @@ namespace llvm { struct fltSemantics; + class raw_ostream; } namespace clang { @@ -70,28 +72,6 @@ namespace clang { namespace Builtin { class Context; } -/// \brief A vector of C++ member functions that is optimized for -/// storing a single method. -class CXXMethodVector { - /// \brief Storage for the vector. - /// - /// When the low bit is zero, this is a const CXXMethodDecl *. When the - /// low bit is one, this is a std::vector *. - mutable uintptr_t Storage; - - typedef std::vector vector_type; - -public: - CXXMethodVector() : Storage(0) { } - - typedef const CXXMethodDecl **iterator; - iterator begin() const; - iterator end() const; - - void push_back(const CXXMethodDecl *Method); - void Destroy(); -}; - /// ASTContext - This class holds long-lived AST nodes (such as types and /// decls) that can be referred to throughout the semantic analysis of a file. class ASTContext { @@ -164,6 +144,8 @@ class ASTContext { QualType ObjCConstantStringType; RecordDecl *CFConstantStringTypeDecl; + RecordDecl *NSConstantStringTypeDecl; + RecordDecl *ObjCFastEnumerationStateTypeDecl; /// \brief The type for the C FILE type. @@ -250,6 +232,7 @@ class ASTContext { /// Since most C++ member functions aren't virtual and therefore /// don't override anything, we store the overridden functions in /// this map on the side rather than within the CXXMethodDecl structure. + typedef UsuallyTinyPtrVector CXXMethodVector; llvm::DenseMap OverriddenMethods; TranslationUnitDecl *TUDecl; @@ -617,11 +600,13 @@ public: QualType getTemplateSpecializationType(TemplateName T, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon = QualType()); + QualType Canon = QualType(), + bool IsCurrentInstantiation = false); QualType getTemplateSpecializationType(TemplateName T, const TemplateArgumentListInfo &Args, - QualType Canon = QualType()); + QualType Canon = QualType(), + bool IsCurrentInstantiation = false); TypeSourceInfo * getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, @@ -688,6 +673,19 @@ public: // constant CFStrings. QualType getCFConstantStringType(); + // getNSConstantStringType - Return the C structure type used to represent + // constant NSStrings. + QualType getNSConstantStringType(); + /// Get the structure type used to representation NSStrings, or NULL + /// if it hasn't yet been built. + QualType getRawNSConstantStringType() { + if (NSConstantStringTypeDecl) + return getTagDeclType(NSConstantStringTypeDecl); + return QualType(); + } + void setNSConstantStringType(QualType T); + + /// Get the structure type used to representation CFStrings, or NULL /// if it hasn't yet been built. QualType getRawCFConstantStringType() { @@ -937,6 +935,8 @@ public: /// layout of the specified Objective-C interface. const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D); + void DumpRecordLayout(const RecordDecl *RD, llvm::raw_ostream &OS); + /// getASTObjCImplementationLayout - Get or compute information about /// the layout of the specified Objective-C implementation. This may /// differ from the interface if synthesized ivars are present. diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h new file mode 100644 index 0000000..217dfad --- /dev/null +++ b/include/clang/AST/ASTVector.h @@ -0,0 +1,397 @@ +//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides ASTVector, a vector ADT whose contents are +// allocated using the allocator associated with an ASTContext.. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h. +// We can refactor this core logic into something common. + +#ifndef LLVM_CLANG_AST_VECTOR +#define LLVM_CLANG_AST_VECTOR + +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/PointerIntPair.h" +#include +#include +#include + +#ifdef _MSC_VER +namespace std { +#if _MSC_VER <= 1310 + // Work around flawed VC++ implementation of std::uninitialized_copy. Define + // additional overloads so that elements with pointer types are recognized as + // scalars and not objects, causing bizarre type conversion errors. + template + inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) { + _Scalar_ptr_iterator_tag _Cat; + return _Cat; + } + + template + inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) { + _Scalar_ptr_iterator_tag _Cat; + return _Cat; + } +#else + // FIXME: It is not clear if the problem is fixed in VS 2005. What is clear + // is that the above hack won't work if it wasn't fixed. +#endif +} +#endif + +namespace clang { + +template +class ASTVector { + T *Begin, *End, *Capacity; + + void setEnd(T *P) { this->End = P; } + +public: + // Default ctor - Initialize to empty. + explicit ASTVector(ASTContext &C, unsigned N = 0) + : Begin(NULL), End(NULL), Capacity(NULL) { + reserve(C, N); + } + + ~ASTVector() { + if (llvm::is_class::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (llvm::is_class::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, ASTContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + void reserve(ASTContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + + /// append - Add the specified range to the end of the SmallVector. + /// + template + void append(ASTContext &C, in_iter in_start, in_iter in_end) { + size_type NumInputs = std::distance(in_start, in_end); + + if (NumInputs == 0) + return; + + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + // TODO: NEED To compile time dispatch on whether in_iter is a random access + // iterator to use the fast uninitialized_copy. + std::uninitialized_copy(in_start, in_end, this->end()); + this->setEnd(this->end() + NumInputs); + } + + /// append - Add the specified range to the end of the SmallVector. + /// + void append(ASTContext &C, size_type NumInputs, const T &Elt) { + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + std::uninitialized_fill_n(this->end(), NumInputs, Elt); + this->setEnd(this->end() + NumInputs); + } + + /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(I, E, Dest); + } + + iterator insert(ASTContext &C, iterator I, const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + push_back(Elt); + return this->end()-1; + } + + if (this->EndX < this->CapacityX) { + Retry: + new (this->end()) T(this->back()); + this->setEnd(this->end()+1); + // Push everything else over. + std::copy_backward(I, this->end()-1, this->end()); + *I = Elt; + return I; + } + size_t EltNo = I-this->begin(); + this->grow(C); + I = this->begin()+EltNo; + goto Retry; + } + + iterator insert(ASTContext &C, iterator I, size_type NumToInsert, + const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + append(C, NumToInsert, Elt); + return this->end()-1; + } + + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + // Ensure there is enough space. + reserve(C, static_cast(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::fill_n(I, NumToInsert, Elt); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + std::fill_n(I, NumOverwritten, Elt); + + // Insert the non-overwritten middle part. + std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt); + return I; + } + + template + iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) { + if (I == this->end()) { // Important special case for empty vector. + append(C, From, To); + return this->end()-1; + } + + size_t NumToInsert = std::distance(From, To); + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + // Ensure there is enough space. + reserve(C, static_cast(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::copy(From, To, I); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + for (; NumOverwritten > 0; --NumOverwritten) { + *I = *From; + ++I; ++From; + } + + // Insert the non-overwritten middle part. + this->uninitialized_copy(From, To, OldEnd); + return I; + } + + void resize(ASTContext &C, unsigned N, const T &NV) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->setEnd(this->begin()+N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(C, N); + construct_range(this->end(), this->begin()+N, NV); + this->setEnd(this->begin()+N); + } + } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(ASTContext &C, size_type MinSize = 1); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + +protected: + iterator capacity_ptr() { return (iterator)this->Capacity; } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template +void ASTVector::grow(ASTContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the ASTContext. + T *NewElts = new (C) T[NewCapacity]; + + // Copy the elements over. + if (llvm::is_class::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } + else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + + C.Deallocate(Begin); + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index b2a87f6..93dcad7 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -263,6 +263,7 @@ public: LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 2cdb983..834c9a0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -31,7 +31,9 @@ class StringLiteral; class TemplateArgumentList; class MemberSpecializationInfo; class FunctionTemplateSpecializationInfo; +class DependentFunctionTemplateSpecializationInfo; class TypeLoc; +class UnresolvedSetImpl; /// \brief A container of type source information. /// @@ -196,6 +198,10 @@ public: return DC->isRecord(); } + /// \brief Given that this declaration is a C++ class member, + /// determine whether it's an instance member of its class. + bool isCXXInstanceMember() const; + /// \brief Determine what kind of linkage this entity has. Linkage getLinkage() const; @@ -211,6 +217,12 @@ public: static bool classofKind(Kind K) { return K >= NamedFirst && K <= NamedLast; } }; +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const NamedDecl *ND) { + ND->getDeclName().printName(OS); + return OS; +} + /// NamespaceDecl - Represent a C++ namespace. class NamespaceDecl : public NamedDecl, public DeclContext { SourceLocation LBracLoc, RBracLoc; @@ -478,6 +490,7 @@ protected: private: // FIXME: This can be packed into the bitfields in Decl. unsigned SClass : 3; + unsigned SClassAsWritten : 3; bool ThreadSpecified : 1; bool HasCXXDirectInit : 1; @@ -485,14 +498,20 @@ private: /// condition, e.g., if (int x = foo()) { ... }. bool DeclaredInCondition : 1; + /// \brief Whether this variable is the exception variable in a C++ catch + /// or an Objective-C @catch statement. + bool ExceptionVar : 1; + friend class StmtIteratorBase; protected: VarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, StorageClass SC) + QualType T, TypeSourceInfo *TInfo, StorageClass SC, + StorageClass SCAsWritten) : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Init(), ThreadSpecified(false), HasCXXDirectInit(false), - DeclaredInCondition(false) { + DeclaredInCondition(false), ExceptionVar(false) { SClass = SC; + SClassAsWritten = SCAsWritten; } typedef Redeclarable redeclarable_base; @@ -509,7 +528,8 @@ public: static VarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, StorageClass S); + QualType T, TypeSourceInfo *TInfo, StorageClass S, + StorageClass SCAsWritten); virtual void Destroy(ASTContext& C); virtual ~VarDecl(); @@ -517,7 +537,11 @@ public: virtual SourceRange getSourceRange() const; StorageClass getStorageClass() const { return (StorageClass)SClass; } + StorageClass getStorageClassAsWritten() const { + return (StorageClass) SClassAsWritten; + } void setStorageClass(StorageClass SC) { SClass = SC; } + void setStorageClassAsWritten(StorageClass SC) { SClassAsWritten = SC; } void setThreadSpecified(bool T) { ThreadSpecified = T; } bool isThreadSpecified() const { @@ -536,6 +560,12 @@ public: return getStorageClass() <= Register; } + /// isStaticLocal - Returns true if a variable with function scope is a + /// static local variable. + bool isStaticLocal() const { + return getStorageClass() == Static && !isFileVarDecl(); + } + /// hasExternStorage - Returns true if a variable has extern or /// __private_extern__ storage. bool hasExternalStorage() const { @@ -815,6 +845,13 @@ public: DeclaredInCondition = InCondition; } + /// \brief Determine whether this variable is the exception variable in a + /// C++ catch statememt or an Objective-C @catch statement. + bool isExceptionVariable() const { + return ExceptionVar; + } + void setExceptionVariable(bool EV) { ExceptionVar = EV; } + /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member /// from which it was instantiated. @@ -844,7 +881,7 @@ class ImplicitParamDecl : public VarDecl { protected: ImplicitParamDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType Tw) - : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, VarDecl::None) {} + : VarDecl(DK, DC, L, Id, Tw, /*TInfo=*/0, VarDecl::None, VarDecl::None) {} public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -866,9 +903,9 @@ class ParmVarDecl : public VarDecl { protected: ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) - : VarDecl(DK, DC, L, Id, T, TInfo, S), - objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) { + StorageClass S, StorageClass SCAsWritten, Expr *DefArg) + : VarDecl(DK, DC, L, Id, T, TInfo, S, SCAsWritten), + objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) { setDefaultArg(DefArg); } @@ -876,7 +913,8 @@ public: static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg); + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg); ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(objcDeclQualifier); @@ -1002,6 +1040,7 @@ private: // FIXME: This can be packed into the bitfields in Decl. // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum unsigned SClass : 2; + unsigned SClassAsWritten : 2; bool IsInline : 1; bool IsVirtualAsWritten : 1; bool IsPure : 1; @@ -1033,19 +1072,20 @@ private: /// FunctionTemplateSpecializationInfo, which contains information about /// the template being specialized and the template arguments involved in /// that specialization. - llvm::PointerUnion3 + FunctionTemplateSpecializationInfo *, + DependentFunctionTemplateSpecializationInfo *> TemplateOrSpecialization; protected: FunctionDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass S, bool isInline) + StorageClass S, StorageClass SCAsWritten, bool isInline) : DeclaratorDecl(DK, DC, L, N, T, TInfo), DeclContext(DK), ParamInfo(0), Body(), - SClass(S), IsInline(isInline), + SClass(S), SClassAsWritten(SCAsWritten), IsInline(isInline), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsCopyAssignment(false), @@ -1070,7 +1110,9 @@ public: static FunctionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass S = None, bool isInline = false, + StorageClass S = None, + StorageClass SCAsWritten = None, + bool isInline = false, bool hasWrittenPrototype = true); virtual void getNameForDiagnostic(std::string &S, @@ -1107,6 +1149,9 @@ public: void setBody(Stmt *B); void setLazyBody(uint64_t Offset) { Body = Offset; } + /// Whether this function is variadic. + bool isVariadic() const; + /// Whether this function is marked as virtual explicitly. bool isVirtualAsWritten() const { return IsVirtualAsWritten; } void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } @@ -1225,6 +1270,11 @@ public: StorageClass getStorageClass() const { return StorageClass(SClass); } void setStorageClass(StorageClass SC) { SClass = SC; } + StorageClass getStorageClassAsWritten() const { + return StorageClass(SClassAsWritten); + } + void setStorageClassAsWritten(StorageClass SC) { SClassAsWritten = SC; } + /// \brief Determine whether the "inline" keyword was specified for this /// function. bool isInlineSpecified() const { return IsInline; } @@ -1361,6 +1411,18 @@ public: void *InsertPos, TemplateSpecializationKind TSK = TSK_ImplicitInstantiation); + /// \brief Specifies that this function declaration is actually a + /// dependent function template specialization. + void setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + DependentFunctionTemplateSpecializationInfo * + getDependentSpecializationInfo() const { + return TemplateOrSpecialization. + dyn_cast(); + } + /// \brief Determine what kind of template instantiation this function /// represents. TemplateSpecializationKind getTemplateSpecializationKind() const; @@ -1961,7 +2023,7 @@ public: /// class BlockDecl : public Decl, public DeclContext { // FIXME: This can be packed into the bitfields in Decl. - bool isVariadic : 1; + bool IsVariadic : 1; /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. @@ -1973,7 +2035,7 @@ class BlockDecl : public Decl, public DeclContext { protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), - isVariadic(false), ParamInfo(0), NumParams(0), Body(0) {} + IsVariadic(false), ParamInfo(0), NumParams(0), Body(0) {} virtual ~BlockDecl(); virtual void Destroy(ASTContext& C); @@ -1983,8 +2045,8 @@ public: SourceLocation getCaretLocation() const { return getLocation(); } - bool IsVariadic() const { return isVariadic; } - void setIsVariadic(bool value) { isVariadic = value; } + bool isVariadic() const { return IsVariadic; } + void setIsVariadic(bool value) { IsVariadic = value; } CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } Stmt *getBody() const { return (Stmt*) Body; } diff --git a/include/clang/AST/DeclAccessPair.h b/include/clang/AST/DeclAccessPair.h new file mode 100644 index 0000000..7ecd8f8 --- /dev/null +++ b/include/clang/AST/DeclAccessPair.h @@ -0,0 +1,72 @@ +//===--- DeclAccessPair.h - A decl bundled with its path access -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclAccessPair class, which provides an +// efficient representation of a pair of a NamedDecl* and an +// AccessSpecifier. Generally the access specifier gives the +// natural access of a declaration when named in a class, as +// defined in C++ [class.access.base]p1. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H +#define LLVM_CLANG_AST_DECLACCESSPAIR_H + +#include "clang/Basic/Specifiers.h" + +namespace clang { + +class NamedDecl; + +/// A POD class for pairing a NamedDecl* with an access specifier. +/// Can be put into unions. +class DeclAccessPair { + NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial + + enum { Mask = 0x3 }; + +public: + static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { + DeclAccessPair p; + p.set(D, AS); + return p; + } + + NamedDecl *getDecl() const { + return (NamedDecl*) (~Mask & (uintptr_t) Ptr); + } + AccessSpecifier getAccess() const { + return AccessSpecifier(Mask & (uintptr_t) Ptr); + } + + void setDecl(NamedDecl *D) { + set(D, getAccess()); + } + void setAccess(AccessSpecifier AS) { + set(getDecl(), AS); + } + void set(NamedDecl *D, AccessSpecifier AS) { + Ptr = reinterpret_cast(uintptr_t(AS) | + reinterpret_cast(D)); + } + + operator NamedDecl*() const { return getDecl(); } + NamedDecl *operator->() const { return getDecl(); } +}; +} + +// Take a moment to tell SmallVector that DeclAccessPair is POD. +namespace llvm { +template struct isPodLike; +template<> struct isPodLike { + static const bool value = true; +}; +} + +#endif diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index d5913e2..a9b948e 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -76,26 +76,68 @@ public: #include "clang/AST/DeclNodes.def" }; - /// IdentifierNamespace - According to C99 6.2.3, there are four - /// namespaces, labels, tags, members and ordinary - /// identifiers. These are meant as bitmasks, so that searches in - /// C++ can look into the "tag" namespace during ordinary lookup. We - /// use additional namespaces for Objective-C entities. We also put - /// C++ friend declarations (of previously-undeclared entities) in - /// shadow namespaces, and 'using' declarations (as opposed to their - /// implicit shadow declarations) can be found in their own - /// namespace. + /// IdentifierNamespace - The different namespaces in which + /// declarations may appear. According to C99 6.2.3, there are + /// four namespaces, labels, tags, members and ordinary + /// identifiers. C++ describes lookup completely differently: + /// certain lookups merely "ignore" certain kinds of declarations, + /// usually based on whether the declaration is of a type, etc. + /// + /// These are meant as bitmasks, so that searches in + /// C++ can look into the "tag" namespace during ordinary lookup. + /// + /// Decl currently provides 16 bits of IDNS bits. enum IdentifierNamespace { - IDNS_Label = 0x1, - IDNS_Tag = 0x2, - IDNS_Member = 0x4, - IDNS_Ordinary = 0x8, - IDNS_ObjCProtocol = 0x10, - IDNS_ObjCImplementation = 0x20, - IDNS_ObjCCategoryName = 0x40, - IDNS_OrdinaryFriend = 0x80, - IDNS_TagFriend = 0x100, - IDNS_Using = 0x200 + /// Labels, declared with 'x:' and referenced with 'goto x'. + IDNS_Label = 0x0001, + + /// Tags, declared with 'struct foo;' and referenced with + /// 'struct foo'. All tags are also types. This is what + /// elaborated-type-specifiers look for in C. + IDNS_Tag = 0x0002, + + /// Types, declared with 'struct foo', typedefs, etc. + /// This is what elaborated-type-specifiers look for in C++, + /// but note that it's ill-formed to find a non-tag. + IDNS_Type = 0x0004, + + /// Members, declared with object declarations within tag + /// definitions. In C, these can only be found by "qualified" + /// lookup in member expressions. In C++, they're found by + /// normal lookup. + IDNS_Member = 0x0008, + + /// Namespaces, declared with 'namespace foo {}'. + /// Lookup for nested-name-specifiers find these. + IDNS_Namespace = 0x0010, + + /// Ordinary names. In C, everything that's not a label, tag, + /// or member ends up here. + IDNS_Ordinary = 0x0020, + + /// Objective C @protocol. + IDNS_ObjCProtocol = 0x0040, + + /// This declaration is a friend function. A friend function + /// declaration is always in this namespace but may also be in + /// IDNS_Ordinary if it was previously declared. + IDNS_OrdinaryFriend = 0x0080, + + /// This declaration is a friend class. A friend class + /// declaration is always in this namespace but may also be in + /// IDNS_Tag|IDNS_Type if it was previously declared. + IDNS_TagFriend = 0x0100, + + /// This declaration is a using declaration. A using declaration + /// *introduces* a number of other declarations into the current + /// scope, and those declarations use the IDNS of their targets, + /// but the actual using declarations go in this namespace. + IDNS_Using = 0x0200, + + /// This declaration is a C++ operator declared in a non-class + /// context. All such operators are also in IDNS_Ordinary. + /// C++ lexical operator lookup looks for these. + IDNS_NonMemberOperator = 0x0400 }; /// ObjCDeclQualifier - Qualifier used on types in method declarations @@ -313,6 +355,13 @@ public: } static unsigned getIdentifierNamespaceForKind(Kind DK); + bool hasTagIdentifierNamespace() const { + return isTagIdentifierNamespace(getIdentifierNamespace()); + } + static bool isTagIdentifierNamespace(unsigned NS) { + // TagDecls have Tag and Type set and may also have TagFriend. + return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); + } /// getLexicalDeclContext - The declaration context where this Decl was /// lexically declared (LexicalDC). May be different from @@ -455,14 +504,14 @@ public: assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend)) && "namespace includes neither ordinary nor tag"); - assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | + assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | IDNS_TagFriend | IDNS_OrdinaryFriend)) && "namespace includes other than ordinary or tag"); IdentifierNamespace = 0; if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; - if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag; + if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type; } if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) { @@ -489,6 +538,14 @@ public: FOK_Declared : FOK_Undeclared); } + /// Specifies that this declaration is a C++ overloaded non-member. + void setNonMemberOperator() { + assert(getKind() == Function || getKind() == FunctionTemplate); + assert((IdentifierNamespace & IDNS_Ordinary) && + "visible non-member operators should be in ordinary namespace"); + IdentifierNamespace |= IDNS_NonMemberOperator; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *) { return true; } static bool classofKind(Kind K) { return true; } diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 23769af..aa649c8 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -471,6 +471,11 @@ public: friend_iterator friend_end() const; void pushFriendDecl(FriendDecl *FD); + /// Determines whether this record has any friends. + bool hasFriends() const { + return data().FirstFriend != 0; + } + /// hasConstCopyConstructor - Determines whether this class has a /// copy constructor that accepts a const-qualified argument. bool hasConstCopyConstructor(ASTContext &Context) const; @@ -931,15 +936,16 @@ class CXXMethodDecl : public FunctionDecl { protected: CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isStatic, bool isInline) + bool isStatic, StorageClass SCAsWritten, bool isInline) : FunctionDecl(DK, RD, L, N, T, TInfo, (isStatic ? Static : None), - isInline) {} + SCAsWritten, isInline) {} public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isStatic = false, + StorageClass SCAsWritten = FunctionDecl::None, bool isInline = false); bool isStatic() const { return getStorageClass() == Static; } @@ -960,6 +966,10 @@ public: /// delete or delete[] operator with a particular signature. bool isUsualDeallocationFunction() const; + /// \brief Determine whether this is a copy-assignment operator, regardless + /// of whether it was declared implicitly or explicitly. + bool isCopyAssignmentOperator() const; + const CXXMethodDecl *getCanonicalDecl() const { return cast(FunctionDecl::getCanonicalDecl()); } @@ -1052,6 +1062,10 @@ class CXXBaseOrMemberInitializer { /// and AnonUnionMember holds field decl for au_i1. FieldDecl *AnonUnionMember; + /// IsVirtual - If the initializer is a base initializer, this keeps track + /// of whether the base is virtual or not. + bool IsVirtual; + /// LParenLoc - Location of the left paren of the ctor-initializer. SourceLocation LParenLoc; @@ -1062,7 +1076,7 @@ public: /// CXXBaseOrMemberInitializer - Creates a new base-class initializer. explicit CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, + TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R); @@ -1095,7 +1109,14 @@ public: /// Otherwise, returns NULL. const Type *getBaseClass() const; Type *getBaseClass(); - + + /// Returns whether the base is virtual or not. + bool isBaseVirtual() const { + assert(isBaseInitializer() && "Must call this on base initializer!"); + + return IsVirtual; + } + /// \brief Returns the declarator information for a base class initializer. TypeSourceInfo *getBaseClassInfo() const { return BaseOrMember.dyn_cast(); @@ -1171,7 +1192,8 @@ class CXXConstructorDecl : public CXXMethodDecl { DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, isInline), + : CXXMethodDecl(CXXConstructor, RD, L, N, T, TInfo, false, + FunctionDecl::None, isInline), IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), BaseOrMemberInitializers(0), NumBaseOrMemberInitializers(0) { setImplicit(isImplicitlyDeclared); @@ -1199,7 +1221,7 @@ public: /// defined. If false, then this constructor was defined by the /// user. This operation can only be invoked if the constructor has /// already been defined. - bool isImplicitlyDefined(ASTContext &C) const { + bool isImplicitlyDefined() const { assert(isThisDeclarationADefinition() && "Can only get the implicit-definition flag once the " "constructor has been defined"); @@ -1314,7 +1336,8 @@ class CXXDestructorDecl : public CXXMethodDecl { CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*TInfo=*/0, false, isInline), + : CXXMethodDecl(CXXDestructor, RD, L, N, T, /*TInfo=*/0, false, + FunctionDecl::None, isInline), ImplicitlyDefined(false), OperatorDelete(0) { setImplicit(isImplicitlyDeclared); } @@ -1370,7 +1393,8 @@ class CXXConversionDecl : public CXXMethodDecl { CXXConversionDecl(CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicitSpecified) - : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, isInline), + : CXXMethodDecl(CXXConversion, RD, L, N, T, TInfo, false, + FunctionDecl::None, isInline), IsExplicitSpecified(isExplicitSpecified) { } public: diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h index 16cb491..2a4b12a 100644 --- a/include/clang/AST/DeclContextInternals.h +++ b/include/clang/AST/DeclContextInternals.h @@ -230,7 +230,7 @@ public: // Tag declarations always go at the end of the list so that an // iterator which points at the first tag will start a span of // decls that only contains tags. - if (D->getIdentifierNamespace() == Decl::IDNS_Tag) + if (D->hasTagIdentifierNamespace()) Vec.push_back(reinterpret_cast(D)); // Resolved using declarations go at the front of the list so that @@ -251,7 +251,7 @@ public: // tag declarations. But we can be clever about tag declarations // because there can only ever be one in a scope. } else if (reinterpret_cast(Vec.back()) - ->getIdentifierNamespace() == Decl::IDNS_Tag) { + ->hasTagIdentifierNamespace()) { uintptr_t TagD = Vec.back(); Vec.back() = reinterpret_cast(D); Vec.push_back(TagD); diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h index 99ef738..a20625d 100644 --- a/include/clang/AST/DeclFriend.h +++ b/include/clang/AST/DeclFriend.h @@ -48,10 +48,6 @@ private: // Location of the 'friend' specifier. SourceLocation FriendLoc; - // FIXME: Hack to keep track of whether this was a friend function - // template specialization. - bool WasSpecialization; - friend class CXXRecordDecl::friend_iterator; friend class CXXRecordDecl; @@ -60,8 +56,7 @@ private: : Decl(Decl::Friend, DC, L), Friend(Friend), NextFriend(0), - FriendLoc(FriendL), - WasSpecialization(false) { + FriendLoc(FriendL) { } public: @@ -88,9 +83,6 @@ public: return FriendLoc; } - bool wasSpecialization() const { return WasSpecialization; } - void setSpecialization(bool WS) { WasSpecialization = WS; } - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FriendDecl *D) { return true; } diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index 082299c..5b03ff8 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -105,14 +105,14 @@ ABSTRACT_DECL(Named, Decl) DECL(ImplicitParam, VarDecl) DECL(ParmVar, VarDecl) DECL(NonTypeTemplateParm, VarDecl) - DECL(Template, NamedDecl) + ABSTRACT_DECL(Template, NamedDecl) DECL(FunctionTemplate, TemplateDecl) DECL(ClassTemplate, TemplateDecl) DECL(TemplateTemplateParm, TemplateDecl) DECL(Using, NamedDecl) DECL(UsingShadow, NamedDecl) DECL(ObjCMethod, NamedDecl) - DECL(ObjCContainer, NamedDecl) + ABSTRACT_DECL(ObjCContainer, NamedDecl) DECL(ObjCCategory, ObjCContainerDecl) DECL(ObjCProtocol, ObjCContainerDecl) DECL(ObjCInterface, ObjCContainerDecl) @@ -143,7 +143,7 @@ LAST_DECL_CONTEXT(Block) // Declaration ranges DECL_RANGE(Named, Namespace, ObjCCompatibleAlias) -DECL_RANGE(ObjCContainer, ObjCContainer, ObjCImplementation) +DECL_RANGE(ObjCContainer, ObjCCategory, ObjCImplementation) DECL_RANGE(Field, Field, ObjCAtDefsField) DECL_RANGE(Type, Typedef, TemplateTypeParm) DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization) @@ -151,7 +151,7 @@ DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization) DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm) DECL_RANGE(Declarator, Function, NonTypeTemplateParm) DECL_RANGE(Function, Function, CXXConversion) -DECL_RANGE(Template, Template, TemplateTemplateParm) +DECL_RANGE(Template, FunctionTemplate, TemplateTemplateParm) DECL_RANGE(ObjCImpl, ObjCCategoryImpl, ObjCImplementation) LAST_DECL_RANGE(Var, Var, NonTypeTemplateParm) diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 9b2b609..e34ec9f 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -29,6 +29,7 @@ class ObjCProtocolDecl; class ObjCCategoryDecl; class ObjCPropertyDecl; class ObjCPropertyImplDecl; +class CXXBaseOrMemberInitializer; class ObjCListBase { void operator=(const ObjCListBase &); // DO NOT IMPLEMENT @@ -136,6 +137,9 @@ private: /// in, inout, etc. unsigned objcDeclQualifier : 6; + // Number of args separated by ':' in a method declaration. + unsigned NumSelectorArgs; + // Result type of this method. QualType MethodDeclType; @@ -167,13 +171,15 @@ private: bool isInstance = true, bool isVariadic = false, bool isSynthesized = false, - ImplementationControl impControl = None) + ImplementationControl impControl = None, + unsigned numSelectorArgs = 0) : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), DeclContext(ObjCMethod), IsInstance(isInstance), IsVariadic(isVariadic), IsSynthesized(isSynthesized), DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None), - MethodDeclType(T), ResultTInfo(ResultTInfo), + NumSelectorArgs(numSelectorArgs), MethodDeclType(T), + ResultTInfo(ResultTInfo), EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {} virtual ~ObjCMethodDecl() {} @@ -197,7 +203,8 @@ public: bool isInstance = true, bool isVariadic = false, bool isSynthesized = false, - ImplementationControl impControl = None); + ImplementationControl impControl = None, + unsigned numSelectorArgs = 0); virtual ObjCMethodDecl *getCanonicalDecl(); const ObjCMethodDecl *getCanonicalDecl() const { @@ -209,6 +216,11 @@ public: } void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } + unsigned getNumSelectorArgs() const { return NumSelectorArgs; } + void setNumSelectorArgs(unsigned numSelectorArgs) { + NumSelectorArgs = numSelectorArgs; + } + // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } SourceLocation getLocEnd() const { return EndLoc; } @@ -235,9 +247,16 @@ public: typedef ObjCList::iterator param_iterator; param_iterator param_begin() const { return ParamInfo.begin(); } param_iterator param_end() const { return ParamInfo.end(); } + // This method returns and of the parameters which are part of the selector + // name mangling requirements. + param_iterator sel_param_end() const { + return ParamInfo.begin() + NumSelectorArgs; + } - void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num) { + void setMethodParams(ASTContext &C, ParmVarDecl *const *List, unsigned Num, + unsigned numSelectorArgs) { ParamInfo.set(List, Num, C); + NumSelectorArgs = numSelectorArgs; } // Iterator access to parameter types. @@ -1114,6 +1133,9 @@ public: static bool classofKind(Kind K) { return K == ObjCCategoryImpl;} }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const ObjCCategoryImplDecl *CID); + /// ObjCImplementationDecl - Represents a class definition - this is where /// method definitions are specified. For example: /// @@ -1131,18 +1153,54 @@ public: class ObjCImplementationDecl : public ObjCImplDecl { /// Implementation Class's super class. ObjCInterfaceDecl *SuperClass; - + /// Support for ivar initialization. + /// IvarInitializers - The arguments used to initialize the ivars + CXXBaseOrMemberInitializer **IvarInitializers; + unsigned NumIvarInitializers; + ObjCImplementationDecl(DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl) : ObjCImplDecl(ObjCImplementation, DC, L, classInterface), - SuperClass(superDecl){} + SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0) {} public: static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *superDecl); - + + /// init_iterator - Iterates through the ivar initializer list. + typedef CXXBaseOrMemberInitializer **init_iterator; + + /// init_const_iterator - Iterates through the ivar initializer list. + typedef CXXBaseOrMemberInitializer * const * init_const_iterator; + + /// init_begin() - Retrieve an iterator to the first initializer. + init_iterator init_begin() { return IvarInitializers; } + /// begin() - Retrieve an iterator to the first initializer. + init_const_iterator init_begin() const { return IvarInitializers; } + + /// init_end() - Retrieve an iterator past the last initializer. + init_iterator init_end() { + return IvarInitializers + NumIvarInitializers; + } + /// end() - Retrieve an iterator past the last initializer. + init_const_iterator init_end() const { + return IvarInitializers + NumIvarInitializers; + } + /// getNumArgs - Number of ivars which must be initialized. + unsigned getNumIvarInitializers() const { + return NumIvarInitializers; + } + + void setNumIvarInitializers(unsigned numNumIvarInitializers) { + NumIvarInitializers = numNumIvarInitializers; + } + + void setIvarInitializers(ASTContext &C, + CXXBaseOrMemberInitializer ** initializers, + unsigned numInitializers); + /// getIdentifier - Get the identifier that names the class /// interface associated with this implementation. IdentifierInfo *getIdentifier() const { @@ -1199,6 +1257,9 @@ public: static bool classofKind(Kind K) { return K == ObjCImplementation; } }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const ObjCImplementationDecl *ID); + /// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is /// declared as @compatibility_alias alias class. class ObjCCompatibleAliasDecl : public NamedDecl { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 8d1a4ca..1ec38ba 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -376,6 +376,81 @@ public: PointOfInstantiation = POI; } }; + +/// \brief Provides information about a dependent function-template +/// specialization declaration. Since explicit function template +/// specialization and instantiation declarations can only appear in +/// namespace scope, and you can only specialize a member of a +/// fully-specialized class, the only way to get one of these is in +/// a friend declaration like the following: +/// +/// template void foo(T); +/// template class A { +/// friend void foo<>(T); +/// }; +class DependentFunctionTemplateSpecializationInfo { + union { + // Force sizeof to be a multiple of sizeof(void*) so that the + // trailing data is aligned. + void *Aligner; + + struct { + /// The number of potential template candidates. + unsigned NumTemplates; + + /// The number of template arguments. + unsigned NumArgs; + } d; + }; + + /// The locations of the left and right angle brackets. + SourceRange AngleLocs; + + FunctionTemplateDecl * const *getTemplates() const { + return reinterpret_cast(this+1); + } + + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast( + &getTemplates()[getNumTemplates()]); + } + +public: + DependentFunctionTemplateSpecializationInfo( + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + /// \brief Returns the number of function templates that this might + /// be a specialization of. + unsigned getNumTemplates() const { + return d.NumTemplates; + } + + /// \brief Returns the i'th template candidate. + FunctionTemplateDecl *getTemplate(unsigned I) const { + assert(I < getNumTemplates() && "template index out of range"); + return getTemplates()[I]; + } + + /// \brief Returns the number of explicit template arguments that were given. + unsigned getNumTemplateArgs() const { + return d.NumArgs; + } + + /// \brief Returns the nth template argument. + const TemplateArgumentLoc &getTemplateArg(unsigned I) const { + assert(I < getNumTemplateArgs() && "template arg index out of range"); + return getTemplateArgs()[I]; + } + + SourceLocation getLAngleLoc() const { + return AngleLocs.getBegin(); + } + + SourceLocation getRAngleLoc() const { + return AngleLocs.getEnd(); + } +}; /// Declaration of a template function. class FunctionTemplateDecl : public TemplateDecl { @@ -652,7 +727,8 @@ class NonTypeTemplateParmDecl NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, VarDecl::None), + : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, VarDecl::None, + VarDecl::None), TemplateParmPosition(D, P), DefaultArgument(0) { } @@ -935,6 +1011,11 @@ class ClassTemplatePartialSpecializationDecl TemplateArgumentLoc *ArgsAsWritten; unsigned NumArgsAsWritten; + /// \brief Sequence number indicating when this class template partial + /// specialization was added to the set of partial specializations for + /// its owning class template. + unsigned SequenceNumber; + /// \brief The class template partial specialization from which this /// class template partial specialization was instantiated. /// @@ -950,13 +1031,15 @@ class ClassTemplatePartialSpecializationDecl TemplateArgumentListBuilder &Builder, TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos, - ClassTemplatePartialSpecializationDecl *PrevDecl) + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, DC, L, SpecializedTemplate, Builder, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), - NumArgsAsWritten(NumArgInfos), InstantiatedFromMember(0, false) { } + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) { } public: static ClassTemplatePartialSpecializationDecl * @@ -966,7 +1049,8 @@ public: TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl); + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber); /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { @@ -983,6 +1067,10 @@ public: return NumArgsAsWritten; } + /// \brief Get the sequence number for this class template partial + /// specialization. + unsigned getSequenceNumber() const { return SequenceNumber; } + /// \brief Retrieve the member class template partial specialization from /// which this particular class template partial specialization was /// instantiated. @@ -1046,6 +1134,15 @@ public: "Only member templates can be member template specializations"); return First->InstantiatedFromMember.setInt(true); } + + /// Retrieves the injected specialization type for this partial + /// specialization. This is not the same as the type-decl-type for + /// this partial specialization, which is an InjectedClassNameType. + QualType getInjectedSpecializationType() const { + assert(getTypeForDecl() && "partial specialization has no type set!"); + return cast(getTypeForDecl()) + ->getInjectedSpecializationType(); + } // FIXME: Add Profile support! @@ -1141,6 +1238,10 @@ public: return CommonPtr->PartialSpecializations; } + /// \brief Retrieve the partial specializations as an ordered list. + void getPartialSpecializations( + llvm::SmallVectorImpl &PS); + /// \brief Find a class template partial specialization with the given /// type T. /// diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 6225069..9401786 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -198,9 +198,12 @@ public: /// callee in a call expression with dependent arguments. bool isDependentName() const; - /// getName - Retrieve the human-readable string for this name. + /// getNameAsString - Retrieve the human-readable string for this name. std::string getAsString() const; + /// printName - Print the human-readable name to a stream. + void printName(llvm::raw_ostream &OS) const; + /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in /// this declaration name, or NULL if this declaration name isn't a /// simple identifier. @@ -331,13 +334,15 @@ public: /// getCXXConstructorName - Returns the name of a C++ constructor /// for the given Type. DeclarationName getCXXConstructorName(CanQualType Ty) { - return getCXXSpecialName(DeclarationName::CXXConstructorName, Ty); + return getCXXSpecialName(DeclarationName::CXXConstructorName, + Ty.getUnqualifiedType()); } /// getCXXDestructorName - Returns the name of a C++ destructor /// for the given Type. DeclarationName getCXXDestructorName(CanQualType Ty) { - return getCXXSpecialName(DeclarationName::CXXDestructorName, Ty); + return getCXXSpecialName(DeclarationName::CXXDestructorName, + Ty.getUnqualifiedType()); } /// getCXXConversionFunctionName - Returns the name of a C++ diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h index 1954a28..2bbe502 100644 --- a/include/clang/AST/DependentDiagnostic.h +++ b/include/clang/AST/DependentDiagnostic.h @@ -22,6 +22,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclContextInternals.h" +#include "clang/AST/Type.h" namespace clang { @@ -42,6 +43,7 @@ public: AccessSpecifier AS, NamedDecl *TargetDecl, CXXRecordDecl *NamingClass, + QualType BaseObjectType, const PartialDiagnostic &PDiag) { DependentDiagnostic *DD = Create(Context, Parent, PDiag); DD->AccessData.Loc = Loc.getRawEncoding(); @@ -49,6 +51,7 @@ public: DD->AccessData.Access = AS; DD->AccessData.TargetDecl = TargetDecl; DD->AccessData.NamingClass = NamingClass; + DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr(); return DD; } @@ -81,6 +84,11 @@ public: return AccessData.NamingClass; } + QualType getAccessBaseObjectType() const { + assert(getKind() == Access); + return QualType::getFromOpaquePtr(AccessData.BaseObjectType); + } + const PartialDiagnostic &getDiagnostic() const { return Diag; } @@ -107,6 +115,7 @@ private: unsigned IsMember : 1; NamedDecl *TargetDecl; CXXRecordDecl *NamingClass; + void *BaseObjectType; } AccessData; }; }; diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index a687ee5..2946e46 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -17,6 +17,9 @@ #include "clang/AST/APValue.h" #include "clang/AST/Stmt.h" #include "clang/AST/Type.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/ASTVector.h" +#include "clang/AST/UsuallyTinyPtrVector.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" @@ -32,11 +35,15 @@ namespace clang { class NamedDecl; class ValueDecl; class BlockDecl; + class CXXBaseSpecifier; class CXXOperatorCallExpr; class CXXMemberCallExpr; class TemplateArgumentLoc; class TemplateArgumentListInfo; +/// \brief A simple array of base specifiers. +typedef UsuallyTinyPtrVector CXXBaseSpecifierArray; + /// Expr - This represents one expression. Note that Expr's are subclasses of /// Stmt. This allows an expression to be transparently used any place a Stmt /// is required. @@ -197,6 +204,12 @@ public: /// \brief Returns whether this expression refers to a vector element. bool refersToVectorElement() const; + /// isKnownToHaveBooleanValue - Return true if this is an integer expression + /// that is known to return 0 or 1. This happens for _Bool/bool expressions + /// but also int expressions which are produced by things like comparisons in + /// C. + bool isKnownToHaveBooleanValue() const; + /// isIntegerConstantExpr - Return true if this expression is a valid integer /// constant expression, and, if so, return its value in Result. If not a /// valid i-c-e, return false and fill in Loc (if specified) with the location @@ -210,7 +223,7 @@ public: } /// isConstantInitializer - Returns true if this expression is a constant /// initializer, which can be emitted at compile-time. - bool isConstantInitializer(ASTContext &Ctx) const; + bool isConstantInitializer(ASTContext &Ctx) const; /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult { @@ -302,7 +315,7 @@ public: /// its subexpression. If that subexpression is also a ParenExpr, /// then this method recursively returns its subexpression, and so forth. /// Otherwise, the method returns the current Expr. - Expr* IgnoreParens(); + Expr *IgnoreParens(); /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr /// or CastExprs, returning their operand. @@ -331,7 +344,7 @@ public: /// temporary object. const Expr *getTemporaryObject() const; - const Expr* IgnoreParens() const { + const Expr *IgnoreParens() const { return const_cast(this)->IgnoreParens(); } const Expr *IgnoreParenCasts() const { @@ -901,7 +914,7 @@ public: /// /// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose /// subexpression is a compound literal with the various MemberExpr and -/// ArraySubscriptExpr's applied to it. +/// ArraySubscriptExpr's applied to it. (This is only used in C) /// class UnaryOperator : public Expr { public: @@ -990,6 +1003,205 @@ public: virtual child_iterator child_end(); }; +/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form +/// offsetof(record-type, member-designator). For example, given: +/// @code +/// struct S { +/// float f; +/// double d; +/// }; +/// struct T { +/// int i; +/// struct S s[10]; +/// }; +/// @endcode +/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). + +class OffsetOfExpr : public Expr { +public: + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + class OffsetOfNode { + public: + /// \brief The kind of offsetof node we have. + enum Kind { + /// \brief An index into an array. + Array = 0x00, + /// \brief A field. + Field = 0x01, + /// \brief A field in a dependent type, known only by its name. + Identifier = 0x02, + /// \brief An implicit indirection through a C++ base class, when the + /// field found is in a base class. + Base = 0x03 + }; + + private: + enum { MaskBits = 2, Mask = 0x03 }; + + /// \brief The source range that covers this part of the designator. + SourceRange Range; + + /// \brief The data describing the designator, which comes in three + /// different forms, depending on the lower two bits. + /// - An unsigned index into the array of Expr*'s stored after this node + /// in memory, for [constant-expression] designators. + /// - A FieldDecl*, for references to a known field. + /// - An IdentifierInfo*, for references to a field with a given name + /// when the class type is dependent. + /// - A CXXBaseSpecifier*, for references that look at a field in a + /// base class. + uintptr_t Data; + + public: + /// \brief Create an offsetof node that refers to an array element. + OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, + SourceLocation RBracketLoc) + : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { } + + /// \brief Create an offsetof node that refers to a field. + OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, + SourceLocation NameLoc) + : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast(Field) | OffsetOfNode::Field) { } + + /// \brief Create an offsetof node that refers to an identifier. + OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name, + SourceLocation NameLoc) + : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast(Name) | Identifier) { } + + /// \brief Create an offsetof node that refers into a C++ base class. + explicit OffsetOfNode(const CXXBaseSpecifier *Base) + : Range(), Data(reinterpret_cast(Base) | OffsetOfNode::Base) {} + + /// \brief Determine what kind of offsetof node this is. + Kind getKind() const { + return static_cast(Data & Mask); + } + + /// \brief For an array element node, returns the index into the array + /// of expressions. + unsigned getArrayExprIndex() const { + assert(getKind() == Array); + return Data >> 2; + } + + /// \brief For a field offsetof node, returns the field. + FieldDecl *getField() const { + assert(getKind() == Field); + return reinterpret_cast(Data & ~(uintptr_t)Mask); + } + + /// \brief For a field or identifier offsetof node, returns the name of + /// the field. + IdentifierInfo *getFieldName() const; + + /// \brief For a base class node, returns the base specifier. + CXXBaseSpecifier *getBase() const { + assert(getKind() == Base); + return reinterpret_cast(Data & ~(uintptr_t)Mask); + } + + /// \brief Retrieve the source range that covers this offsetof node. + /// + /// For an array element node, the source range contains the locations of + /// the square brackets. For a field or identifier node, the source range + /// contains the location of the period (if there is one) and the + /// identifier. + SourceRange getRange() const { return Range; } + }; + +private: + + SourceLocation OperatorLoc, RParenLoc; + // Base type; + TypeSourceInfo *TSInfo; + // Number of sub-components (i.e. instances of OffsetOfNode). + unsigned NumComps; + // Number of sub-expressions (i.e. array subscript expressions). + unsigned NumExprs; + + OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc); + + explicit OffsetOfExpr(unsigned numComps, unsigned numExprs) + : Expr(OffsetOfExprClass, EmptyShell()), + TSInfo(0), NumComps(numComps), NumExprs(numExprs) {} + +public: + + static OffsetOfExpr *Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc); + + static OffsetOfExpr *CreateEmpty(ASTContext &C, + unsigned NumComps, unsigned NumExprs); + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Return the location of the right parentheses. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation R) { RParenLoc = R; } + + TypeSourceInfo *getTypeSourceInfo() const { + return TSInfo; + } + void setTypeSourceInfo(TypeSourceInfo *tsi) { + TSInfo = tsi; + } + + const OffsetOfNode &getComponent(unsigned Idx) { + assert(Idx < NumComps && "Subscript out of range"); + return reinterpret_cast (this + 1)[Idx]; + } + + void setComponent(unsigned Idx, OffsetOfNode ON) { + assert(Idx < NumComps && "Subscript out of range"); + reinterpret_cast (this + 1)[Idx] = ON; + } + + unsigned getNumComponents() const { + return NumComps; + } + + Expr* getIndexExpr(unsigned Idx) { + assert(Idx < NumExprs && "Subscript out of range"); + return reinterpret_cast( + reinterpret_cast(this+1) + NumComps)[Idx]; + } + + void setIndexExpr(unsigned Idx, Expr* E) { + assert(Idx < NumComps && "Subscript out of range"); + reinterpret_cast( + reinterpret_cast(this+1) + NumComps)[Idx] = E; + } + + unsigned getNumExpressions() const { + return NumExprs; + } + + virtual SourceRange getSourceRange() const { + return SourceRange(OperatorLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OffsetOfExprClass; + } + + static bool classof(const OffsetOfExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of /// types and expressions. class SizeOfAlignOfExpr : public Expr { @@ -1274,7 +1486,7 @@ public: class MemberExpr : public Expr { /// Extra data stored in some member expressions. struct MemberNameQualifier : public NameQualifier { - NamedDecl *FoundDecl; + DeclAccessPair FoundDecl; }; /// Base - the expression for the base pointer or structure references. In @@ -1349,7 +1561,7 @@ public: static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, - ValueDecl *memberdecl, NamedDecl *founddecl, + ValueDecl *memberdecl, DeclAccessPair founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty); @@ -1365,9 +1577,10 @@ public: void setMemberDecl(ValueDecl *D) { MemberDecl = D; } /// \brief Retrieves the declaration found by lookup. - NamedDecl *getFoundDecl() const { + DeclAccessPair getFoundDecl() const { if (!HasQualifierOrFoundDecl) - return getMemberDecl(); + return DeclAccessPair::make(getMemberDecl(), + getMemberDecl()->getAccess()); return getMemberQualifier()->FoundDecl; } @@ -1636,8 +1849,53 @@ public: private: CastKind Kind; Stmt *Op; + + /// BasePath - For derived-to-base and base-to-derived casts, the base array + /// contains the inheritance path. + CXXBaseSpecifierArray BasePath; + + void CheckBasePath() const { +#ifndef NDEBUG + switch (getCastKind()) { + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerived: + case CK_BaseToDerivedMemberPointer: + assert(!BasePath.empty() && "Cast kind should have a base path!"); + break; + + // These should not have an inheritance path. + case CK_Unknown: + case CK_BitCast: + case CK_NoOp: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToMemberPointer: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: + case CK_MemberPointerToBoolean: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + assert(BasePath.empty() && "Cast kind should not have a base path!"); + break; + } +#endif + } + protected: - CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op) : + CastExpr(StmtClass SC, QualType ty, const CastKind kind, Expr *op, + CXXBaseSpecifierArray BasePath) : Expr(SC, ty, // Cast expressions are type-dependent if the type is // dependent (C++ [temp.dep.expr]p3). @@ -1645,12 +1903,16 @@ protected: // Cast expressions are value-dependent if the type is // dependent or if the subexpression is value-dependent. ty->isDependentType() || (op && op->isValueDependent())), - Kind(kind), Op(op) {} + Kind(kind), Op(op), BasePath(BasePath) { + CheckBasePath(); + } /// \brief Construct an empty cast. CastExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { } + virtual void DoDestroy(ASTContext &C); + public: CastKind getCastKind() const { return Kind; } void setCastKind(CastKind K) { Kind = K; } @@ -1667,10 +1929,12 @@ public: const Expr *getSubExprAsWritten() const { return const_cast(this)->getSubExprAsWritten(); } - + + const CXXBaseSpecifierArray& getBasePath() const { return BasePath; } + static bool classof(const Stmt *T) { StmtClass SC = T->getStmtClass(); - if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) + if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass) return true; if (SC >= ImplicitCastExprClass && SC <= CStyleCastExprClass) @@ -1706,14 +1970,15 @@ class ImplicitCastExpr : public CastExpr { bool LvalueCast; public: - ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, bool Lvalue) : - CastExpr(ImplicitCastExprClass, ty, kind, op), LvalueCast(Lvalue) { } + ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, + CXXBaseSpecifierArray BasePath, bool Lvalue) + : CastExpr(ImplicitCastExprClass, ty, kind, op, BasePath), + LvalueCast(Lvalue) { } /// \brief Construct an empty implicit cast. explicit ImplicitCastExpr(EmptyShell Shell) : CastExpr(ImplicitCastExprClass, Shell) { } - virtual SourceRange getSourceRange() const { return getSubExpr()->getSourceRange(); } @@ -1753,8 +2018,9 @@ class ExplicitCastExpr : public CastExpr { protected: ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind, - Expr *op, TypeSourceInfo *writtenTy) - : CastExpr(SC, exprTy, kind, op), TInfo(writtenTy) {} + Expr *op, CXXBaseSpecifierArray BasePath, + TypeSourceInfo *writtenTy) + : CastExpr(SC, exprTy, kind, op, BasePath), TInfo(writtenTy) {} /// \brief Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell) @@ -1774,7 +2040,7 @@ public: StmtClass SC = T->getStmtClass(); if (SC >= CStyleCastExprClass && SC <= CStyleCastExprClass) return true; - if (SC >= CXXNamedCastExprClass && SC <= CXXFunctionalCastExprClass) + if (SC >= CXXStaticCastExprClass && SC <= CXXFunctionalCastExprClass) return true; return false; @@ -1790,10 +2056,10 @@ class CStyleCastExpr : public ExplicitCastExpr { SourceLocation RPLoc; // the location of the right paren public: CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, - TypeSourceInfo *writtenTy, - SourceLocation l, SourceLocation r) : - ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy), - LPLoc(l), RPLoc(r) {} + CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation r) + : ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, BasePath, + writtenTy), LPLoc(l), RPLoc(r) {} /// \brief Construct an empty C-style explicit cast. explicit CStyleCastExpr(EmptyShell Shell) @@ -2362,7 +2628,7 @@ public: virtual child_iterator child_end(); }; -/// VAArgExpr, used for the builtin function __builtin_va_start. +/// VAArgExpr, used for the builtin function __builtin_va_arg. class VAArgExpr : public Expr { Stmt *Val; SourceLocation BuiltinLoc, RParenLoc; @@ -2373,7 +2639,7 @@ public: BuiltinLoc(BLoc), RParenLoc(RPLoc) { } - /// \brief Create an empty __builtin_va_start expression. + /// \brief Create an empty __builtin_va_arg expression. explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { } const Expr *getSubExpr() const { return cast(Val); } @@ -2438,7 +2704,8 @@ public: /// serves as its syntactic form. class InitListExpr : public Expr { // FIXME: Eliminate this vector in favor of ASTContext allocation - std::vector InitExprs; + typedef ASTVector InitExprsTy; + InitExprsTy InitExprs; SourceLocation LBraceLoc, RBraceLoc; /// Contains the initializer list that describes the syntactic form @@ -2454,11 +2721,13 @@ class InitListExpr : public Expr { bool HadArrayRangeDesignator; public: - InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits, + InitListExpr(ASTContext &C, SourceLocation lbraceloc, + Expr **initexprs, unsigned numinits, SourceLocation rbraceloc); /// \brief Build an empty initializer list. - explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty) { } + explicit InitListExpr(ASTContext &C, EmptyShell Empty) + : Expr(InitListExprClass, Empty), InitExprs(C) { } unsigned getNumInits() const { return InitExprs.size(); } @@ -2478,7 +2747,7 @@ public: } /// \brief Reserve space for some number of initializers. - void reserveInits(unsigned NumInits); + void reserveInits(ASTContext &C, unsigned NumInits); /// @brief Specify the number of initializers /// @@ -2495,7 +2764,7 @@ public: /// When @p Init is out of range for this initializer list, the /// initializer list will be extended with NULL expressions to /// accomodate the new entry. - Expr *updateInit(unsigned Init, Expr *expr); + Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr); /// \brief If this initializes a union, specifies which field in the /// union to initialize. @@ -2541,8 +2810,8 @@ public: virtual child_iterator child_begin(); virtual child_iterator child_end(); - typedef std::vector::iterator iterator; - typedef std::vector::reverse_iterator reverse_iterator; + typedef InitExprsTy::iterator iterator; + typedef InitExprsTy::reverse_iterator reverse_iterator; iterator begin() { return InitExprs.begin(); } iterator end() { return InitExprs.end(); } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6e2e832..f9ca78a 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -118,8 +118,9 @@ private: protected: CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op, - TypeSourceInfo *writtenTy, SourceLocation l) - : ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {} + CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy, + SourceLocation l) + : ExplicitCastExpr(SC, ty, kind, op, BasePath, writtenTy), Loc(l) {} explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell) : ExplicitCastExpr(SC, Shell) { } @@ -137,7 +138,6 @@ public: } static bool classof(const Stmt *T) { switch (T->getStmtClass()) { - case CXXNamedCastExprClass: case CXXStaticCastExprClass: case CXXDynamicCastExprClass: case CXXReinterpretCastExprClass: @@ -156,9 +156,10 @@ public: /// @c static_cast(1.0). class CXXStaticCastExpr : public CXXNamedCastExpr { public: - CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op, - TypeSourceInfo *writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {} + CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op, + CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy, + SourceLocation l) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, BasePath, writtenTy, l) {} explicit CXXStaticCastExpr(EmptyShell Empty) : CXXNamedCastExpr(CXXStaticCastExprClass, Empty) { } @@ -177,9 +178,11 @@ public: /// @c dynamic_cast(BasePtr). class CXXDynamicCastExpr : public CXXNamedCastExpr { public: - CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, - TypeSourceInfo *writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {} + CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, + CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy, + SourceLocation l) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, BasePath, + writtenTy, l) {} explicit CXXDynamicCastExpr(EmptyShell Empty) : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty) { } @@ -199,8 +202,9 @@ public: class CXXReinterpretCastExpr : public CXXNamedCastExpr { public: CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op, + CXXBaseSpecifierArray BasePath, TypeSourceInfo *writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op, BasePath, writtenTy, l) {} explicit CXXReinterpretCastExpr(EmptyShell Empty) @@ -221,7 +225,8 @@ class CXXConstCastExpr : public CXXNamedCastExpr { public: CXXConstCastExpr(QualType ty, Expr *op, TypeSourceInfo *writtenTy, SourceLocation l) - : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {} + : CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, + CXXBaseSpecifierArray(), writtenTy, l) {} explicit CXXConstCastExpr(EmptyShell Empty) : CXXNamedCastExpr(CXXConstCastExprClass, Empty) { } @@ -293,37 +298,41 @@ public: /// This represents code like @c typeid(int) or @c typeid(*objPtr) class CXXTypeidExpr : public Expr { private: - bool isTypeOp : 1; - union { - void *Ty; - Stmt *Ex; - } Operand; + llvm::PointerUnion Operand; SourceRange Range; public: - CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) : - Expr(CXXTypeidExprClass, Ty, + CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + Operand->getType()->isDependentType()), + Operand(Operand), Range(R) { } + + CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, // typeid is never type-dependent (C++ [temp.dep.expr]p4) false, // typeid is value-dependent if the type or expression are dependent - (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType() - : static_cast(op)->isValueDependent())), - isTypeOp(isTypeOp), Range(r) { - if (isTypeOp) - Operand.Ty = op; - else - // op was an Expr*, so cast it back to that to be safe - Operand.Ex = static_cast(op); - } + Operand->isTypeDependent() || Operand->isValueDependent()), + Operand(Operand), Range(R) { } + + bool isTypeOperand() const { return Operand.is(); } + + /// \brief Retrieves the type operand of this typeid() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand() const; - bool isTypeOperand() const { return isTypeOp; } - QualType getTypeOperand() const { + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); - return QualType::getFromOpaquePtr(Operand.Ty); + return Operand.get(); } + Expr* getExprOperand() const { assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); - return static_cast(Operand.Ex); + return static_cast(Operand.get()); } virtual SourceRange getSourceRange() const { @@ -621,12 +630,20 @@ public: /// CXXConstructExpr - Represents a call to a C++ constructor. class CXXConstructExpr : public Expr { +public: + enum ConstructionKind { + CK_Complete, + CK_NonVirtualBase, + CK_VirtualBase + }; + +private: CXXConstructorDecl *Constructor; SourceLocation Loc; bool Elidable : 1; bool ZeroInitialization : 1; - bool BaseInitialization : 1; + unsigned ConstructKind : 2; Stmt **Args; unsigned NumArgs; @@ -636,7 +653,7 @@ protected: CXXConstructorDecl *d, bool elidable, Expr **args, unsigned numargs, bool ZeroInitialization = false, - bool BaseInitialization = false); + ConstructionKind ConstructKind = CK_Complete); ~CXXConstructExpr() { } virtual void DoDestroy(ASTContext &C); @@ -651,7 +668,7 @@ public: CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization = false, - bool BaseInitialization = false); + ConstructionKind ConstructKind = CK_Complete); CXXConstructorDecl* getConstructor() const { return Constructor; } @@ -673,8 +690,12 @@ public: /// \brief Determines whether this constructor is actually constructing /// a base class (rather than a complete object). - bool isBaseInitialization() const { return BaseInitialization; } - void setBaseInitialization(bool BI) { BaseInitialization = BI; } + ConstructionKind getConstructionKind() const { + return (ConstructionKind)ConstructKind; + } + void setConstructionKind(ConstructionKind CK) { + ConstructKind = CK; + } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; @@ -725,9 +746,10 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr { public: CXXFunctionalCastExpr(QualType ty, TypeSourceInfo *writtenTy, SourceLocation tyBeginLoc, CastKind kind, - Expr *castExpr, SourceLocation rParenLoc) + Expr *castExpr, CXXBaseSpecifierArray BasePath, + SourceLocation rParenLoc) : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr, - writtenTy), + BasePath, writtenTy), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} explicit CXXFunctionalCastExpr(EmptyShell Shell) @@ -774,7 +796,8 @@ public: CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, SourceLocation tyBeginLoc, Expr **Args,unsigned NumArgs, - SourceLocation rParenLoc); + SourceLocation rParenLoc, + bool ZeroInitialization = false); ~CXXTemporaryObjectExpr() { } @@ -1290,6 +1313,9 @@ public: Results.append(Begin, End); } + /// Gets the naming class of this lookup, if any. + CXXRecordDecl *getNamingClass() const; + typedef UnresolvedSetImpl::iterator decls_iterator; decls_iterator decls_begin() const { return Results.begin(); } decls_iterator decls_end() const { return Results.end(); } diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 6f43973..8a09f4e 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -59,13 +59,14 @@ public: /// and behavior as StringLiteral except that the string initializer is obtained /// from ASTContext with the encoding type as an argument. class ObjCEncodeExpr : public Expr { - QualType EncType; + TypeSourceInfo *EncodedType; SourceLocation AtLoc, RParenLoc; public: - ObjCEncodeExpr(QualType T, QualType ET, + ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, SourceLocation at, SourceLocation rp) - : Expr(ObjCEncodeExprClass, T, ET->isDependentType(), - ET->isDependentType()), EncType(ET), AtLoc(at), RParenLoc(rp) {} + : Expr(ObjCEncodeExprClass, T, EncodedType->getType()->isDependentType(), + EncodedType->getType()->isDependentType()), + EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} @@ -75,9 +76,12 @@ public: SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } - QualType getEncodedType() const { return EncType; } - void setEncodedType(QualType T) { EncType = T; } + QualType getEncodedType() const { return EncodedType->getType(); } + TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; } + void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) { + EncodedType = EncType; + } virtual SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); @@ -177,11 +181,12 @@ class ObjCIvarRefExpr : public Expr { public: ObjCIvarRefExpr(ObjCIvarDecl *d, - QualType t, SourceLocation l, Expr *base=0, + QualType t, SourceLocation l, Expr *base, bool arrow = false, bool freeIvar = false) : - Expr(ObjCIvarRefExprClass, t, false, false), D(d), - Loc(l), Base(base), IsArrow(arrow), - IsFreeIvar(freeIvar) {} + Expr(ObjCIvarRefExprClass, t, /*TypeDependent=*/false, + base->isValueDependent()), D(d), + Loc(l), Base(base), IsArrow(arrow), + IsFreeIvar(freeIvar) {} explicit ObjCIvarRefExpr(EmptyShell Empty) : Expr(ObjCIvarRefExprClass, Empty) {} @@ -228,8 +233,9 @@ private: public: ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, SourceLocation l, Expr *base) - : Expr(ObjCPropertyRefExprClass, t, false, false), AsProperty(PD), - IdLoc(l), Base(base) { + : Expr(ObjCPropertyRefExprClass, t, /*TypeDependent=*/false, + base->isValueDependent()), + AsProperty(PD), IdLoc(l), Base(base) { } explicit ObjCPropertyRefExpr(EmptyShell Empty) @@ -293,7 +299,8 @@ public: QualType t, ObjCMethodDecl *setter, SourceLocation l, Expr *base) - : Expr(ObjCImplicitSetterGetterRefExprClass, t, false, false), + : Expr(ObjCImplicitSetterGetterRefExprClass, t, /*TypeDependent=*/false, + base->isValueDependent()), Setter(setter), Getter(getter), MemberLoc(l), Base(base), InterfaceDecl(0), ClassLoc(SourceLocation()) { } @@ -339,152 +346,376 @@ public: virtual child_iterator child_end(); }; +/// \brief An expression that sends a message to the given Objective-C +/// object or class. +/// +/// The following contains two message send expressions: +/// +/// \code +/// [[NSString alloc] initWithString:@"Hello"] +/// \endcode +/// +/// The innermost message send invokes the "alloc" class method on the +/// NSString class, while the outermost message send invokes the +/// "initWithString" instance method on the object returned from +/// NSString's "alloc". In all, an Objective-C message send can take +/// on four different (although related) forms: +/// +/// 1. Send to an object instance. +/// 2. Send to a class. +/// 3. Send to the superclass instance of the current class. +/// 4. Send to the superclass of the current class. +/// +/// All four kinds of message sends are modeled by the ObjCMessageExpr +/// class, and can be distinguished via \c getReceiverKind(). Example: +/// class ObjCMessageExpr : public Expr { - // SubExprs - The receiver and arguments of the message expression. - Stmt **SubExprs; + /// \brief The number of arguments in the message send, not + /// including the receiver. + unsigned NumArgs : 16; + + /// \brief The kind of message send this is, which is one of the + /// ReceiverKind values. + /// + /// We pad this out to a byte to avoid excessive masking and shifting. + unsigned Kind : 8; + + /// \brief Whether we have an actual method prototype in \c + /// SelectorOrMethod. + /// + /// When non-zero, we have a method declaration; otherwise, we just + /// have a selector. + unsigned HasMethod : 8; + + /// \brief When the message expression is a send to 'super', this is + /// the location of the 'super' keyword. + SourceLocation SuperLoc; + + /// \brief Stores either the selector that this message is sending + /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer + /// referring to the method that we type-checked against. + uintptr_t SelectorOrMethod; + + /// \brief The source locations of the open and close square + /// brackets ('[' and ']', respectively). + SourceLocation LBracLoc, RBracLoc; + + ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) + : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0), + HasMethod(0), SelectorOrMethod(0) { } + + ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + + /// \brief Retrieve the pointer value of the message receiver. + void *getReceiverPointer() const { + return *const_cast( + reinterpret_cast(this + 1)); + } - // NumArgs - The number of arguments (not including the receiver) to the - // message expression. - unsigned NumArgs; + /// \brief Set the pointer value of the message receiver. + void setReceiverPointer(void *Value) { + *reinterpret_cast(this + 1) = Value; + } - /// \brief The location of the class name in a class message. - SourceLocation ClassNameLoc; +public: + /// \brief The kind of receiver this message is sending to. + enum ReceiverKind { + /// \brief The receiver is a class. + Class = 0, + /// \brief The receiver is an object instance. + Instance, + /// \brief The receiver is a superclass. + SuperClass, + /// \brief The receiver is the instance of the superclass object. + SuperInstance + }; - // A unigue name for this message. - Selector SelName; + /// \brief Create a message send to super. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param SuperLoc The location of the "super" keyword. + /// + /// \param IsInstanceSuper Whether this is an instance "super" + /// message (otherwise, it's a class "super" message). + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + + /// \brief Create a class message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param Receiver The type of the receiver, including + /// source-location information. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + + /// \brief Create an instance message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param Receiver The expression used to produce the object that + /// will receive this message. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc); + + /// \brief Create an empty Objective-C message expression, to be + /// filled in by subsequent calls. + /// + /// \param Context The context in which the message send will be created. + /// + /// \param NumArgs The number of message arguments, not including + /// the receiver. + static ObjCMessageExpr *CreateEmpty(ASTContext &Context, unsigned NumArgs); + + /// \brief Determine the kind of receiver that this message is being + /// sent to. + ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; } + + /// \brief Determine whether this is an instance message to either a + /// computed object or to super. + bool isInstanceMessage() const { + return getReceiverKind() == Instance || getReceiverKind() == SuperInstance; + } - // A method prototype for this message (optional). - // FIXME: Since method decls contain the selector, and most messages have a - // prototype, consider devising a scheme for unifying SelName/MethodProto. - ObjCMethodDecl *MethodProto; + /// \brief Determine whether this is an class message to either a + /// specified class or to super. + bool isClassMessage() const { + return getReceiverKind() == Class || getReceiverKind() == SuperClass; + } - SourceLocation LBracloc, RBracloc; + /// \brief Returns the receiver of an instance message. + /// + /// \brief Returns the object expression for an instance message, or + /// NULL for a message that is not an instance message. + Expr *getInstanceReceiver() { + if (getReceiverKind() == Instance) + return static_cast(getReceiverPointer()); - // Constants for indexing into SubExprs. - enum { RECEIVER=0, ARGS_START=1 }; + return 0; + } + const Expr *getInstanceReceiver() const { + return const_cast(this)->getInstanceReceiver(); + } - // Bit-swizzling flags. - enum { IsInstMeth=0, IsClsMethDeclUnknown, IsClsMethDeclKnown, Flags=0x3 }; - unsigned getFlag() const { return (uintptr_t) SubExprs[RECEIVER] & Flags; } + /// \brief Turn this message send into an instance message that + /// computes the receiver object with the given expression. + void setInstanceReceiver(Expr *rec) { + Kind = Instance; + setReceiverPointer(rec); + } + + /// \brief Returns the type of a class message send, or NULL if the + /// message is not a class message. + QualType getClassReceiver() const { + if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo()) + return TSInfo->getType(); + + return QualType(); + } -public: - /// This constructor is used to represent class messages where the - /// ObjCInterfaceDecl* of the receiver is not known. - ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, ObjCMethodDecl *methDecl, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned NumArgs); - - /// This constructor is used to represent class messages where the - /// ObjCInterfaceDecl* of the receiver is known. - // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, ObjCMethodDecl *methDecl, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned NumArgs); - - // constructor for instance messages. - ObjCMessageExpr(ASTContext &C, Expr *receiver, Selector selInfo, - QualType retType, ObjCMethodDecl *methDecl, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned NumArgs); - - explicit ObjCMessageExpr(EmptyShell Empty) - : Expr(ObjCMessageExprClass, Empty), SubExprs(0), NumArgs(0) {} - - virtual void DoDestroy(ASTContext &C); - - /// getReceiver - Returns the receiver of the message expression. - /// This can be NULL if the message is for class methods. For - /// class methods, use getClassName. - /// FIXME: need to handle/detect 'super' usage within a class method. - Expr *getReceiver() { - uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - return (x & Flags) == IsInstMeth ? (Expr*) x : 0; - } - const Expr *getReceiver() const { - return const_cast(this)->getReceiver(); - } - // FIXME: need setters for different receiver types. - void setReceiver(Expr *rec) { SubExprs[RECEIVER] = rec; } - Selector getSelector() const { return SelName; } - void setSelector(Selector S) { SelName = S; } + /// \brief Returns a type-source information of a class message + /// send, or NULL if the message is not a class message. + TypeSourceInfo *getClassReceiverTypeInfo() const { + if (getReceiverKind() == Class) + return reinterpret_cast(getReceiverPointer()); + return 0; + } + + void setClassReceiver(TypeSourceInfo *TSInfo) { + Kind = Class; + setReceiverPointer(TSInfo); + } - const ObjCMethodDecl *getMethodDecl() const { return MethodProto; } - ObjCMethodDecl *getMethodDecl() { return MethodProto; } - void setMethodDecl(ObjCMethodDecl *MD) { MethodProto = MD; } + /// \brief Retrieve the location of the 'super' keyword for a class + /// or instance message to 'super', otherwise an invalid source location. + SourceLocation getSuperLoc() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return SuperLoc; - /// \brief Describes the class receiver of a message send. - struct ClassInfo { - /// \brief The interface declaration for the class that is - /// receiving the message. May be NULL. - ObjCInterfaceDecl *Decl; + return SourceLocation(); + } - /// \brief The name of the class that is receiving the - /// message. This will never be NULL. - IdentifierInfo *Name; + /// \brief Retrieve the Objective-C interface to which this message + /// is being directed, if known. + /// + /// This routine cross-cuts all of the different kinds of message + /// sends to determine what the underlying (statically known) type + /// of the receiver will be; use \c getReceiverKind() to determine + /// whether the message is a class or an instance method, whether it + /// is a send to super or not, etc. + /// + /// \returns The Objective-C interface if known, otherwise NULL. + ObjCInterfaceDecl *getReceiverInterface() const; + + /// \brief Retrieve the type referred to by 'super'. + /// + /// The returned type will either be an ObjCInterfaceType (for an + /// class message to super) or an ObjCObjectPointerType that refers + /// to a class (for an instance message to super); + QualType getSuperType() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return QualType::getFromOpaquePtr(getReceiverPointer()); + + return QualType(); + } - /// \brief The source location of the class name. - SourceLocation Loc; + void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) { + Kind = IsInstanceSuper? SuperInstance : SuperClass; + SuperLoc = Loc; + setReceiverPointer(T.getAsOpaquePtr()); + } - ClassInfo() : Decl(0), Name(0), Loc() { } + Selector getSelector() const; - ClassInfo(ObjCInterfaceDecl *Decl, IdentifierInfo *Name, SourceLocation Loc) - : Decl(Decl), Name(Name), Loc(Loc) { } - }; + void setSelector(Selector S) { + HasMethod = false; + SelectorOrMethod = reinterpret_cast(S.getAsOpaquePtr()); + } - /// getClassInfo - For class methods, this returns both the ObjCInterfaceDecl* - /// and IdentifierInfo* of the invoked class. Both can be NULL if this - /// is an instance message, and the ObjCInterfaceDecl* can be NULL if none - /// was available when this ObjCMessageExpr object was constructed. - ClassInfo getClassInfo() const; - void setClassInfo(const ClassInfo &C); + const ObjCMethodDecl *getMethodDecl() const { + if (HasMethod) + return reinterpret_cast(SelectorOrMethod); - /// getClassName - For class methods, this returns the invoked class, - /// and returns NULL otherwise. For instance methods, use getReceiver. - IdentifierInfo *getClassName() const { - return getClassInfo().Name; + return 0; } - /// getNumArgs - Return the number of actual arguments to this call. + ObjCMethodDecl *getMethodDecl() { + if (HasMethod) + return reinterpret_cast(SelectorOrMethod); + + return 0; + } + + void setMethodDecl(ObjCMethodDecl *MD) { + HasMethod = true; + SelectorOrMethod = reinterpret_cast(MD); + } + + /// \brief Return the number of actual arguments in this message, + /// not counting the receiver. unsigned getNumArgs() const { return NumArgs; } - void setNumArgs(unsigned nArgs) { - NumArgs = nArgs; - // FIXME: should always allocate SubExprs via the ASTContext's - // allocator. - if (!SubExprs) - SubExprs = new Stmt* [NumArgs + 1]; + + /// \brief Retrieve the arguments to this message, not including the + /// receiver. + Stmt **getArgs() { + return reinterpret_cast(this + 1) + 1; + } + const Stmt * const *getArgs() const { + return reinterpret_cast(this + 1) + 1; } /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < NumArgs && "Arg access out of range!"); - return cast(SubExprs[Arg+ARGS_START]); + return cast(getArgs()[Arg]); } const Expr *getArg(unsigned Arg) const { assert(Arg < NumArgs && "Arg access out of range!"); - return cast(SubExprs[Arg+ARGS_START]); + return cast(getArgs()[Arg]); } /// setArg - Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { assert(Arg < NumArgs && "Arg access out of range!"); - SubExprs[Arg+ARGS_START] = ArgExpr; + getArgs()[Arg] = ArgExpr; } - SourceLocation getLeftLoc() const { return LBracloc; } - SourceLocation getRightLoc() const { return RBracloc; } + SourceLocation getLeftLoc() const { return LBracLoc; } + SourceLocation getRightLoc() const { return RBracLoc; } - void setLeftLoc(SourceLocation L) { LBracloc = L; } - void setRightLoc(SourceLocation L) { RBracloc = L; } + void setLeftLoc(SourceLocation L) { LBracLoc = L; } + void setRightLoc(SourceLocation L) { RBracLoc = L; } void setSourceRange(SourceRange R) { - LBracloc = R.getBegin(); - RBracloc = R.getEnd(); + LBracLoc = R.getBegin(); + RBracLoc = R.getEnd(); } virtual SourceRange getSourceRange() const { - return SourceRange(LBracloc, RBracloc); + return SourceRange(LBracLoc, RBracLoc); } static bool classof(const Stmt *T) { @@ -499,14 +730,17 @@ public: typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; - arg_iterator arg_begin() { return &SubExprs[ARGS_START]; } - arg_iterator arg_end() { return &SubExprs[ARGS_START] + NumArgs; } - const_arg_iterator arg_begin() const { return &SubExprs[ARGS_START]; } - const_arg_iterator arg_end() const { return &SubExprs[ARGS_START] + NumArgs; } + arg_iterator arg_begin() { return getArgs(); } + arg_iterator arg_end() { return getArgs() + NumArgs; } + const_arg_iterator arg_begin() const { return getArgs(); } + const_arg_iterator arg_end() const { return getArgs() + NumArgs; } }; /// ObjCSuperExpr - Represents the "super" expression in Objective-C, /// which refers to the object on which the current method is executing. +/// +/// FIXME: This class is intended for removal, once its remaining +/// clients have been altered to represent "super" internally. class ObjCSuperExpr : public Expr { SourceLocation Loc; public: @@ -542,7 +776,8 @@ class ObjCIsaExpr : public Expr { bool IsArrow; public: ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) - : Expr(ObjCIsaExprClass, ty, false, false), + : Expr(ObjCIsaExprClass, ty, /*TypeDependent=*/false, + base->isValueDependent()), Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} /// \brief Build an empty expression. diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index b8d80bc..79e4451 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -66,6 +66,13 @@ public: /// building a new declaration. virtual Decl *GetDecl(uint32_t ID) = 0; + /// \brief Resolve a selector ID into a selector. + virtual Selector GetSelector(uint32_t ID) = 0; + + /// \brief Returns the number of selectors known to the external AST + /// source. + virtual uint32_t GetNumKnownSelectors() = 0; + /// \brief Resolve the offset of a statement in the decl stream into a /// statement. /// diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 4668489..0b68a40 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -70,13 +70,13 @@ namespace clang { }; class ConstExprIterator { - Stmt* const * I; + const Stmt * const *I; public: - ConstExprIterator(Stmt* const* i) : I(i) {} + ConstExprIterator(const Stmt * const *i) : I(i) {} ConstExprIterator() : I(0) {} ConstExprIterator& operator++() { ++I; return *this; } - ConstExprIterator operator+(size_t i) { return I+i; } - ConstExprIterator operator-(size_t i) { return I-i; } + ConstExprIterator operator+(size_t i) const { return I+i; } + ConstExprIterator operator-(size_t i) const { return I-i; } const Expr * operator[](size_t idx) const; signed operator-(const ConstExprIterator& R) const { return I - R.I; } const Expr * operator*() const; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index ec6149e..3a23e49 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -78,6 +78,7 @@ EXPR(StringLiteral , Expr) EXPR(CharacterLiteral , Expr) EXPR(ParenExpr , Expr) EXPR(UnaryOperator , Expr) +EXPR(OffsetOfExpr , Expr) EXPR(SizeOfAlignOfExpr , Expr) EXPR(ArraySubscriptExpr , Expr) EXPR(CallExpr , Expr) @@ -107,7 +108,7 @@ EXPR(GNUNullExpr , Expr) // C++ Expressions. EXPR(CXXOperatorCallExpr , CallExpr) EXPR(CXXMemberCallExpr , CallExpr) -EXPR(CXXNamedCastExpr , ExplicitCastExpr) +ABSTRACT_EXPR(CXXNamedCastExpr , ExplicitCastExpr) EXPR(CXXStaticCastExpr , CXXNamedCastExpr) EXPR(CXXDynamicCastExpr , CXXNamedCastExpr) EXPR(CXXReinterpretCastExpr , CXXNamedCastExpr) diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h index 3fd8f16..269aa4c 100644 --- a/include/clang/AST/StmtObjC.h +++ b/include/clang/AST/StmtObjC.h @@ -71,38 +71,31 @@ public: /// ObjCAtCatchStmt - This represents objective-c's @catch statement. class ObjCAtCatchStmt : public Stmt { private: - enum { BODY, NEXT_CATCH, END_EXPR }; - ParmVarDecl *ExceptionDecl; - Stmt *SubExprs[END_EXPR]; + VarDecl *ExceptionDecl; + Stmt *Body; SourceLocation AtCatchLoc, RParenLoc; public: ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, - ParmVarDecl *catchVarDecl, - Stmt *atCatchStmt, Stmt *atCatchList); + VarDecl *catchVarDecl, + Stmt *atCatchStmt) + : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl), + Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { } explicit ObjCAtCatchStmt(EmptyShell Empty) : Stmt(ObjCAtCatchStmtClass, Empty) { } - const Stmt *getCatchBody() const { return SubExprs[BODY]; } - Stmt *getCatchBody() { return SubExprs[BODY]; } - void setCatchBody(Stmt *S) { SubExprs[BODY] = S; } + const Stmt *getCatchBody() const { return Body; } + Stmt *getCatchBody() { return Body; } + void setCatchBody(Stmt *S) { Body = S; } - const ObjCAtCatchStmt *getNextCatchStmt() const { - return static_cast(SubExprs[NEXT_CATCH]); - } - ObjCAtCatchStmt *getNextCatchStmt() { - return static_cast(SubExprs[NEXT_CATCH]); - } - void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; } - - const ParmVarDecl *getCatchParamDecl() const { + const VarDecl *getCatchParamDecl() const { return ExceptionDecl; } - ParmVarDecl *getCatchParamDecl() { + VarDecl *getCatchParamDecl() { return ExceptionDecl; } - void setCatchParamDecl(ParmVarDecl *D) { ExceptionDecl = D; } + void setCatchParamDecl(VarDecl *D) { ExceptionDecl = D; } SourceLocation getAtCatchLoc() const { return AtCatchLoc; } void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } @@ -110,7 +103,7 @@ public: void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } virtual SourceRange getSourceRange() const { - return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd()); + return SourceRange(AtCatchLoc, Body->getLocEnd()); } bool hasEllipsis() const { return getCatchParamDecl() == 0; } @@ -160,50 +153,94 @@ public: /// @try ... @catch ... @finally statement. class ObjCAtTryStmt : public Stmt { private: - enum { TRY, CATCH, FINALLY, END_EXPR }; - Stmt* SubStmts[END_EXPR]; - + // The location of the SourceLocation AtTryLoc; -public: + + // The number of catch blocks in this statement. + unsigned NumCatchStmts : 16; + + // Whether this statement has a @finally statement. + bool HasFinally : 1; + + /// \brief Retrieve the statements that are stored after this @try statement. + /// + /// The order of the statements in memory follows the order in the source, + /// with the @try body first, followed by the @catch statements (if any) and, + /// finally, the @finally (if it exists). + Stmt **getStmts() { return reinterpret_cast (this + 1); } + const Stmt* const *getStmts() const { + return reinterpret_cast (this + 1); + } + ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, - Stmt *atCatchStmt, - Stmt *atFinallyStmt) - : Stmt(ObjCAtTryStmtClass) { - SubStmts[TRY] = atTryStmt; - SubStmts[CATCH] = atCatchStmt; - SubStmts[FINALLY] = atFinallyStmt; - AtTryLoc = atTryLoc; - } - explicit ObjCAtTryStmt(EmptyShell Empty) : - Stmt(ObjCAtTryStmtClass, Empty) { } + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + + explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts, + bool HasFinally) + : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts), + HasFinally(HasFinally) { } +public: + static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + static ObjCAtTryStmt *CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally); + + /// \brief Retrieve the location of the @ in the @try. SourceLocation getAtTryLoc() const { return AtTryLoc; } void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } - const Stmt *getTryBody() const { return SubStmts[TRY]; } - Stmt *getTryBody() { return SubStmts[TRY]; } - void setTryBody(Stmt *S) { SubStmts[TRY] = S; } - - const ObjCAtCatchStmt *getCatchStmts() const { - return dyn_cast_or_null(SubStmts[CATCH]); + /// \brief Retrieve the @try body. + const Stmt *getTryBody() const { return getStmts()[0]; } + Stmt *getTryBody() { return getStmts()[0]; } + void setTryBody(Stmt *S) { getStmts()[0] = S; } + + /// \brief Retrieve the number of @catch statements in this try-catch-finally + /// block. + unsigned getNumCatchStmts() const { return NumCatchStmts; } + + /// \brief Retrieve a @catch statement. + const ObjCAtCatchStmt *getCatchStmt(unsigned I) const { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null(getStmts()[I + 1]); } - ObjCAtCatchStmt *getCatchStmts() { - return dyn_cast_or_null(SubStmts[CATCH]); + + /// \brief Retrieve a @catch statement. + ObjCAtCatchStmt *getCatchStmt(unsigned I) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null(getStmts()[I + 1]); } - void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; } - + + /// \brief Set a particular catch statement. + void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + getStmts()[I + 1] = S; + } + + /// Retrieve the @finally statement, if any. const ObjCAtFinallyStmt *getFinallyStmt() const { - return dyn_cast_or_null(SubStmts[FINALLY]); + if (!HasFinally) + return 0; + + return cast_or_null(getStmts()[1 + NumCatchStmts]); } ObjCAtFinallyStmt *getFinallyStmt() { - return dyn_cast_or_null(SubStmts[FINALLY]); + if (!HasFinally) + return 0; + + return cast_or_null(getStmts()[1 + NumCatchStmts]); } - void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; } - - virtual SourceRange getSourceRange() const { - return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd()); + void setFinallyStmt(Stmt *S) { + assert(HasFinally && "@try does not have a @finally slot!"); + getStmts()[1 + NumCatchStmts] = S; } + virtual SourceRange getSourceRange() const; + static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCAtTryStmtClass; } diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index aafe963..f3de9fa 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -25,6 +25,7 @@ namespace llvm { namespace clang { class DependentTemplateName; +class DiagnosticBuilder; class IdentifierInfo; class NestedNameSpecifier; struct PrintingPolicy; @@ -173,6 +174,11 @@ public: } }; +/// Insertion operator for diagnostics. This allows sending TemplateName's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + TemplateName N); + /// \brief Represents a template name that was expressed as a /// qualified name. /// diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 7279365..030c74c 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -871,6 +871,7 @@ public: bool isRecordType() const; bool isClassType() const; bool isStructureType() const; + bool isStructureOrClassType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. @@ -922,6 +923,11 @@ public: const ObjCInterfaceType *getAsObjCQualifiedInterfaceType() const; const CXXRecordDecl *getCXXRecordDeclForPointerType() const; + /// \brief Retrieves the CXXRecordDecl that this type refers to, either + /// because the type is a RecordType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + CXXRecordDecl *getAsCXXRecordDecl() const; + // Member-template getAs'. This scheme will eventually // replace the specific getAsXXXX methods above. // @@ -2433,8 +2439,11 @@ public: class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { - // FIXME: Currently needed for profiling expressions; can we avoid this? - ASTContext &Context; + // The ASTContext is currently needed in order to profile expressions. + // FIXME: avoid this. + // + // The bool is whether this is a current instantiation. + llvm::PointerIntPair ContextAndCurrentInstantiation; /// \brief The name of the template being specialized. TemplateName Template; @@ -2445,6 +2454,7 @@ class TemplateSpecializationType TemplateSpecializationType(ASTContext &Context, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, QualType Canon); @@ -2476,6 +2486,12 @@ public: static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &, const PrintingPolicy &Policy); + /// True if this template specialization type matches a current + /// instantiation in the context in which it is found. + bool isCurrentInstantiation() const { + return ContextAndCurrentInstantiation.getInt(); + } + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } @@ -2496,15 +2512,20 @@ public: /// \precondition @c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; - bool isSugared() const { return !isDependentType(); } + bool isSugared() const { + return !isDependentType() || isCurrentInstantiation(); + } QualType desugar() const { return getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Template, getArgs(), NumArgs, Context); + Profile(ID, Template, isCurrentInstantiation(), getArgs(), NumArgs, + *ContextAndCurrentInstantiation.getPointer()); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - const TemplateArgument *Args, unsigned NumArgs, + bool IsCurrentInstantiation, + const TemplateArgument *Args, + unsigned NumArgs, ASTContext &Context); static bool classof(const Type *T) { @@ -2513,40 +2534,57 @@ public: static bool classof(const TemplateSpecializationType *T) { return true; } }; -/// \brief The injected class name of a C++ class template. Used to -/// record that a type was spelled with a bare identifier rather than -/// as a template-id; the equivalent for non-templated classes is just -/// RecordType. +/// \brief The injected class name of a C++ class template or class +/// template partial specialization. Used to record that a type was +/// spelled with a bare identifier rather than as a template-id; the +/// equivalent for non-templated classes is just RecordType. /// -/// For consistency, template instantiation turns these into RecordTypes. +/// Injected class name types are always dependent. Template +/// instantiation turns these into RecordTypes. /// -/// The desugared form is always a unqualified TemplateSpecializationType. -/// The canonical form is always either a TemplateSpecializationType -/// (when dependent) or a RecordType (otherwise). +/// Injected class name types are always canonical. This works +/// because it is impossible to compare an injected class name type +/// with the corresponding non-injected template type, for the same +/// reason that it is impossible to directly compare template +/// parameters from different dependent contexts: injected class name +/// types can only occur within the scope of a particular templated +/// declaration, and within that scope every template specialization +/// will canonicalize to the injected class name (when appropriate +/// according to the rules of the language). class InjectedClassNameType : public Type { CXXRecordDecl *Decl; - QualType UnderlyingType; + /// The template specialization which this type represents. + /// For example, in + /// template class A { ... }; + /// this is A, whereas in + /// template class A > { ... }; + /// this is A >. + /// + /// It is always unqualified, always a template specialization type, + /// and always dependent. + QualType InjectedType; friend class ASTContext; // ASTContext creates these. - InjectedClassNameType(CXXRecordDecl *D, QualType TST, QualType Canon) - : Type(InjectedClassName, Canon, Canon->isDependentType()), - Decl(D), UnderlyingType(TST) { + friend class TagDecl; // TagDecl mutilates the Decl + InjectedClassNameType(CXXRecordDecl *D, QualType TST) + : Type(InjectedClassName, QualType(), true), + Decl(D), InjectedType(TST) { assert(isa(TST)); assert(!TST.hasQualifiers()); - assert(TST->getCanonicalTypeInternal() == Canon); + assert(TST->isDependentType()); } public: - QualType getUnderlyingType() const { return UnderlyingType; } - const TemplateSpecializationType *getUnderlyingTST() const { - return cast(UnderlyingType.getTypePtr()); + QualType getInjectedSpecializationType() const { return InjectedType; } + const TemplateSpecializationType *getInjectedTST() const { + return cast(InjectedType.getTypePtr()); } CXXRecordDecl *getDecl() const { return Decl; } - bool isSugared() const { return true; } - QualType desugar() const { return UnderlyingType; } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == InjectedClassName; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 7e8b73c..c665073 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -91,7 +91,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) NON_CANONICAL_TYPE(QualifiedName, Type) -NON_CANONICAL_TYPE(InjectedClassName, Type) +DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) TYPE(ObjCInterface, Type) TYPE(ObjCObjectPointer, Type) @@ -105,6 +105,8 @@ LAST_TYPE(ObjCObjectPointer) #ifdef LEAF_TYPE LEAF_TYPE(Enum) LEAF_TYPE(Builtin) +LEAF_TYPE(Record) +LEAF_TYPE(InjectedClassName) LEAF_TYPE(ObjCInterface) LEAF_TYPE(TemplateTypeParm) #undef LEAF_TYPE diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h index 553f04d..cad7e61 100644 --- a/include/clang/AST/UnresolvedSet.h +++ b/include/clang/AST/UnresolvedSet.h @@ -17,56 +17,7 @@ #include #include "llvm/ADT/SmallVector.h" -#include "clang/Basic/Specifiers.h" - -namespace clang { - -class NamedDecl; - -/// A POD class for pairing a NamedDecl* with an access specifier. -/// Can be put into unions. -class DeclAccessPair { - NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial - - enum { Mask = 0x3 }; - -public: - static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { - DeclAccessPair p; - p.set(D, AS); - return p; - } - - NamedDecl *getDecl() const { - return (NamedDecl*) (~Mask & (uintptr_t) Ptr); - } - AccessSpecifier getAccess() const { - return AccessSpecifier(Mask & (uintptr_t) Ptr); - } - - void setDecl(NamedDecl *D) { - set(D, getAccess()); - } - void setAccess(AccessSpecifier AS) { - set(getDecl(), AS); - } - void set(NamedDecl *D, AccessSpecifier AS) { - Ptr = reinterpret_cast(uintptr_t(AS) | - reinterpret_cast(D)); - } - - operator NamedDecl*() const { return getDecl(); } - NamedDecl *operator->() const { return getDecl(); } -}; -} - -// Take a moment to tell SmallVector that this is POD. -namespace llvm { -template struct isPodLike; -template<> struct isPodLike { - static const bool value = true; -}; -} +#include "clang/AST/DeclAccessPair.h" namespace clang { diff --git a/include/clang/AST/UsuallyTinyPtrVector.h b/include/clang/AST/UsuallyTinyPtrVector.h new file mode 100644 index 0000000..5ee40e0 --- /dev/null +++ b/include/clang/AST/UsuallyTinyPtrVector.h @@ -0,0 +1,105 @@ +//===-- UsuallyTinyPtrVector.h - Pointer vector class -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the UsuallyTinyPtrVector class, which is a vector that +// optimizes the case where there is only one element. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H +#define LLVM_CLANG_AST_USUALLY_TINY_PTR_VECTOR_H + +#include + +namespace clang { + +/// \brief A vector class template that is optimized for storing a single +/// pointer element. +template +class UsuallyTinyPtrVector { + /// \brief Storage for the vector. + /// + /// When the low bit is zero, this is a T *. When the + /// low bit is one, this is a std::vector *. + mutable uintptr_t Storage; + + typedef std::vector vector_type; + +public: + UsuallyTinyPtrVector() : Storage(0) { } + explicit UsuallyTinyPtrVector(T *Element) + : Storage(reinterpret_cast(Element)) { } + + bool empty() const { return !Storage; } + + typedef const T **iterator; + iterator begin() const; + iterator end() const; + + void push_back(T *Method); + void Destroy(); +}; + +template +typename UsuallyTinyPtrVector::iterator +UsuallyTinyPtrVector::begin() const { + if ((Storage & 0x01) == 0) + return reinterpret_cast(&Storage); + + vector_type *Vec = reinterpret_cast(Storage & ~0x01); + return &Vec->front(); +} + + +template +typename UsuallyTinyPtrVector::iterator +UsuallyTinyPtrVector::end() const { + if ((Storage & 0x01) == 0) { + if (Storage == 0) + return reinterpret_cast(&Storage); + + return reinterpret_cast(&Storage) + 1; + } + + vector_type *Vec = reinterpret_cast(Storage & ~0x01); + return &Vec->front() + Vec->size(); +} + +template +void UsuallyTinyPtrVector::push_back(T *Element) { + if (Storage == 0) { + // 0 -> 1 element. + Storage = reinterpret_cast(Element); + return; + } + + vector_type *Vec; + if ((Storage & 0x01) == 0) { + // 1 -> 2 elements. Allocate a new vector and push the element into that + // vector. + Vec = new vector_type; + Vec->push_back(reinterpret_cast(Storage)); + Storage = reinterpret_cast(Vec) | 0x01; + } else + Vec = reinterpret_cast(Storage & ~0x01); + + // Add the new element to the vector. + Vec->push_back(Element); +} + +template +void UsuallyTinyPtrVector::Destroy() { + if (Storage & 0x01) + delete reinterpret_cast(Storage & ~0x01); + + Storage = 0; +} + +} +#endif diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h deleted file mode 100644 index a4e6d51..0000000 --- a/include/clang/Analysis/Support/Optional.h +++ /dev/null @@ -1,66 +0,0 @@ -//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides Optional, a template class modeled in the spirit of -// OCaml's 'opt' variant. The idea is to strongly type whether or not -// a value can be optional. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL -#define LLVM_CLANG_ANALYSIS_OPTIONAL - -namespace clang { - -template -class Optional { - T x; - unsigned hasVal : 1; -public: - explicit Optional() : x(), hasVal(false) {} - Optional(const T &y) : x(y), hasVal(true) {} - - static inline Optional create(const T* y) { - return y ? Optional(*y) : Optional(); - } - - Optional &operator=(const T &y) { - x = y; - hasVal = true; - return *this; - } - - const T* getPointer() const { assert(hasVal); return &x; } - const T& getValue() const { assert(hasVal); return x; } - - operator bool() const { return hasVal; } - bool hasValue() const { return hasVal; } - const T* operator->() const { return getPointer(); } - const T& operator*() const { assert(hasVal); return x; } -}; -} //end clang namespace - -namespace llvm { - -template struct simplify_type; - -template -struct simplify_type > { - typedef const T* SimpleType; - static SimpleType getSimplifiedValue(const ::clang::Optional &Val) { - return Val.getPointer(); - } -}; - -template -struct simplify_type< ::clang::Optional > - : public simplify_type > {}; -} // end llvm namespace - -#endif diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 453f660..b306954 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -314,6 +314,7 @@ BUILTIN(__builtin_setjmp, "iv**", "") BUILTIN(__builtin_longjmp, "vv**i", "r") BUILTIN(__builtin_unwind_init, "v", "") BUILTIN(__builtin_eh_return_data_regno, "ii", "nc") +BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:") BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") // GCC exception builtins @@ -335,6 +336,7 @@ BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF") BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF") BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF") BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF") BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:") BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:") BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:") @@ -346,12 +348,9 @@ BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") BUILTIN(__builtin_expect, "LiLiLi" , "nc") BUILTIN(__builtin_prefetch, "vvC*.", "nc") -BUILTIN(__builtin_abort, "v", "Fnr") BUILTIN(__builtin_trap, "v", "nr") BUILTIN(__builtin_unreachable, "v", "nr") - BUILTIN(__builtin_shufflevector, "v." , "nc") - BUILTIN(__builtin_alloca, "v*z" , "n") // "Overloaded" Atomic operator builtins. These are overloaded to support data @@ -473,6 +472,13 @@ BUILTIN(__sync_fetch_and_max, "ii*i", "n") BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n") BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n") +// Random libc builtins. +BUILTIN(__builtin_abort, "v", "Fnr") +BUILTIN(__builtin_index, "c*cC*i", "Fn") +BUILTIN(__builtin_rindex, "c*cC*i", "Fn") + + + // C99 library functions // C99 stdlib.h LIBBUILTIN(abort, "v", "fr", "stdlib.h") diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def index 817a032..287bba9 100644 --- a/include/clang/Basic/BuiltinsPPC.def +++ b/include/clang/Basic/BuiltinsPPC.def @@ -18,7 +18,97 @@ // The format of this database matches clang/Basic/Builtins.def. // This is just a placeholder, the types and attributes are wrong. -BUILTIN(__builtin_altivec_abs_v4sf , "ii" , "nc") +BUILTIN(__builtin_altivec_abs_v16qi, "V16UcV16Sc", "") +BUILTIN(__builtin_altivec_abs_v8hi, "V8UsV8Ss", "") +BUILTIN(__builtin_altivec_abs_v4si, "V4UiV4Si", "") + +BUILTIN(__builtin_altivec_abss_v16qi, "V16UcV16Sc", "") +BUILTIN(__builtin_altivec_abss_v8hi, "V8UsV8Ss", "") +BUILTIN(__builtin_altivec_abss_v4si, "V4UiV4Si", "") + +BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_stvx, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvxl, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvebx, "vV16civ*", "") +BUILTIN(__builtin_altivec_stvehx, "vV8siv*", "") +BUILTIN(__builtin_altivec_stvewx, "vV4iiv*", "") + +BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mfvscr, "V8Us", "") + +BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mtvscr, "vV4i", "") + +BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") + // FIXME: Obviously incomplete. #undef BUILTIN diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 5c75d37..a878dd1 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -245,7 +245,7 @@ BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cc", "") -BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLic", "") +BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cc", "") BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 57dd696..bf94af6 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -188,6 +188,9 @@ private: bool ErrorsAsFatal; // Treat errors like fatal errors. bool SuppressSystemWarnings; // Suppress warnings in system headers. bool SuppressAllDiagnostics; // Suppress all diagnostics. + unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. + unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, + // 0 -> no limit. ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? DiagnosticClient *Client; @@ -211,9 +214,10 @@ private: /// diagnostic that they follow. Diagnostic::Level LastDiagLevel; - unsigned NumDiagnostics; // Number of diagnostics reported - unsigned NumErrors; // Number of diagnostics that are errors - + unsigned NumWarnings; // Number of warnings reported + unsigned NumErrors; // Number of errors reported + unsigned NumErrorsSuppressed; // Number of errors suppressed + /// CustomDiagInfo - Information for uniquing and looking up custom diags. diag::CustomDiagInfo *CustomDiagInfo; @@ -270,6 +274,22 @@ public: void setClient(DiagnosticClient* client) { Client = client; } + /// setErrorLimit - Specify a limit for the number of errors we should + /// emit before giving up. Zero disables the limit. + void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; } + + /// \brief Specify the maximum number of template instantiation + /// notes to emit along with a given diagnostic. + void setTemplateBacktraceLimit(unsigned Limit) { + TemplateBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of template instantiation + /// nodes to emit along with a given diagnostic. + unsigned getTemplateBacktraceLimit() const { + return TemplateBacktraceLimit; + } + /// setIgnoreAllWarnings - When set to true, any unmapped warnings are /// ignored. If this and WarningsAsErrors are both set, then this one wins. void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } @@ -324,8 +344,9 @@ public: void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { assert(Diag < diag::DIAG_UPPER_LIMIT && "Can only map builtin diagnostics"); - assert((isBuiltinWarningOrExtension(Diag) || Map == diag::MAP_FATAL) && - "Cannot map errors!"); + assert((isBuiltinWarningOrExtension(Diag) || + (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) && + "Cannot map errors into warnings!"); setDiagnosticMappingInternal(Diag, Map, true); } @@ -338,7 +359,8 @@ public: bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } unsigned getNumErrors() const { return NumErrors; } - unsigned getNumDiagnostics() const { return NumDiagnostics; } + unsigned getNumErrorsSuppressed() const { return NumErrorsSuppressed; } + unsigned getNumWarnings() const { return NumWarnings; } /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is @@ -383,7 +405,18 @@ public: /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic /// ID is for an extension of some sort. /// - static bool isBuiltinExtensionDiag(unsigned DiagID); + static bool isBuiltinExtensionDiag(unsigned DiagID) { + bool ignored; + return isBuiltinExtensionDiag(DiagID, ignored); + } + + /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic + /// ID is for an extension of some sort. This also returns EnabledByDefault, + /// which is set to indicate whether the diagnostic is ignored by default (in + /// which case -pedantic enables it) or treated as a warning/error by default. + /// + static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); + /// getWarningOptionForDiag - Return the lowest-level warning option that /// enables the specified diagnostic. If there is no -Wfoo flag that controls @@ -473,7 +506,7 @@ private: /// getDiagnosticMappingInfo - Return the mapping info currently set for the /// specified builtin diagnostic. This returns the high bit encoding, or zero /// if the field is completely uninitialized. - unsigned getDiagnosticMappingInfo(diag::kind Diag) const { + diag::Mapping getDiagnosticMappingInfo(diag::kind Diag) const { const DiagMappings ¤tMappings = DiagMappingsStack.back(); return (diag::Mapping)((currentMappings[Diag/2] >> (Diag & 1)*4) & 15); } diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 8e791c3..88e7dc1 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -13,6 +13,11 @@ let Component = "Common" in { +// Basic. + +def fatal_too_many_errors + : Error<"too many errors emitted, stopping now">, DefaultFatal; + def note_previous_definition : Note<"previous definition is here">; def note_previous_declaration : Note<"previous declaration is here">; def note_previous_implicit_declaration : Note< @@ -36,7 +41,7 @@ def err_expected_colon_after_setter_name : Error< "must end with ':'">; // Parse && Sema -def err_no_declarators : Error<"declaration does not declare anything">; +def ext_no_declarators : ExtWarn<"declaration does not declare anything">; def err_param_redefinition : Error<"redefinition of parameter %0">; def err_invalid_storage_class_in_func_decl : Error< "invalid storage class specifier in function declarator">; @@ -67,5 +72,6 @@ def err_target_invalid_feature : Error<"invalid target feature '%0'">; def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; def err_file_modified : Error< "file '%0' modified since it was first processed">, DefaultFatal; - +def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but " + "encoding is not supported">, DefaultFatal; } diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 3dbe47f..3b7272e 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -94,5 +94,7 @@ def warn_drv_conflicting_deployment_targets : Warning< def warn_drv_treating_input_as_cxx : Warning< "treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">, InGroup; +def warn_drv_objc_gc_unsupported : Warning< + "Objective-C garbage collection is not supported on this platform, ignoring '%0'">; } diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 2e0b4ba..b731030 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -14,7 +14,10 @@ def err_fe_error_reading : Error<"error reading '%0'">; def err_fe_error_reading_stdin : Error<"error reading stdin">; def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; -def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; +def err_fe_invalid_ast_action : Error<"invalid action for AST input">, + DefaultFatal; +def err_fe_inline_asm : Error<"%0">; // Error generated by the backend. +def note_fe_inline_asm_here : Note<"generated from here">; def err_fe_invalid_code_complete_file : Error< "cannot locate code-completion file %0">, DefaultFatal; def err_fe_stdout_binary : Error<"unable to change standard output to binary">, @@ -69,12 +72,12 @@ def err_fe_pth_file_has_no_source_header : Error< def warn_fe_macro_contains_embedded_newline : Warning< "macro '%0' contains embedded newline, text after the newline is ignored.">; -def err_verify_bogus_characters : Error< - "bogus characters before '{{' in expected string">; def err_verify_missing_start : Error< - "cannot find start ('{{') of expected string">; + "cannot find start ('{{') of expected %0">; def err_verify_missing_end : Error< - "cannot find end ('}}') of expected string">; + "cannot find end ('}}') of expected %0">; +def err_verify_invalid_content : Error< + "invalid expected %0: %1">; def err_verify_inconsistent_diags : Error< "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: %2">; @@ -120,12 +123,18 @@ def warn_pch_nonfragile_abi2 : Error< "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 " "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 " "Objective-C ABI is selected">; +def warn_pch_no_constant_cfstrings : Error< + "Objctive-C NSstring generation support was %select{disabled|enabled}0 " + "in PCH file but currently %select{disabled|enabled}1">; def warn_pch_extensions : Error< "extensions were %select{enabled|disabled}0 in PCH file but are " "currently %select{enabled|disabled}1">; def warn_pch_gnu_extensions : Error< "GNU extensions were %select{disabled|enabled}0 in PCH file but are " "currently %select{disabled|enabled}1">; +def warn_pch_gnu_keywords : Error< + "GNU keywords were %select{disabled|enabled}0 in PCH file but are " + "currently %select{disabled|enabled}1">; def warn_pch_microsoft_extensions : Error< "Microsoft extensions were %select{disabled|enabled}0 in PCH file but are " "currently %select{disabled|enabled}1">; diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index b0c016b..c74a48c 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -108,6 +108,7 @@ def : DiagGroup<"type-limits">; def Uninitialized : DiagGroup<"uninitialized">; def UnknownPragmas : DiagGroup<"unknown-pragmas">; def UnusedArgument : DiagGroup<"unused-argument">; +def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">; def UnusedFunction : DiagGroup<"unused-function">; def UnusedLabel : DiagGroup<"unused-label">; def UnusedParameter : DiagGroup<"unused-parameter">; @@ -138,7 +139,8 @@ def Conversion : DiagGroup<"conversion", def Unused : DiagGroup<"unused", [UnusedArgument, UnusedFunction, UnusedLabel, - UnusedParameter, UnusedValue, UnusedVariable]>; + // UnusedParameter, (matches GCC's behavior) + UnusedValue, UnusedVariable]>; // Format settings. def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull]>; @@ -156,23 +158,22 @@ def Extra : DiagGroup<"extra", [ ]>; def Most : DiagGroup<"most", [ + CharSubscript, Comment, Format, Implicit, MismatchedTags, MissingBraces, MultiChar, + Reorder, ReturnType, Switch, Trigraphs, Uninitialized, UnknownPragmas, - UnusedValue, - UnusedVariable, + Unused, VectorConversions, - VolatileRegisterVar, - Reorder, - CharSubscript + VolatileRegisterVar ]>; // -Wall is -Wmost -Wparentheses diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 3e0956f..2795851 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -190,7 +190,9 @@ def err_objc_missing_end : Error<"missing @end">; def warn_objc_protocol_qualifier_missing_id : Warning< "protocol qualifiers without 'id' is archaic">; def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; - +def err_illegal_super_cast : Error< + "cannot cast 'super' (it isn't an expression)">; + def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b66d6cc..93ab858 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -85,6 +85,8 @@ def warn_unused_parameter : Warning<"unused parameter %0">, InGroup, DefaultIgnore; def warn_unused_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; +def warn_unused_exception_param : Warning<"unused exception parameter %0">, + InGroup, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">; def err_array_star_in_function_definition : Error< @@ -215,7 +217,8 @@ def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">; def err_statically_allocated_object : Error< "interface type cannot be statically allocated">; def err_object_cannot_be_passed_returned_by_value : Error< - "interface type %1 cannot be %select{returned|passed}0 by value">; + "interface type %1 cannot be %select{returned|passed}0 by value" + "; did you forget * in %1">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">; @@ -237,6 +240,8 @@ def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; def err_undef_superclass : Error< "cannot find interface declaration for %0, superclass of %1">; +def err_no_nsconstant_string_class : Error< + "cannot find interface declaration for %0">; def err_recursive_superclass : Error< "trying to recursively use %0 as superclass of %1">; def warn_previous_alias_decl : Warning<"previously declared alias is ignored">; @@ -296,7 +301,7 @@ def warn_implements_nscopying : Warning< def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; -def note_declared_at : Note<"declared at">; +def note_declared_at : Note<"declared here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_missing_atend : Warning<"'@end' is missing in implementation context">; @@ -322,8 +327,8 @@ def warn_atomic_property_rule : Warning< "writable atomic property %0 cannot pair a synthesized setter/getter " "with a user defined setter/getter">; def err_use_continuation_class : Error< - "property declaration in continuation class of %0 is to change a 'readonly' " - "property to 'readwrite'">; + "illegal declaration of property in continuation class %0" + ": attribute must be readwrite, while its primary must be readonly">; def err_continuation_class : Error<"continuation class has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< @@ -381,11 +386,13 @@ def err_static_assert_failed : Error<"static_assert failed \"%0\"">; def err_unexpected_friend : Error< "friends can only be classes or functions">; -def err_enum_friend : Error< - "enum types cannot be friends">; +def ext_enum_friend : ExtWarn< + "enumeration type %0 cannot be a friend">; +def ext_nonclass_type_friend : ExtWarn< + "non-class type %0 cannot be a friend">; def err_friend_is_member : Error< "friends cannot be members of the declaring class">; -def err_unelaborated_friend_type : Error< +def ext_unelaborated_friend_type : ExtWarn< "must specify '%select{struct|union|class|enum}0' to befriend %1">; def err_qualified_friend_not_found : Error< "no function named %0 with type %1 was found in the specified scope">; @@ -399,6 +406,9 @@ def err_abstract_type_in_decl : Error< "%select{return|parameter|variable|field}0 type %1 is an abstract class">; def err_allocation_of_abstract_type : Error< "allocation of an object of abstract type %0">; +def err_throw_abstract_type : Error< + "cannot throw an object of abstract type %0">; +def err_array_of_abstract_type : Error<"array of abstract class type %0">; def err_multiple_final_overriders : Error< "virtual function %q0 has more than one final overrider in %1">; @@ -448,11 +458,20 @@ def warn_missing_exception_specification : Warning< // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; -def err_access : - Error<"%1 is a %select{private|protected}0 member of %3">, - NoSFINAE; -def err_access_ctor : - Error<"calling a %select{private|protected}0 constructor of class %2">, +def err_access : Error< + "%1 is a %select{private|protected}0 member of %3">, NoSFINAE; +def err_access_ctor : Error< + "calling a %select{private|protected}0 constructor of class %2">, NoSFINAE; +def err_access_base : Error< + "%select{base class|inherited virtual base class}0 %1 has %select{private|" + "protected}3 %select{constructor|copy constructor|copy assignment operator|" + "destructor}2">, NoSFINAE; +def err_access_field: Error< + "field of type %0 has %select{private|protected}2 %select{constructor|copy " + "constructor|copy assignment operator|destructor}1">, NoSFINAE; + +def err_access_ctor_field : + Error<"field of type %1 has %select{private|protected}2 constructor">, NoSFINAE; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, @@ -461,6 +480,9 @@ def err_access_dtor_vbase : Error<"inherited virtual base class %0 has " "%select{private|protected}1 destructor">, NoSFINAE; +def err_access_dtor_temp : + Error<"temporary of type %0 has %select{private|protected}1 destructor">, + NoSFINAE; def err_access_dtor_field : Error<"field of type %1 has %select{private|protected}2 destructor">, NoSFINAE; @@ -494,6 +516,9 @@ def note_access_constrained_by_path : Note< // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; +def err_dependent_nested_name_spec : Error< + "nested name specifier for a declaration cannot depend on a template " + "parameter">; def err_nested_name_member_ref_lookup_ambiguous : Error< "lookup of %0 in member access expression is ambiguous">; def note_ambig_member_ref_object_type : Note< @@ -542,6 +567,8 @@ def err_non_virtual_pure : Error< def err_implicit_object_parameter_init : Error< "cannot initialize object parameter of type %0 with an expression " "of type %1">; +def err_qualified_member_of_unrelated : Error< + "%q0 is not a member of class %1">; def note_field_decl : Note<"member is declared here">; def note_ivar_decl : Note<"ivar is declared here">; @@ -592,6 +619,7 @@ def err_covariant_return_type_class_type_more_qualified : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (class type %1 is more qualified than class " "type %2">; + // C++ constructors def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; def err_invalid_qualified_constructor : Error< @@ -601,6 +629,11 @@ def err_constructor_return_type : Error< def err_constructor_redeclared : Error<"constructor cannot be redeclared">; def err_constructor_byvalue_arg : Error< "copy constructor must pass its first argument by reference">; +def warn_no_constructor_for_refconst : Warning< + "%select{struct|union|class|enum}0 %1 does not declare any constructor to " + "initialize its non-modifiable members">; +def note_refconst_member_not_initialized : Note< + "%select{const|reference}0 member %1 will never be initialized">; // C++ destructors def err_destructor_not_member : Error< @@ -678,18 +711,23 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup>; def err_temp_copy_no_viable : Error< - "no viable copy constructor %select{copying variable|copying parameter|" + "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " - "element}0 of type %1">; + "element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element}0 of type %1">; def err_temp_copy_ambiguous : Error< - "ambiguous copy constructor call when %select{copying variable|copying " + "ambiguous constructor call when %select{copying variable|copying " "parameter|returning object|throwing object|copying member subobject|copying " - "array element}0 of type %1">; + "array element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element}0 of type %1">; def err_temp_copy_deleted : Error< "%select{copying variable|copying parameter|returning object|throwing " - "object|copying member subobject|copying array element}0 of type %1 invokes " - "deleted copy constructor">; - + "object|copying member subobject|copying array element|allocating object|" + "copying temporary|initializing base subobject|initializing vector element}0 " + "of type %1 invokes deleted constructor">; +def err_temp_copy_incomplete : Error< + "copying a temporary object of incomplete type %0">; + // C++0x decltype def err_cannot_determine_declared_type_of_overloaded_function : Error< "cannot determine the %select{type|declared type}0 of an overloaded " @@ -1116,9 +1154,13 @@ def err_member_call_without_object : Error< "call to non-static member function without an object argument">; // C++ Address of Overloaded Function +def err_addr_ovl_no_viable : Error< + "address of overloaded function %0 does not match required type %1">; def err_addr_ovl_ambiguous : Error< "address of overloaded function %0 is ambiguous">; - +def err_addr_ovl_not_func_ptrref : Error< + "address of overloaded function %0 cannot be converted to type %1">; + // C++ Template Declarations def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; @@ -1178,6 +1220,8 @@ def err_template_decl_ref : Error< "cannot refer to class template %0 without a template argument list">; // C++ Template Argument Lists +def err_template_missing_args : Error< + "use of class template %0 requires template arguments">; def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " "%select{class template|function template|template template parameter" @@ -1231,9 +1275,6 @@ def err_template_arg_no_ref_bind : Error< def err_template_arg_ref_bind_ignores_quals : Error< "reference binding of non-type template parameter of type %0 to template " "argument of type %1 ignores qualifiers">; -def err_template_arg_unresolved_overloaded_function : Error< - "overloaded function cannot be resolved to a non-type template parameter of " - "type %0">; def err_template_arg_not_decl_ref : Error< "non-type template argument does not refer to any declaration">; def err_template_arg_not_object_or_func_form : Error< @@ -1414,7 +1455,10 @@ def note_prior_template_arg_substitution : Note< " template parameter%1 %2">; def note_template_default_arg_checking : Note< "while checking a default template argument used here">; - +def note_instantiation_contexts_suppressed : Note< + "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " + "see all)">; + def err_field_instantiates_to_function : Error< "data member instantiated with function type %0">; def err_nested_name_spec_non_tag : Error< @@ -1551,6 +1595,14 @@ def err_redefinition_different_kind : Error< "redefinition of %0 as different kind of symbol">; def err_redefinition_different_typedef : Error< "typedef redefinition with different types (%0 vs %1)">; +def err_tag_reference_non_tag : Error< + "elaborated type refers to %select{a non-tag type|a typedef|a template}0">; +def err_tag_reference_conflict : Error< + "implicit declaration introduced by elaborated type conflicts with " + "%select{a declaration|a typedef|a template}0 of the same name">; +def err_dependent_tag_decl : Error< + "%select{declaration|definition}0 of %select{struct|union|class|enum}1 " + "in a dependent scope">; def err_tag_definition_of_typedef : Error< "definition of type %0 conflicts with typedef of the same name">; def err_conflicting_types : Error<"conflicting types for %0">; @@ -1641,6 +1693,8 @@ def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; def err_illegal_initializer : Error< "illegal initializer (only variables can be initialized)">; def err_illegal_initializer_type : Error<"illegal initializer type %0">; +def err_init_objc_class : Error< + "cannot initialize Objective-C class type %0">; def err_implicit_empty_initializer : Error< "initializer for aggregate with no elements requires explicit braces">; def err_bitfield_has_negative_width : Error< @@ -1649,9 +1703,18 @@ def err_anon_bitfield_has_negative_width : Error< "anonymous bit-field has negative width (%0)">; def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; def err_bitfield_width_exceeds_type_size : Error< - "size of bit-field %0 exceeds size of its type (%1 bits)">; + "size of bit-field %0 (%1 bits) exceeds size of its type (%2 bits)">; def err_anon_bitfield_width_exceeds_type_size : Error< - "size of anonymous bit-field exceeds size of its type (%0 bits)">; + "size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">; + +// Used by C++ which allows bit-fields that are wider than the type. +def warn_bitfield_width_exceeds_type_size: Warning< + "size of bit-field %0 (%1 bits) exceeds the size of its type; value will be " + "truncated to %2 bits">; +def warn_anon_bitfield_width_exceeds_type_size : Warning< + "size of anonymous bit-field (%0 bits) exceeds size of its type; value will " + "be truncated to %1 bits">; + def warn_missing_braces : Warning< "suggest braces around initialization of subobject">, InGroup>, DefaultIgnore; @@ -1758,6 +1821,7 @@ def ext_offsetof_extended_field_designator : Extension< "using extended field designator is an extension">; def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, InGroup; +def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, @@ -1773,6 +1837,8 @@ def warn_precedence_bitwise_rel : Warning< InGroup; def note_precedence_bitwise_first : Note< "place parentheses around the %0 expression to evaluate it first">; +def note_precedence_bitwise_silence : Note< + "place parentheses around the %0 expression to silence this warning">; def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " @@ -1807,9 +1873,9 @@ def err_typecheck_member_reference_arrow : Error< def err_typecheck_member_reference_suggestion : Error< "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">; def err_typecheck_member_reference_type : Error< - "cannot refer to type member %0 with '%select{.|->}1'">; + "cannot refer to type member %0 in %1 with '%select{.|->}2'">; def err_typecheck_member_reference_unknown : Error< - "cannot refer to member %0 with '%select{.|->}1'">; + "cannot refer to member %0 in %1 with '%select{.|->}2'">; def err_member_reference_needs_call : Error< "base of member reference has function type %0; perhaps you meant to call " "this function with '()'?">; @@ -1835,6 +1901,8 @@ def err_out_of_line_declaration : Error< def note_member_def_close_match : Note<"member declaration nearly matches">; def err_typecheck_ivar_variable_size : Error< "instance variables must have a constant size">; +def err_ivar_reference_type : Error< + "instance variables cannot be of reference type">; def err_typecheck_illegal_increment_decrement : Error< "cannot %select{decrement|increment}1 value of type %0">; def err_typecheck_arithmetic_incomplete_type : Error< @@ -2003,10 +2071,16 @@ def error_no_super_class : Error< "no super class declared in @interface for %0">; def err_invalid_receiver_to_message : Error< "invalid receiver to message expression">; +def err_invalid_receiver_to_message_super : Error< + "'super' is only valid in a method body">; +def err_invalid_receiver_class_message : Error< + "receiver type %0 is not an Objective-C class">; def warn_bad_receiver_type : Warning< "receiver type %0 is not 'id' or interface pointer, consider " "casting it to 'id'">; def err_bad_receiver_type : Error<"bad receiver type %0">; +def err_unknown_receiver_suggest : Error< + "unknown receiver %0; did you mean %1?">; def error_objc_throw_expects_object : Error< "@throw requires an Objective-C object type (%0 invalid)">; def error_objc_synchronized_expects_object : Error< @@ -2019,8 +2093,15 @@ def err_catch_param_not_objc_type : Error< "@catch parameter is not a pointer to an interface type">; def err_illegal_qualifiers_on_catch_parm : Error< "illegal qualifiers on @catch parameter">; -def err_illegal_super_cast : Error< - "cannot cast 'super' (it isn't an expression)">; +def err_storage_spec_on_catch_parm : Error< + "@catch parameter cannot have storage specifier %select{|'typedef'|'extern'|" + "'static'|'auto'|'register'|'__private_extern__'|'mutable'}0">; +def warn_register_objc_catch_parm : Warning< + "'register' storage specifier on @catch parameter will be ignored">; +def err_qualified_objc_catch_parm : Error< + "@catch parameter declarator cannot be qualified">; + + def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " "use @synthesize, @dynamic or provide a method implementation">; @@ -2029,7 +2110,10 @@ def warn_setter_getter_impl_required_in_category : Warning< "use @dynamic or provide a method implementation in category">; def note_property_impl_required : Note< "implementation is here">; - +def note_parameter_named_here : Note< + "passing argument to parameter %0 here">; +def note_parameter_here : Note< + "passing argument to parameter here">; // C++ casts // These messages adhere to the TryCast pattern: %0 is an int specifying the @@ -2099,6 +2183,8 @@ def err_new_incomplete_type : Error< "allocation of incomplete type %0">; def err_new_array_nonconst : Error< "only the first dimension of an allocated array may have dynamic size">; +def err_new_array_init_args : Error< + "array 'new' cannot have initialization arguments">; def err_new_paren_array_nonconst : Error< "when type is in parentheses, array cannot have dynamic size">; def err_placement_new_non_placement_delete : Error< @@ -2116,8 +2202,8 @@ def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behaviour">; def err_no_suitable_delete_member_function_found : Error< "no suitable member %0 in %1">; -def note_delete_member_function_declared_here : Note< - "%0 declared here">; +def note_member_declared_here : Note< + "member %0 declared here">; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated">, InGroup; @@ -2132,6 +2218,8 @@ def err_qualified_catch_declarator : Error< def err_early_catch_all : Error<"catch-all handler must come last">; def err_bad_memptr_rhs : Error< "right hand operand to %0 has non pointer-to-member type %1">; +def err_memptr_rhs_to_incomplete : Error< + "cannot dereference pointer into incomplete class type %0">; def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; @@ -2190,6 +2278,8 @@ def err_typecheck_deleted_function : Error< "conversion function from %0 to %1 invokes a deleted function">; def err_expected_class_or_namespace : Error<"expected a class or namespace">; +def err_missing_qualified_for_redecl : Error< + "must qualify the name %0 to declare %q1 in this scope">; def err_invalid_declarator_scope : Error< "definition or redeclaration of %0 not in a namespace enclosing %1">; def err_invalid_declarator_global_scope : Error< @@ -2213,6 +2303,8 @@ def warn_condition_is_idiomatic_assignment : Warning<"using the result " InGroup>, DefaultIgnore; def note_condition_assign_to_comparison : Note< "use '==' to turn this assignment into an equality comparison">; +def note_condition_assign_silence : Note< + "place parentheses around the assignment to silence this warning">; def warn_value_always_zero : Warning< "%0 is always %select{zero|false|NULL}1 in this context">; @@ -2221,53 +2313,91 @@ def warn_value_always_zero : Warning< // In most of these diagnostics the %2 is a value from the // Sema::AssignmentAction enumeration def err_typecheck_convert_incompatible : Error< - "incompatible type %select{assigning|passing|returning|converting|initializing|sending|casting}2" - " %1, expected %0">; -def err_typecheck_convert_ambiguous : Error< - "ambiguity in initializing value of type %0 with initializer of type %1">; -def err_cannot_initialize_decl_noname : Error< - "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 " - "of type %2">; -def err_cannot_initialize_decl : Error< - "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from incompatible type|to parameter of incompatible type|" + "from a function with incompatible result type|to incompatible type|" + "with an expression of incompatible type|to parameter of incompatible type|" + "to incompatible type}2 %1">; def warn_incompatible_qualified_id : Warning< - "incompatible type %select{assigning|passing|returning|converting|initializing|sending|casting}2" - " %1, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from incompatible type|to parameter of incompatible type|" + "from a function with incompatible result type|to incompatible type|" + "with an expression of incompatible type|to parameter of incompatible type|" + "to incompatible type}2 %1">; def ext_typecheck_convert_pointer_int : ExtWarn< "incompatible pointer to integer conversion " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; def ext_typecheck_convert_int_pointer : ExtWarn< "incompatible integer to pointer conversion " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; def ext_typecheck_convert_pointer_void_func : Extension< - "%select{assigning|passing|returning|converting|initializing|sending|casting}2" - " %1 converts between void* and function pointer, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 " + "converts between void pointer and function pointer">; def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< - "pointer types point to integer types with different sign " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">, + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 " + "converts between pointers to integer types with different sign">, InGroup>; def ext_typecheck_convert_incompatible_pointer : ExtWarn< "incompatible pointer types " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; def ext_typecheck_convert_discards_qualifiers : ExtWarn< - "%select{assigning|passing|returning|converting|initializing|sending|casting}2" - " %1 discards qualifiers, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 discards " + "qualifiers">; def ext_nested_pointer_qualifier_mismatch : ExtWarn< - "%select{assigning|passing|returning|converting|initializing|sending|casting}2," - " %0 and %1 have different qualifiers in nested pointer types">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 discards " + "qualifiers in nested pointer types">; def warn_incompatible_vectors : Warning< - "incompatible vector types %select{assigning|passing|returning|converting|initializing|sending|casting}2" - " %1, expected %0">, + "incompatible vector types " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">, InGroup, DefaultIgnore; def err_int_to_block_pointer : Error< - "invalid conversion " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2" - " integer %1, expected block pointer %0">; -def err_typecheck_comparison_of_distinct_blocks : Error< - "comparison of distinct block types (%0 and %1)">; + "invalid block pointer conversion " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; def err_typecheck_convert_incompatible_block_pointer : Error< "incompatible block pointer types " - "%select{assigning|passing|returning|converting|initializing|sending|casting}2 %1, expected %0">; + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; + +def err_typecheck_convert_ambiguous : Error< + "ambiguity in initializing value of type %0 with initializer of type %1">; +def err_cannot_initialize_decl_noname : Error< + "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 " + "of type %2">; +def err_cannot_initialize_decl : Error< + "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2">; +def err_typecheck_comparison_of_distinct_blocks : Error< + "comparison of distinct block types (%0 and %1)">; def err_typecheck_array_not_modifiable_lvalue : Error< "array type %0 is not assignable">; @@ -2295,9 +2425,17 @@ def note_function_with_incomplete_return_type_declared_here : Note< def err_call_incomplete_argument : Error< "argument type %0 is incomplete">; def err_typecheck_call_too_few_args : Error< - "too few arguments to %select{function|block|method}0 call">; + "too few arguments to %select{function|block|method}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_few_args_at_least : Error< + "too few arguments to %select{function|block|method}0 call, " + "expected at least %1, have %2">; def err_typecheck_call_too_many_args : Error< - "too many arguments to %select{function|block|method}0 call">; + "too many arguments to %select{function|block|method}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_many_args_at_most : Error< + "too many arguments to %select{function|block|method}0 call, " + "expected at most %1, have %2">; def warn_call_wrong_number_of_arguments : Warning< "too %select{few|many}0 arguments in call to %1">; def err_atomic_builtin_must_be_pointer : Error< @@ -2359,8 +2497,11 @@ def ext_typecheck_expression_not_constant_but_accepted : Extension< InGroup; def warn_unused_expr : Warning<"expression result unused">, InGroup; +def warn_unused_voidptr : Warning< + "expression result unused; should this cast be to 'void'?">, + InGroup; def warn_unused_property_expr : Warning< - "property access result unused - getters should not have side effects">, + "property access result unused - getters should not be used for side effects">, InGroup; def warn_unused_call : Warning< "ignoring return value of function declared with %0 attribute">, @@ -2412,24 +2553,21 @@ def err_overload_incorrect_fntype : Error< def err_only_constructors_take_base_inits : Error< "only constructors take base initializers">; -def error_multiple_mem_initialization : Error < - "multiple initializations given for non-static member '%0'">; - -def error_multiple_base_initialization : Error < +def err_multiple_mem_initialization : Error < + "multiple initializations given for non-static member %0">; +def err_multiple_mem_union_initialization : Error < + "initializing multiple members of anonymous union">; +def err_multiple_base_initialization : Error < "multiple initializations given for base %0">; def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; -def warn_field_initialized : Warning< - "member '%0' will be initialized after">, - InGroup, DefaultIgnore; -def warn_base_initialized : Warning< - "base class %0 will be initialized after">, +def warn_initializer_out_of_order : Warning< + "%select{field|base class}0 %1 will be initialized after " + "%select{field|base}2 %3">, InGroup, DefaultIgnore; -def note_fieldorbase_initialized_here : Note< - "%select{field|base}0 %1">; def err_base_init_does_not_name_class : Error< "constructor initializer %0 does not name a class">; @@ -2437,9 +2575,7 @@ def err_base_init_direct_and_virtual : Error< "base class initializer %0 names both a direct base class and an " "inherited virtual base class">; def err_not_direct_base_or_virtual : Error< - "type %0 is not a direct or virtual base of '%1'">; -def err_not_direct_base_or_virtual_multi : Error< - "type %0 is not a direct or virtual base of '%1'">; + "type %0 is not a direct or virtual base of %1">; def err_in_class_initializer_non_integral_type : Error< "in-class initializer has non-integral, non-enumeration type %0">; @@ -2587,6 +2723,8 @@ def err_conv_function_to_array : Error< "conversion function cannot convert to an array type">; def err_conv_function_to_function : Error< "conversion function cannot convert to a function type">; +def err_conv_function_with_complex_decl : Error< + "must use a typedef to declare a conversion to %0">; def err_conv_function_redeclared : Error< "conversion function cannot be redeclared">; def warn_conv_to_self_not_used : Warning< @@ -2669,7 +2807,7 @@ def warn_selfcomparison : Warning< "self-comparison always results in a constant value">; def warn_stringcompare : Warning< "result of comparison against %select{a string literal|@encode}0 is " - "unspecified (use strcmp instead)">; + "unspecified (use strncmp instead)">; @@ -2698,7 +2836,7 @@ def err_default_not_in_switch : Error< "'default' statement not in switch statement">; def err_case_not_in_switch : Error<"'case' statement not in switch statement">; def warn_bool_switch_condition : Warning< - "switch condition is a bool">; + "switch condition has boolean value">; def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">, InGroup>; @@ -2770,22 +2908,15 @@ def err_vector_incorrect_num_initializers : Error< "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; def err_altivec_empty_initializer : Error<"expected initializer">; -def err_stack_const_level : Error< - "level argument for a stack address builtin must be constant">; - -def err_prefetch_invalid_arg_type : Error< - "argument to __builtin_prefetch must be of integer type">; -def err_prefetch_invalid_arg_ice : Error< - "argument to __builtin_prefetch must be a constant integer">; def err_argument_invalid_range : Error< "argument should be a value from %0 to %1">; -def err_object_size_invalid_argument : Error< - "argument to __builtin_object_size must be a constant integer">; - def err_builtin_longjmp_invalid_val : Error< "argument to __builtin_longjmp must be a constant 1">; +def err_constant_integer_arg_type : Error< + "argument to %0 must be a constant integer">; + def ext_mixed_decls_code : Extension< "ISO C90 forbids mixing declarations and code">; def err_non_variable_decl_in_for : Error< @@ -2834,9 +2965,9 @@ def warn_ivar_use_hidden : Warning< def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; def error_private_ivar_access : Error<"instance variable %0 is private">, - NoSFINAE; + NoSFINAE; def error_protected_ivar_access : Error<"instance variable %0 is protected">, - NoSFINAE; + NoSFINAE; def warn_maynot_respond : Warning<"%0 may not respond to %1">; def warn_attribute_method_def : Warning< "method attribute can only be specified on method declarations">; diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index fdf69d0..1ed86f1 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -28,6 +28,7 @@ public: unsigned DollarIdents : 1; // '$' allowed in identifiers. unsigned AsmPreprocessor : 1; // Preprocessor in asm mode. unsigned GNUMode : 1; // True in gnu99 mode false in c99 mode (etc) + unsigned GNUKeywords : 1; // True if GNU-only keywords are allowed unsigned ImplicitInt : 1; // C89 implicit 'int'. unsigned Digraphs : 1; // C94, C99 and C++ unsigned HexFloats : 1; // C99 Hexadecimal float constants. @@ -98,8 +99,13 @@ public: unsigned ElideConstructors : 1; // Whether C++ copy constructors should be // elided if possible. unsigned CatchUndefined : 1; // Generate code to check for undefined ops. - unsigned DumpVtableLayouts : 1; // Dump the layouts of all the emitted - // vtables. + unsigned DumpRecordLayouts : 1; /// Dump the layout of IRgen'd records. + unsigned DumpVTableLayouts : 1; /// Dump the layouts of emitted vtables. + unsigned NoConstantCFStrings : 1; // Do not do CF strings + + // FIXME: This is just a temporary option, for testing purposes. + unsigned NoBitFieldTypeAlign : 1; + private: unsigned GC : 2; // Objective-C Garbage Collection modes. We // declare this enum as unsigned because MSVC @@ -126,9 +132,10 @@ public: LangOptions() { Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0; - GNUMode = ImplicitInt = Digraphs = 0; + GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0; HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0; + NoConstantCFStrings = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0; Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0; @@ -155,7 +162,7 @@ public: OverflowChecking = 0; ObjCGCBitmapPrint = 0; - InstantiationDepth = 500; + InstantiationDepth = 1024; Optimize = 0; OptimizeSize = 0; @@ -169,7 +176,9 @@ public: CharIsSigned = 1; ShortWChar = 0; CatchUndefined = 0; - DumpVtableLayouts = 0; + DumpRecordLayouts = 0; + DumpVTableLayouts = 0; + NoBitFieldTypeAlign = 0; } GCMode getGCMode() const { return (GCMode) GC; } diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 555e6f5..0bbeffe 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -176,19 +176,14 @@ public: /// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful /// for argument passing to functions that expect both objects. class FullSourceLoc : public SourceLocation { - SourceManager* SrcMgr; + const SourceManager *SrcMgr; public: /// Creates a FullSourceLoc where isValid() returns false. - explicit FullSourceLoc() : SrcMgr((SourceManager*) 0) {} + explicit FullSourceLoc() : SrcMgr(0) {} - explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM) + explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} - SourceManager &getManager() { - assert(SrcMgr && "SourceManager is NULL."); - return *SrcMgr; - } - const SourceManager &getManager() const { assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index d123969..930fb52 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -78,8 +78,13 @@ namespace SrcMgr { /// \param Diag Object through which diagnostics will be emitted it the /// buffer cannot be retrieved. /// + /// \param Loc If specified, is the location that invalid file diagnostics + /// will be emitted at. + /// /// \param Invalid If non-NULL, will be set \c true if an error occurred. - const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag, + const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag, + const SourceManager &SM, + SourceLocation Loc = SourceLocation(), bool *Invalid = 0) const; /// getSize - Returns the size of the content encapsulated by this @@ -447,11 +452,17 @@ public: /// getBuffer - Return the buffer for the specified FileID. If there is an /// error opening this buffer the first time, this manufactures a temporary /// buffer and returns a non-empty error string. - const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const { - return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag, - Invalid); + const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc, + bool *Invalid = 0) const { + return getSLocEntry(FID).getFile().getContentCache() + ->getBuffer(Diag, *this, Loc, Invalid); } + const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const { + return getSLocEntry(FID).getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), Invalid); + } + /// getFileEntryForID - Returns the FileEntry record for the provided FileID. const FileEntry *getFileEntryForID(FileID FID) const { return getSLocEntry(FID).getFile().getContentCache()->Entry; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index bc2cf19..1998750 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -45,6 +45,7 @@ protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. bool TLSSupported; + bool NoAsmVariants; // True if {|} are normal characters. unsigned char PointerWidth, PointerAlign; unsigned char IntWidth, IntAlign; unsigned char FloatWidth, FloatAlign; @@ -85,6 +86,14 @@ public: protected: IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType; + + /// Control whether the alignment of bit-field types is respected when laying + /// out structures. If true, then the alignment of the bit-field type will be + /// used to (a) impact the alignment of the containing structure, and (b) + /// ensure that the individual bit-field will not straddle an alignment + /// boundary. + unsigned UseBitFieldTypeAlignment : 1; + public: IntType getSizeType() const { return SizeType; } IntType getIntMaxType() const { return IntMaxType; } @@ -197,6 +206,10 @@ public: return UserLabelPrefix; } + bool useBitFieldTypeAlignment() const { + return UseBitFieldTypeAlignment; + } + /// getTypeName - Return the user string for the specified integer type enum. /// For example, SignedShort -> "short". static const char *getTypeName(IntType T); @@ -326,6 +339,18 @@ public: return "__DATA,__cfstring"; } + /// getNSStringSection - Return the section to use for NSString + /// literals, or 0 if no special section is used. + virtual const char *getNSStringSection() const { + return "__OBJC,__cstring_object,regular,no_dead_strip"; + } + + /// getNSStringNonFragileABISection - Return the section to use for + /// NSString literals, or 0 if no special section is used (NonFragile ABI). + virtual const char *getNSStringNonFragileABISection() const { + return "__DATA, __objc_stringobj, regular, no_dead_strip"; + } + /// isValidSectionSpecifier - This is an optional hook that targets can /// implement to perform semantic checking on attribute((section("foo"))) /// specifiers. In this case, "foo" is passed in to be checked. If the @@ -402,6 +427,15 @@ public: return TLSSupported; } + /// hasNoAsmVariants - Return true if {|} are normal characters in the + /// asm string. If this returns false (the default), then {abc|xyz} is syntax + /// that says that when compiling for asm variant #0, "abc" should be + /// generated, but when compiling for asm variant #1, "xyz" should be + /// generated. + bool hasNoAsmVariants() const { + return NoAsmVariants; + } + /// getEHDataRegisterNumber - Return the register number that /// __builtin_eh_return_regno would return with the specified argument. virtual int getEHDataRegisterNumber(unsigned RegNo) const { diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h index 2e0993a..b3b6184 100644 --- a/include/clang/Basic/Version.h +++ b/include/clang/Basic/Version.h @@ -18,11 +18,11 @@ #include "llvm/ADT/StringRef.h" /// \brief Clang major version -#define CLANG_VERSION_MAJOR 1 +#define CLANG_VERSION_MAJOR 2 // FIXME: Updates to this file must also update CMakeLists.txt and VER. /// \brief Clang minor version -#define CLANG_VERSION_MINOR 5 +#define CLANG_VERSION_MINOR 0 /// \brief Clang patchlevel version // #define CLANG_VERSION_PATCHLEVEL 1 diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h index 6170342..5b65d52 100644 --- a/include/clang/Checker/BugReporter/BugReporter.h +++ b/include/clang/Checker/BugReporter/BugReporter.h @@ -458,7 +458,6 @@ public: namespace bugreporter { const Stmt *GetDerefExpr(const ExplodedNode *N); -const Stmt *GetReceiverExpr(const ExplodedNode *N); const Stmt *GetDenomExpr(const ExplodedNode *N); const Stmt *GetCalleeExpr(const ExplodedNode *N); const Stmt *GetRetValExpr(const ExplodedNode *N); diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h index fdf52a7..0c59d7b 100644 --- a/include/clang/Checker/PathSensitive/AnalysisManager.h +++ b/include/clang/Checker/PathSensitive/AnalysisManager.h @@ -37,6 +37,8 @@ class AnalysisManager : public BugReporterData { enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + unsigned MaxNodes; + bool VisualizeEGDot; bool VisualizeEGUbi; bool PurgeDead; @@ -55,12 +57,12 @@ public: AnalysisManager(ASTContext &ctx, Diagnostic &diags, const LangOptions &lang, PathDiagnosticClient *pd, StoreManagerCreator storemgr, - ConstraintManagerCreator constraintmgr, + ConstraintManagerCreator constraintmgr, unsigned maxnodes, bool vizdot, bool vizubi, bool purge, bool eager, bool trim) : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - AScope(ScopeDecl), + AScope(ScopeDecl), MaxNodes(maxnodes), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), EagerlyAssume(eager), TrimGraph(trim) {} @@ -104,6 +106,8 @@ public: PD->FlushDiagnostics(); } + unsigned getMaxNodes() const { return MaxNodes; } + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h index a3ff0db..2d8afee 100644 --- a/include/clang/Checker/PathSensitive/GRCoreEngine.h +++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h @@ -239,31 +239,7 @@ public: } ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, - const GRState* St, ProgramPoint::Kind K) { - - const GRState* PredState = GetState(Pred); - - // If the state hasn't changed, don't generate a new node. - if (!BuildSinks && St == PredState && Auditor == 0) { - Dst.Add(Pred); - return NULL; - } - - ExplodedNode* N = generateNode(S, St, Pred, K); - - if (N) { - if (BuildSinks) - N->markAsSink(); - else { - if (Auditor && Auditor->Audit(N, Mgr)) - N->markAsSink(); - - Dst.Add(N); - } - } - - return N; - } + const GRState* St, ProgramPoint::Kind K); ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred, const GRState* St) { @@ -273,7 +249,6 @@ public: BuildSinks = Tmp; return N; } - }; class GRBranchNodeBuilder { diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index 161cb28..f04ca75 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -87,6 +87,15 @@ class GRExprEngine : public GRSubEngine { llvm::OwningPtr TF; + class CallExprWLItem { + public: + CallExpr::arg_iterator I; + ExplodedNode *N; + + CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} + }; + public: GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf); @@ -333,6 +342,10 @@ public: /// VisitReturnStmt - Transfer function logic for return statements. void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitOffsetOfExpr - Transfer function for offsetof. + void VisitOffsetOfExpr(OffsetOfExpr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, @@ -352,6 +365,12 @@ public: void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, ExplodedNodeSet &Dst); + void VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -363,6 +382,11 @@ public: const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD, const StackFrameContext *SFC); + /// Evaluate arguments with a work list algorithm. + void EvalArguments(ExprIterator AI, ExprIterator AE, + const FunctionProtoType *FnType, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) /// with those assumptions. diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h index 57ea8a3..2ab3b42 100644 --- a/include/clang/Checker/PathSensitive/MemRegion.h +++ b/include/clang/Checker/PathSensitive/MemRegion.h @@ -869,11 +869,11 @@ public: /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. const ElementRegion *getElementRegion(QualType elementType, SVal Idx, - const MemRegion *superRegion, - ASTContext &Ctx); + const MemRegion *superRegion, + ASTContext &Ctx); const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, - const MemRegion *superRegion) { + const MemRegion *superRegion) { return getElementRegion(ER->getElementType(), ER->getIndex(), superRegion, ER->getContext()); } diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h index 72565f4..41d7c2b 100644 --- a/include/clang/Checker/PathSensitive/Store.h +++ b/include/clang/Checker/PathSensitive/Store.h @@ -129,11 +129,14 @@ public: CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){} }; + const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); + /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from /// a MemRegion* to a specific location type. 'R' is the region being /// casted and 'CastToTy' the result type of the cast. const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); + /// EvalBinOp - Perform pointer arithmetic. virtual SVal EvalBinOp(BinaryOperator::Opcode Op, Loc lhs, NonLoc rhs, QualType resultTy) { diff --git a/include/clang/Checker/PathSensitive/ValueManager.h b/include/clang/Checker/PathSensitive/ValueManager.h index f80ad42..5a9d54d 100644 --- a/include/clang/Checker/PathSensitive/ValueManager.h +++ b/include/clang/Checker/PathSensitive/ValueManager.h @@ -22,6 +22,7 @@ #include "clang/Checker/PathSensitive/BasicValueFactory.h" #include "clang/Checker/PathSensitive/SymbolManager.h" #include "clang/Checker/PathSensitive/SValuator.h" +#include "clang/AST/ExprCXX.h" namespace llvm { class BumpPtrAllocator; } @@ -133,6 +134,11 @@ public: I->getType()->isUnsignedIntegerType())); } + nonloc::ConcreteInt makeIntVal(const CXXBoolLiteralExpr *E) { + return E->getValue() ? nonloc::ConcreteInt(BasicVals.getValue(1, 1, true)) + : nonloc::ConcreteInt(BasicVals.getValue(0, 1, true)); + } + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { return nonloc::ConcreteInt(BasicVals.getValue(V)); } diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h index 638ed51..54d3ba0 100644 --- a/include/clang/CodeGen/CodeGenOptions.h +++ b/include/clang/CodeGen/CodeGenOptions.h @@ -28,10 +28,17 @@ public: OnlyAlwaysInlining // Only run the always inlining pass. }; + enum ObjCDispatchMethodKind { + Legacy = 0, + NonLegacy = 1, + Mixed = 2 + }; + unsigned AsmVerbose : 1; /// -dA, -fverbose-asm. unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors. unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker /// aliases to base ctors when possible. + unsigned DataSections : 1; /// Set when -fdata-sections is enabled unsigned DebugInfo : 1; /// Should generate deubg info (-g). unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled. unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in @@ -39,12 +46,12 @@ public: /// internal state before optimizations are /// done. unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled. + unsigned FunctionSections : 1; /// Set when -ffunction-sections is enabled unsigned MergeAllConstants : 1; /// Merge identical constants. unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss - unsigned ObjCLegacyDispatch: 1; /// Use legacy Objective-C dispatch, even with - /// 2.0 runtime. + unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use. unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. unsigned SoftFloat : 1; /// -soft-float. @@ -88,15 +95,17 @@ public: AsmVerbose = 0; CXAAtExit = 1; CXXCtorDtorAliases = 0; + DataSections = 0; DebugInfo = 0; DisableFPElim = 0; DisableLLVMOpts = 0; DisableRedZone = 0; + FunctionSections = 0; MergeAllConstants = 1; NoCommon = 0; NoImplicitFloat = 0; NoZeroInitializedInBSS = 0; - ObjCLegacyDispatch = 0; + ObjCDispatchMethod = Legacy; OptimizationLevel = 0; OptimizeSize = 0; SoftFloat = 0; @@ -109,6 +118,10 @@ public: Inlining = NoInlining; RelocationModel = "pic"; } + + ObjCDispatchMethodKind getObjCDispatchMethod() const { + return ObjCDispatchMethodKind(ObjCDispatchMethod); + } }; } // end namespace clang diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 124288a..18b54ef 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -97,6 +97,8 @@ def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, HelpText<"Display exploded graph using GraphViz">; def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, HelpText<"Display exploded graph using Ubigraph">; +def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, + HelpText<"The maximum number of nodes the analyzer can generate">; //===----------------------------------------------------------------------===// // CodeGen Options @@ -123,6 +125,10 @@ def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, HelpText<"Do not emit code to make initialization of local statics thread safe">; def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">, HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; +def ffunction_sections : Flag<"-ffunction-sections">, + HelpText<"Place each function in its own section (ELF Only)">; +def fdata_sections : Flag<"-fdata-sections">, + HelpText<"Place each data in its own section (ELF Only)">; def masm_verbose : Flag<"-masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<"-mcode-model">, @@ -192,6 +198,10 @@ def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, HelpText<"Print diagnostic name with mappable diagnostics">; def ftabstop : Separate<"-ftabstop">, MetaVarName<"">, HelpText<"Set the tab stop distance.">; +def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"">, + HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">; +def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"">, + HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, @@ -235,8 +245,6 @@ def x : Separate<"-x">, HelpText<"Input language type">; def cxx_inheritance_view : Separate<"-cxx-inheritance-view">, MetaVarName<"">, HelpText<"View C++ inheritance for a specified class">; -def fixit_at : Separate<"-fixit-at">, MetaVarName<"">, - HelpText<"Perform Fix-It modifications at the given source location">; def o : Separate<"-o">, MetaVarName<"">, HelpText<"Specify output file">; def load : Separate<"-load">, MetaVarName<"">, HelpText<"Load the named plugin (dynamic shared object)">; @@ -269,6 +277,8 @@ def fsyntax_only : Flag<"-fsyntax-only">, HelpText<"Run parser and perform semantic analysis">; def fixit : Flag<"-fixit">, HelpText<"Apply fix-it advice to the input source">; +def fixit_EQ : Joined<"-fixit=">, + HelpText<"Apply fix-it advice creating a file with the given suffix">; def parse_print_callbacks : Flag<"-parse-print-callbacks">, HelpText<"Run parser and print each callback invoked">; def emit_html : Flag<"-emit-html">, @@ -283,8 +293,6 @@ def ast_view : Flag<"-ast-view">, HelpText<"Build ASTs and view them with GraphViz">; def print_decl_contexts : Flag<"-print-decl-contexts">, HelpText<"Print DeclContexts and their Decls">; -def dump_record_layouts : Flag<"-dump-record-layouts">, - HelpText<"Dump record layout information">; def emit_pth : Flag<"-emit-pth">, HelpText<"Generate pre-tokenized header file">; def emit_pch : Flag<"-emit-pch">, @@ -315,6 +323,14 @@ def print_stats : Flag<"-print-stats">, def ftime_report : Flag<"-ftime-report">, HelpText<"Print the amount of time each phase of compilation takes">; +def fdump_record_layouts : Flag<"-fdump-record-layouts">, + HelpText<"Dump record layout information">; + +// Generic forwarding to LLVM options. This should only be used for debugging +// and experimental features. +def mllvm : Separate<"-mllvm">, + HelpText<"Additional arguments to forward to LLVM's option processing">; + //===----------------------------------------------------------------------===// // Language Options //===----------------------------------------------------------------------===// @@ -323,10 +339,14 @@ def fno_builtin : Flag<"-fno-builtin">, HelpText<"Disable implicit builtin knowledge of functions">; def faltivec : Flag<"-faltivec">, HelpText<"Enable AltiVec vector initializer syntax">; -def faccess_control : Flag<"-faccess-control">, - HelpText<"Enable C++ access control">; +def fno_access_control : Flag<"-fno-access-control">, + HelpText<"Disable C++ access control">; def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, HelpText<"Don't assume that C++'s global operator new can't alias any pointer">; +def fgnu_keywords : Flag<"-fgnu-keywords">, + HelpText<"Allow GNU-extension keywords regardless of language standard">; +def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, + HelpText<"Disallow GNU-extension keywords regardless of language standard">; def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, HelpText<"Allow '$' in identifiers">; def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, @@ -365,12 +385,14 @@ def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, def fconstant_string_class : Separate<"-fconstant-string-class">, MetaVarName<"">, HelpText<"Specify the class to use for constant Objective-C string objects.">; +def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, + HelpText<"Enable creation of CodeFoundation-type constant strings">; def fobjc_gc : Flag<"-fobjc-gc">, HelpText<"Enable Objective-C garbage collection">; def fobjc_gc_only : Flag<"-fobjc-gc-only">, HelpText<"Use GC exclusively for Objective-C related memory management">; -def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, - HelpText<"Use legacy dispatch with the Objective-C non-fragile ABI">; +def fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">, + HelpText<"Objective-C dispatch method to use">; def print_ivar_layout : Flag<"-print-ivar-layout">, HelpText<"Enable Objective-C Ivar layout bitmap print trace">; def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, @@ -401,6 +423,8 @@ def trigraphs : Flag<"-trigraphs">, HelpText<"Process trigraph sequences">; def fwritable_strings : Flag<"-fwritable-strings">, HelpText<"Store string literals as writable data">; +def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">, + HelpText<"Ignore bit-field types when aligning structures">; //===----------------------------------------------------------------------===// // Header Search Options diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index ed68d68..2127e57 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -248,7 +248,7 @@ def fclasspath_EQ : Joined<"-fclasspath=">, Group; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, Group; def fcommon : Flag<"-fcommon">, Group; def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group; -def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group; +def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group; def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group; def fcreate_profile : Flag<"-fcreate-profile">, Group; def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group; @@ -265,6 +265,10 @@ def fexceptions : Flag<"-fexceptions">, Group; def fextdirs_EQ : Joined<"-fextdirs=">, Group; def fhosted : Flag<"-fhosted">, Group; def ffreestanding : Flag<"-ffreestanding">, Group; + +def fgnu_keywords : Flag<"-fgnu-keywords">, Group; +def fasm : Flag<"-fasm">, Alias; + def fgnu_runtime : Flag<"-fgnu-runtime">, Group; def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; def filelist : Separate<"-filelist">, Flags<[LinkerInput]>; @@ -300,6 +304,10 @@ def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group, Group; def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group; def fno_exceptions : Flag<"-fno-exceptions">, Group; + +def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group; +def fno_asm : Flag<"-fno-asm">, Alias; + def fno_inline_functions : Flag<"-fno-inline-functions">, Group; def fno_inline : Flag<"-fno-inline">, Group; def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group; @@ -321,6 +329,7 @@ def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group; def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group; def fno_working_directory : Flag<"-fno-working-directory">, Group; def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group; +def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group; def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group; def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group; def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group; @@ -356,7 +365,10 @@ def fstack_protector : Flag<"-fstack-protector">, Group; def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group; def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>; def ftabstop_EQ : Joined<"-ftabstop=">, Group; +def ferror_limit_EQ : Joined<"-ferror-limit=">, Group; def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group; +def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">, + Group; def fterminated_vtables : Flag<"-fterminated-vtables">, Group; def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group; def ftime_report : Flag<"-ftime-report">, Group; diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h index 851e423..ef77206 100644 --- a/include/clang/Driver/Tool.h +++ b/include/clang/Driver/Tool.h @@ -48,6 +48,10 @@ public: virtual bool hasIntegratedAssembler() const { return false; } virtual bool hasIntegratedCPP() const = 0; + /// \brief Does this tool have "good" standardized diagnostics, or should the + /// driver add an additional "command failed" diagnostic on failures. + virtual bool hasGoodDiagnostics() const { return false; } + /// ConstructJob - Construct jobs to perform the action \arg JA, /// writing to \arg Output and with \arg Inputs. /// diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 9a82973..1a8ae77 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -103,6 +103,10 @@ public: /// ABI). virtual bool IsObjCLegacyDispatchDefault() const { return false; } + /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the + /// mixed dispatch method be used? + virtual bool UseObjCMixedDispatch() const { return false; } + /// GetDefaultStackProtectorLevel - Get the default stack protector level for /// this tool chain (0=off, 1=on, 2=all). virtual unsigned GetDefaultStackProtectorLevel() const { return 0; } @@ -120,6 +124,9 @@ public: /// particular PIC mode. virtual const char *GetForcedPicModel() const = 0; + /// Does this tool chain support Objective-C garbage collection. + virtual bool SupportsObjCGC() const { return false; } + /// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf /// compile unit information. virtual bool UseDwarfDebugFlags() const { return false; } diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index b5b09f5..9163a20 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -57,10 +57,6 @@ ASTConsumer *CreateASTViewer(); // to stderr; this is intended for debugging. ASTConsumer *CreateDeclContextPrinter(); -// RecordLayout dumper: prints out the record layout information for all records -// in the translation unit; this is intended for debugging. -ASTConsumer *CreateRecordLayoutDumper(); - // ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code. // This is considered experimental, and only works with Apple's ObjC runtime. ASTConsumer *CreateObjCRewriter(const std::string &InFile, diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 287c67e..aaa3920 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -15,22 +15,21 @@ #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) #endif -ANALYSIS(CFGDump, "cfg-dump", +ANALYSIS(CFGDump, "cfg-dump", "Display Control-Flow Graphs", Code) -ANALYSIS(CFGView, "cfg-view", +ANALYSIS(CFGView, "cfg-view", "View Control-Flow Graphs using GraphViz", Code) ANALYSIS(DisplayLiveVariables, "dump-live-variables", "Print results of live variable analysis", Code) ANALYSIS(SecuritySyntacticChecks, "analyzer-check-security-syntactic", - "Perform quick security checks that require no data flow", - Code) + "Perform quick security checks that require no data flow", Code) ANALYSIS(LLVMConventionChecker, "analyzer-check-llvm-conventions", - "Check code for LLVM codebase conventions (domain-specific)", - TranslationUnit) + "Check code for LLVM codebase conventions (domain-specific)", + TranslationUnit) ANALYSIS(WarnDeadStores, "analyzer-check-dead-stores", "Warn about stores to dead variables", Code) @@ -39,15 +38,15 @@ ANALYSIS(WarnUninitVals, "warn-uninit-values", "Warn about uses of uninitialized variables", Code) ANALYSIS(WarnObjCMethSigs, "analyzer-check-objc-methodsigs", - "Warn about Objective-C method signatures with type incompatibilities", - ObjCImplementation) + "Warn about Objective-C method signatures with type incompatibilities", + ObjCImplementation) ANALYSIS(WarnObjCDealloc, "analyzer-check-objc-missing-dealloc", - "Warn about Objective-C classes that lack a correct implementation of -dealloc", - ObjCImplementation) +"Warn about Objective-C classes that lack a correct implementation of -dealloc", + ObjCImplementation) ANALYSIS(WarnObjCUnusedIvars, "analyzer-check-objc-unused-ivars", - "Warn about private ivars that are never used", ObjCImplementation) + "Warn about private ivars that are never used", ObjCImplementation) ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", "Run the [Core] Foundation reference count checker", Code) @@ -55,10 +54,6 @@ ANALYSIS(ObjCMemChecker, "analyzer-check-objc-mem", ANALYSIS(WarnSizeofPointer, "warn-sizeof-pointer", "Warn about unintended use of sizeof() on pointer expressions", Code) -ANALYSIS(InlineCall, "inline-call", - "Experimental transfer function inling callees when its definition" - " is available.", TranslationUnit) - #ifndef ANALYSIS_STORE #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h index f55e5dc..3341bb0 100644 --- a/include/clang/Frontend/AnalysisConsumer.h +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -60,6 +60,7 @@ public: AnalysisConstraints AnalysisConstraintsOpt; AnalysisDiagClients AnalysisDiagOpt; std::string AnalyzeSpecificFunction; + unsigned MaxNodes; unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index b37c180..797cb34 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -38,6 +38,9 @@ public: /// binary serialization mechanism, to be /// deserialized by, e.g., the CIndex library. + unsigned ErrorLimit; /// Limit # errors emitted. + unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace. + /// The distance between tab stops. unsigned TabStop; enum { DefaultTabStop = 8, MaxTabStop = 100 }; @@ -70,6 +73,8 @@ public: ShowSourceRanges = 0; VerifyDiagnostics = 0; BinaryOutput = 0; + ErrorLimit = 0; + TemplateBacktraceLimit = 0; } }; diff --git a/include/clang/Frontend/FixItRewriter.h b/include/clang/Frontend/FixItRewriter.h index fac87af..b432d74 100644 --- a/include/clang/Frontend/FixItRewriter.h +++ b/include/clang/Frontend/FixItRewriter.h @@ -16,23 +16,24 @@ #define LLVM_CLANG_FRONTEND_FIX_IT_REWRITER_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Rewrite/Rewriter.h" #include "llvm/ADT/SmallVector.h" +namespace llvm { class raw_ostream; } + namespace clang { class SourceManager; class FileEntry; -/// \brief Stores a source location in the form that it shows up on -/// the Clang command line, e.g., file:line:column. -/// -/// FIXME: Would prefer to use real SourceLocations, but I don't see a -/// good way to resolve them during parsing. -struct RequestedSourceLocation { - const FileEntry *File; - unsigned Line; - unsigned Column; +class FixItPathRewriter { +public: + virtual ~FixItPathRewriter(); + + /// \brief This file is about to be rewritten. Return the name of the file + /// that is okay to write to. + virtual std::string RewriteFilename(const std::string &Filename) = 0; }; class FixItRewriter : public DiagnosticClient { @@ -47,38 +48,46 @@ class FixItRewriter : public DiagnosticClient { /// of error messages. DiagnosticClient *Client; + /// \brief Turn an input path into an output path. NULL implies overwriting + /// the original. + FixItPathRewriter *PathRewriter; + /// \brief The number of rewriter failures. unsigned NumFailures; - /// \brief Locations at which we should perform fix-its. - /// - /// When empty, perform fix-it modifications everywhere. - llvm::SmallVector FixItLocations; - public: + typedef Rewriter::buffer_iterator iterator; + /// \brief Initialize a new fix-it rewriter. FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, - const LangOptions &LangOpts); + const LangOptions &LangOpts, FixItPathRewriter *PathRewriter); /// \brief Destroy the fix-it rewriter. ~FixItRewriter(); - /// \brief Add a location where fix-it modifications should be - /// performed. - void addFixItLocation(RequestedSourceLocation Loc) { - FixItLocations.push_back(Loc); + /// \brief Check whether there are modifications for a given file. + bool IsModified(FileID ID) const { + return Rewrite.getRewriteBufferFor(ID) != NULL; } - /// \brief Write the modified source file. + // Iteration over files with changes. + iterator buffer_begin() { return Rewrite.buffer_begin(); } + iterator buffer_end() { return Rewrite.buffer_end(); } + + /// \brief Write a single modified source file. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFile(FileID ID, llvm::raw_ostream &OS); + + /// \brief Write the modified source files. /// /// \returns true if there was an error, false otherwise. - bool WriteFixedFile(const std::string &InFileName, - const std::string &OutFileName = std::string()); + bool WriteFixedFiles(); /// IncludeInDiagnosticCounts - This method (whose default implementation - /// returns true) indicates whether the diagnostics handled by this - /// DiagnosticClient should be included in the number of diagnostics - /// reported by Diagnostic. + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticClient should be included in the number of diagnostics + /// reported by Diagnostic. virtual bool IncludeInDiagnosticCounts() const; /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index a7b6aa7..3ddd77d 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -16,6 +16,7 @@ namespace clang { class FixItRewriter; +class FixItPathRewriter; //===----------------------------------------------------------------------===// // Custom Consumer Actions @@ -73,15 +74,10 @@ protected: llvm::StringRef InFile); }; -class DumpRecordAction : public ASTFrontendAction { -protected: - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile); -}; - class FixItAction : public ASTFrontendAction { private: llvm::OwningPtr Rewriter; + llvm::OwningPtr PathRewriter; protected: diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index ee3811a..60512ed 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -24,7 +24,6 @@ namespace frontend { ASTPrintXML, ///< Parse ASTs and print them in XML. ASTView, ///< Parse ASTs and view them in Graphviz. DumpRawTokens, ///< Dump out raw tokens. - DumpRecordLayouts, ///< Dump record layout information. DumpTokens, ///< Dump out preprocessed tokens. EmitAssembly, ///< Emit a .s file. EmitBC, ///< Emit a .bc file. @@ -93,8 +92,8 @@ public: /// If given, the name for a C++ class to view the inheritance of. std::string ViewClassInheritance; - /// A list of locations to apply fix-its at. - std::vector FixItLocations; + /// If given, the new suffix for fix-it rewritten files. + std::string FixItSuffix; /// If given, enable code completion at the provided location. ParsedSourceLocation CodeCompletionAt; @@ -111,6 +110,10 @@ public: /// \brief The list of AST files to merge. std::vector ASTMergeFiles; + /// \brief A list of arguments to forward to LLVM's option processing; this + /// should only be used for debugging and experimental features. + std::vector LLVMArgs; + public: FrontendOptions() { DebugCodeCompletionPrinter = 1; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index f975c49..1640afb 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -453,7 +453,9 @@ namespace clang { /// \brief Block extedned descriptor type for Blocks CodeGen SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13, /// \brief Objective-C "SEL" redefinition type - SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14 + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14, + /// \brief NSConstantString type + SPECIAL_TYPE_NS_CONSTANT_STRING = 15 }; /// \brief Record codes for each kind of declaration. @@ -601,6 +603,8 @@ namespace clang { EXPR_PAREN, /// \brief A UnaryOperator record. EXPR_UNARY_OPERATOR, + /// \brief An OffsetOfExpr record. + EXPR_OFFSETOF, /// \brief A SizefAlignOfExpr record. EXPR_SIZEOF_ALIGN_OF, /// \brief An ArraySubscriptExpr record. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 73c1bf4..c235230 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -436,7 +436,7 @@ private: std::deque PendingIdentifierInfos; /// \brief FIXME: document! - llvm::SmallVector SpecialTypes; + llvm::SmallVector SpecialTypes; /// \brief Contains declarations and definitions that will be /// "interesting" to the ASTConsumer, when we get that AST consumer. @@ -688,6 +688,9 @@ public: Selector DecodeSelector(unsigned Idx); + virtual Selector GetSelector(uint32_t ID); + virtual uint32_t GetNumKnownSelectors(); + Selector GetSelector(const RecordData &Record, unsigned &Idx) { return DecodeSelector(Record[Idx++]); } diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def index 2f0da9e..f63761a 100644 --- a/include/clang/Frontend/StmtXML.def +++ b/include/clang/Frontend/StmtXML.def @@ -254,7 +254,7 @@ NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op ENUM_XML(UnaryOperator::Real, "__real") ENUM_XML(UnaryOperator::Imag, "__imag") ENUM_XML(UnaryOperator::Extension, "__extension__") - ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof") + ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof") END_ENUM_XML SUB_NODE_XML(Expr) // expr END_NODE_XML @@ -311,6 +311,13 @@ NODE_XML(ConditionalOperator, "ConditionalOperator") // expr1 ? expr2 : expr3 SUB_NODE_XML(Expr) // expr3 END_NODE_XML +NODE_XML(OffsetOfExpr, "OffsetOfExpr") // offsetof(basetype, components) + ATTRIBUTE_FILE_LOCATION_XML + TYPE_ATTRIBUTE_XML(getTypeSourceInfo()->getType()) + ATTRIBUTE_XML(getNumComponents(), "num_components") + SUB_NODE_SEQUENCE_XML(OffsetOfExpr::OffsetOfNode) +END_NODE_XML + NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr") // sizeof(expr) or alignof(expr) ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index 157876b..3367136 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -68,7 +68,7 @@ public: void EmitCaretDiagnostic(SourceLocation Loc, SourceRange *Ranges, unsigned NumRanges, - SourceManager &SM, + const SourceManager &SM, const FixItHint *Hints, unsigned NumHints, unsigned Columns); diff --git a/include/clang/Frontend/VerifyDiagnosticsClient.h b/include/clang/Frontend/VerifyDiagnosticsClient.h index 08adbb0..6f45e49 100644 --- a/include/clang/Frontend/VerifyDiagnosticsClient.h +++ b/include/clang/Frontend/VerifyDiagnosticsClient.h @@ -25,7 +25,10 @@ class TextDiagnosticBuffer; /// USING THE DIAGNOSTIC CHECKER: /// /// Indicating that a line expects an error or a warning is simple. Put a -/// comment on the line that has the diagnostic, use "expected-{error,warning}" +/// comment on the line that has the diagnostic, use: +/// +/// expected-{error,warning,note} +/// /// to tag if it's an expected error or warning, and place the expected text /// between {{ and }} markers. The full text doesn't have to be included, only /// enough to ensure that the correct diagnostic was emitted. @@ -45,6 +48,20 @@ class TextDiagnosticBuffer; /// /// void f(); // expected-note 2 {{previous declaration is here}} /// +/// Regex matching mode may be selected by appending '-re' to type. Example: +/// +/// expected-error-re +/// +/// Examples matching error: "variable has incomplete type 'struct s'" +/// +/// // expected-error {{variable has incomplete type 'struct s'}} +/// // expected-error {{variable has incomplete type}} +/// +/// // expected-error-re {{variable has has type 'struct .'}} +/// // expected-error-re {{variable has has type 'struct .*'}} +/// // expected-error-re {{variable has has type 'struct (.*)'}} +/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}} +/// class VerifyDiagnosticsClient : public DiagnosticClient { public: Diagnostic &Diags; diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index e891e94..d74124e 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -44,6 +44,14 @@ public: SrcMgr::CharacteristicKind FileType) { } + /// FileSkipped - This callback is invoked whenever a source file is + /// skipped as the result of header guard optimization. ParentFile + /// is the file that #includes the skipped file. FilenameTok is the + /// token in ParentFile that indicates the skipped file. + virtual void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { + } /// EndOfMainFile - This callback is invoked when the end of the main file is /// reach, no subsequent callbacks will be made. @@ -96,6 +104,13 @@ public: Second->FileChanged(Loc, Reason, FileType); } + virtual void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { + First->FileSkipped(ParentFile, FilenameTok, FileType); + Second->FileSkipped(ParentFile, FilenameTok, FileType); + } + virtual void EndOfMainFile() { First->EndOfMainFile(); Second->EndOfMainFile(); diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 312a760..20d9fc5 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -366,17 +366,17 @@ public: /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. - bool EnterMainSourceFile(); + void EnterMainSourceFile(); /// EndSourceFile - Inform the preprocessor callbacks that processing is /// complete. void EndSourceFile(); /// EnterSourceFile - Add a source file to the top of the include stack and - /// start lexing tokens from it instead of the current buffer. Return true - /// and fill in ErrorStr with the error information on failure. - bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, - std::string &ErrorStr); + /// start lexing tokens from it instead of the current buffer. Emit an error + /// and don't enter the file on error. + void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, + SourceLocation Loc); /// EnterMacro - Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. Args specifies the diff --git a/include/clang/Lex/TokenConcatenation.h b/include/clang/Lex/TokenConcatenation.h index d759e47..094990a 100644 --- a/include/clang/Lex/TokenConcatenation.h +++ b/include/clang/Lex/TokenConcatenation.h @@ -58,7 +58,9 @@ namespace clang { public: TokenConcatenation(Preprocessor &PP); - bool AvoidConcat(const Token &PrevTok, const Token &Tok) const; + bool AvoidConcat(const Token &PrevPrevTok, + const Token &PrevTok, + const Token &Tok) const; private: /// StartsWithL - Return true if the spelling of this token starts with 'L'. diff --git a/include/clang/Makefile b/include/clang/Makefile index 624292a..d76e0a9 100644 --- a/include/clang/Makefile +++ b/include/clang/Makefile @@ -2,3 +2,30 @@ LEVEL = ../../../.. DIRS := Basic Driver include $(LEVEL)/Makefile.common + +install-local:: + $(Echo) Installing Clang include files + $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) + $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include/clang" ; then \ + cd $(PROJ_SRC_ROOT)/tools/clang/include && \ + for hdr in `find clang -type f '!' '(' -name '*~' \ + -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ + -o -name 'Makefile' -o -name '*.td' ')' -print \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) + $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang" ; then \ + cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ + for hdr in `find clang -type f '!' '(' -name 'Makefile' ')' -print \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +endif diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 59cc0d2..3d68d80 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -205,7 +205,7 @@ public: /// \returns the type referred to by this identifier, or NULL if the type /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS = 0, + Scope *S, CXXScopeSpec *SS = 0, bool isClassName = false, TypeTy *ObjectType = 0) = 0; @@ -243,7 +243,7 @@ public: virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, - const CXXScopeSpec *SS, + CXXScopeSpec *SS, TypeTy *&SuggestedType) { return false; } @@ -281,7 +281,7 @@ public: /// /// \returns the kind of template that this name refers to. virtual TemplateNameKind isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, @@ -329,7 +329,7 @@ public: /// This actual is used in the parsing of pseudo-destructor names to /// distinguish a nested-name-specifier and a "type-name ::" when we /// see the token sequence "X :: ~". - virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, TypeTy *ObjectType) { @@ -371,7 +371,7 @@ public: /// /// \returns a CXXScopeTy* object representing the C++ scope. virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -387,7 +387,7 @@ public: /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. virtual bool IsInvalidUnlessNestedName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext) { @@ -428,7 +428,7 @@ public: /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. /// \returns true if an error occurred, false otherwise. - virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) { return false; } @@ -468,7 +468,11 @@ public: virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy(); } - virtual void ActOnObjCCatchParam(DeclPtrTy D) { + + /// \brief Parsed an exception object declaration within an Objective-C + /// @catch statement. + virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D) { + return DeclPtrTy(); } /// AddInitializerToDecl - This action is called immediately after @@ -576,8 +580,7 @@ public: virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc) { return DeclPtrTy(); } @@ -655,7 +658,7 @@ public: /// /// \returns the declaration to which this tag refers. virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -938,20 +941,46 @@ public: } // Objective-c statements + + /// \brief Parsed an Objective-C @catch statement. + /// + /// \param AtLoc The location of the '@' starting the '@catch'. + /// + /// \param RParen The location of the right parentheses ')' after the + /// exception variable. + /// + /// \param Parm The variable that will catch the exception. Will be NULL if + /// this is a @catch(...) block. + /// + /// \param Body The body of the @catch block. virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, - DeclPtrTy Parm, StmtArg Body, - StmtArg CatchList) { + DeclPtrTy Parm, StmtArg Body) { return StmtEmpty(); } + /// \brief Parsed an Objective-C @finally statement. + /// + /// \param AtLoc The location of the '@' starting the '@finally'. + /// + /// \param Body The body of the @finally block. virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { return StmtEmpty(); } + /// \brief Parsed an Objective-C @try-@catch-@finally statement. + /// + /// \param AtLoc The location of the '@' starting '@try'. + /// + /// \param Try The body of the '@try' statement. + /// + /// \param CatchStmts The @catch statements. + /// + /// \param Finally The @finally statement. virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, StmtArg Catch, + StmtArg Try, + MultiStmtArg CatchStmts, StmtArg Finally) { return StmtEmpty(); } @@ -1049,7 +1078,7 @@ public: /// id-expression or identifier was an ampersand ('&'), indicating that /// we will be taking the address of this expression. virtual OwningExprResult ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, bool HasTrailingLParen, bool IsAddressOfOperand) { @@ -1127,7 +1156,7 @@ public: virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Member, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen) { @@ -1315,7 +1344,7 @@ public: virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); @@ -1326,7 +1355,7 @@ public: SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { return DeclPtrTy(); @@ -1372,7 +1401,7 @@ public: AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -1501,7 +1530,7 @@ public: /// \returns the type being destructed. virtual TypeTy *getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, TypeTy *ObjectType, bool EnteringContext) { return getTypeName(II, NameLoc, S, &SS, false, ObjectType); @@ -1683,7 +1712,7 @@ public: virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, @@ -1729,7 +1758,7 @@ public: virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorDecl, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -1939,7 +1968,7 @@ public: /// \param EnteringContext whether we are entering the context of this /// template. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { @@ -1995,7 +2024,7 @@ public: virtual DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -2133,7 +2162,7 @@ public: SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr) { @@ -2306,7 +2335,7 @@ public: TypeTy *ReturnType, // the method return type. Selector Sel, // a unique name for the method. ObjCArgInfo *ArgInfo, // ArgInfo: Has 'Sel.getNumArgs()' entries. - llvm::SmallVectorImpl &Cdecls, // c-style args + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *MethodAttrList, // optional // tok::objc_not_keyword, tok::objc_optional, tok::objc_required tok::ObjCKeywordKind impKind, @@ -2336,36 +2365,118 @@ public: return DeclPtrTy(); } - virtual OwningExprResult ActOnClassPropertyRefExpr( - IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation &receiverNameLoc, - SourceLocation &propertyNameLoc) { + virtual OwningExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc) { return ExprEmpty(); } - // ActOnClassMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnClassMessage( - Scope *S, - IdentifierInfo *receivingClassName, - Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, - SourceLocation selectorLoc, - SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs) { - return ExprResult(); - } - // ActOnInstanceMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation selectorLoc, SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs) { - return ExprResult(); + /// \brief Describes the kind of message expression indicated by a message + /// send that starts with an identifier. + enum ObjCMessageKind { + /// \brief The message is sent to 'super'. + ObjCSuperMessage, + /// \brief The message is an instance message. + ObjCInstanceMessage, + /// \brief The message is a class message, and the identifier is a type + /// name. + ObjCClassMessage + }; + + /// \brief Determine the kind of Objective-C message send that we will be + /// performing based on the identifier given. + /// + /// This action determines how a message send that starts with [ + /// identifier (followed by another identifier) will be parsed, + /// e.g., as a class message, instance message, super message. The + /// result depends on the meaning of the given identifier. If the + /// identifier is unknown, the action should indicate that the + /// message is an instance message. + /// + /// By default, this routine applies syntactic disambiguation and uses + /// \c getTypeName() to determine whether the identifier refers to a type. + /// However, \c Action subclasses may override this routine to improve + /// error recovery. + /// + /// \param S The scope in which the message send occurs. + /// + /// \param Name The identifier following the '['. + /// + /// \param NameLoc The location of the identifier. + /// + /// \param IsSuper Whether the name is the pseudo-keyword "super". + /// + /// \param HasTrailingDot Whether the name is followed by a period. + /// + /// \param ReceiverType If this routine returns \c ObjCClassMessage, + /// this argument will be set to the receiver type. + /// + /// \returns The kind of message send. + virtual ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType); + + /// \brief Parsed a message send to 'super'. + /// + /// \param S The scope in which the message send occurs. + /// \param SuperLoc The location of the 'super' keyword. + /// \param Sel The selector to which the message is being sent. + /// \param LBracLoc The location of the opening square bracket ']'. + /// \param SelectorLoc The location of the first identifier in the selector. + /// \param RBrac The location of the closing square bracket ']'. + /// \param Args The message arguments. + virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + return OwningExprResult(*this); + } + + /// \brief Parsed a message send to a class. + /// + /// \param S The scope in which the message send occurs. + /// \param Receiver The type of the class receiving the message. + /// \param Sel The selector to which the message is being sent. + /// \param LBracLoc The location of the opening square bracket ']'. + /// \param SelectorLoc The location of the first identifier in the selector. + /// \param RBrac The location of the closing square bracket ']'. + /// \param Args The message arguments. + virtual OwningExprResult ActOnClassMessage(Scope *S, + TypeTy *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + return OwningExprResult(*this); + } + + /// \brief Parsed a message send to an object instance. + /// + /// \param S The scope in which the message send occurs. + /// \param Receiver The expression that computes the receiver object. + /// \param Sel The selector to which the message is being sent. + /// \param LBracLoc The location of the opening square bracket ']'. + /// \param SelectorLoc The location of the first identifier in the selector. + /// \param RBrac The location of the closing square bracket ']'. + /// \param Args The message arguments. + virtual OwningExprResult ActOnInstanceMessage(Scope *S, + ExprArg Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + return OwningExprResult(*this); } + virtual DeclPtrTy ActOnForwardClassDeclaration( SourceLocation AtClassLoc, IdentifierInfo **IdentList, @@ -2581,7 +2692,7 @@ public: /// /// \parame EnteringContext whether we're entering the context of this /// scope specifier. - virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { } /// \brief Code completion for a C++ "using" declaration or directive. @@ -2692,21 +2803,33 @@ public: unsigned NumMethods) { } + /// \brief Code completion for an ObjC message expression that sends + /// a message to the superclass. + /// + /// This code completion action is invoked when the code-completion token is + /// found after the class name and after each argument. + /// + /// \param S The scope in which the message expression occurs. + /// \param SuperLoc The location of the 'super' keyword. + /// \param SelIdents The identifiers that describe the selector (thus far). + /// \param NumSelIdents The number of identifiers in \p SelIdents. + virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { } + /// \brief Code completion for an ObjC message expression that refers to /// a class method. /// /// This code completion action is invoked when the code-completion token is /// found after the class name and after each argument. /// - /// \param S the scope in which the message expression occurs. - /// \param FName the factory name. - /// \param FNameLoc the source location of the factory name. - /// \param SelIdents the identifiers that describe the selector (thus far). - /// \param NumSelIdents the number of identifiers in \p SelIdents. - virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc, + /// \param S The scope in which the message expression occurs. + /// \param Receiver The type of the class that is receiving a message. + /// \param SelIdents The identifiers that describe the selector (thus far). + /// \param NumSelIdents The number of identifiers in \p SelIdents. + virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, IdentifierInfo **SelIdents, - unsigned NumSelIdents){ } + unsigned NumSelIdents) { } /// \brief Code completion for an ObjC message expression that refers to /// an instance method. @@ -2752,7 +2875,8 @@ public: /// /// \param ClassName the name of the class being defined. virtual void CodeCompleteObjCSuperclass(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { } /// \brief Code completion for an Objective-C implementation, after the @@ -2765,7 +2889,8 @@ public: /// This code completion action is invoked after the '(' that indicates /// a category name within an Objective-C interface declaration. virtual void CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { } /// \brief Code completion for the category name in an Objective-C category @@ -2774,7 +2899,8 @@ public: /// This code completion action is invoked after the '(' that indicates /// the category name within an Objective-C category implementation. virtual void CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { } /// \brief Code completion for the property names when defining an @@ -2795,6 +2921,32 @@ public: IdentifierInfo *PropertyName, DeclPtrTy ObjCImpDecl) { } + + /// \brief Code completion for an Objective-C method declaration or + /// definition, which may occur within an interface, category, + /// extension, protocol, or implementation thereof (where applicable). + /// + /// This code completion action is invoked after the "-" or "+" that + /// starts a method declaration or definition, and after the return + /// type such a declaration (e.g., "- (id)"). + /// + /// \param S The scope in which the completion occurs. + /// + /// \param IsInstanceMethod Whether this is an instance method + /// (introduced with '-'); otherwise, it's a class method + /// (introduced with '+'). + /// + /// \param ReturnType If non-NULL, the specified return type of the method + /// being declared or defined. + /// + /// \param IDecl The interface, category, protocol, or + /// implementation, or category implementation in which this method + /// declaration or definition occurs. + virtual void CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnType, + DeclPtrTy IDecl) { + } //@} }; @@ -2837,7 +2989,7 @@ public: /// \returns the type referred to by this identifier, or NULL if the type /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName = false, TypeTy *ObjectType = 0); @@ -2847,7 +2999,7 @@ public: const CXXScopeSpec *SS); virtual TemplateNameKind isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 37acab9..12512f3 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -41,6 +41,7 @@ class AttributeList { unsigned NumArgs; AttributeList *Next; bool DeclspecAttribute, CXX0XAttribute; + mutable bool Invalid; /// True if already diagnosed as invalid. AttributeList(const AttributeList &); // DO NOT IMPLEMENT void operator=(const AttributeList &); // DO NOT IMPLEMENT public: @@ -128,6 +129,9 @@ public: bool isDeclspecAttribute() const { return DeclspecAttribute; } bool isCXX0XAttribute() const { return CXX0XAttribute; } + bool isInvalid() const { return Invalid; } + void setInvalid(bool b = true) const { Invalid = b; } + Kind getKind() const { return getKind(getName()); } static Kind getKind(const IdentifierInfo *Name); diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index f6f1eb9..9c19a67 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -27,9 +27,18 @@ namespace clang { class Preprocessor; class Declarator; struct TemplateIdAnnotation; - + /// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope -/// specifier. +/// specifier. These can be in 3 states: +/// 1) Not present, identified by isEmpty() +/// 2) Present, identified by isNotEmpty() +/// 2.a) Valid, idenified by isValid() +/// 2.b) Invalid, identified by isInvalid(). +/// +/// isSet() is deprecated because it mostly corresponded to "valid" but was +/// often used as if it meant "present". +/// +/// The actual scope is described by getScopeRep(). class CXXScopeSpec { SourceRange Range; void *ScopeRep; @@ -47,13 +56,18 @@ public: ActionBase::CXXScopeTy *getScopeRep() const { return ScopeRep; } void setScopeRep(ActionBase::CXXScopeTy *S) { ScopeRep = S; } + /// No scope specifier. bool isEmpty() const { return !Range.isValid(); } + /// A scope specifier is present, but may be valid or invalid. bool isNotEmpty() const { return !isEmpty(); } - /// isInvalid - An error occured during parsing of the scope specifier. + /// An error occured during parsing of the scope specifier. bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } + /// A scope specifier is present, and it refers to a real scope. + bool isValid() const { return isNotEmpty() && ScopeRep != 0; } - /// isSet - A scope specifier was resolved to a valid C++ scope. + /// Deprecated. Some call sites intend isNotEmpty() while others intend + /// isValid(). bool isSet() const { return ScopeRep != 0; } void clear() { @@ -68,8 +82,9 @@ public: class DeclSpec { public: // storage-class-specifier + // Note: The order of these enumerators is important for diagnostics. enum SCS { - SCS_unspecified, + SCS_unspecified = 0, SCS_typedef, SCS_extern, SCS_static, @@ -171,6 +186,8 @@ private: // constexpr-specifier bool Constexpr_specified : 1; + /*SCS*/unsigned StorageClassSpecAsWritten : 3; + /// TypeRep - This contains action-specific information about a specific TST. /// For example, for a typedef or struct, it might contain the declaration for /// these. @@ -203,6 +220,9 @@ private: WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); + void SaveStorageSpecifierAsWritten() { + StorageClassSpecAsWritten = StorageClassSpec; + } DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT void operator=(const DeclSpec&); // DO NOT IMPLEMENT @@ -224,6 +244,7 @@ public: FS_explicit_specified(false), Friend_specified(false), Constexpr_specified(false), + StorageClassSpecAsWritten(SCS_unspecified), TypeRep(0), AttrList(0), ProtocolQualifiers(0), @@ -321,6 +342,10 @@ public: /// unsigned getParsedSpecifiers() const; + SCS getStorageClassSpecAsWritten() const { + return (SCS)StorageClassSpecAsWritten; + } + /// isEmpty - Return true if this declaration specifier is completely empty: /// no tokens were parsed in the production of it. bool isEmpty() const { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9a4634a..42a41d6 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -41,6 +41,29 @@ public: virtual void print(llvm::raw_ostream &OS) const; }; +/// PrecedenceLevels - These are precedences for the binary/ternary +/// operators in the C99 grammar. These have been named to relate +/// with the C99 grammar productions. Low precedences numbers bind +/// more weakly than high numbers. +namespace prec { + enum Level { + Unknown = 0, // Not binary operator. + Comma = 1, // , + Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= + Conditional = 3, // ? + LogicalOr = 4, // || + LogicalAnd = 5, // && + InclusiveOr = 6, // | + ExclusiveOr = 7, // ^ + And = 8, // & + Equality = 9, // ==, != + Relational = 10, // >=, <=, >, < + Shift = 11, // <<, >> + Additive = 12, // -, + + Multiplicative = 13, // *, /, % + PointerToMember = 14 // .*, ->* + }; +} /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has @@ -460,9 +483,11 @@ private: //===--------------------------------------------------------------------===// // Diagnostic Emission and Error recovery. +public: DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); +private: void SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange); @@ -771,9 +796,15 @@ private: const ParsedTemplateInfo &TemplateInfo); void ParseLexedMethodDeclarations(ParsingClass &Class); void ParseLexedMethodDefs(ParsingClass &Class); + bool ConsumeAndStoreUntil(tok::TokenKind T1, + CachedTokens &Toks, + bool StopAtSemi = true, + bool ConsumeFinalToken = true) { + return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken); + } bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, - tok::TokenKind EarlyAbortIf = tok::unknown, + bool StopAtSemi = true, bool ConsumeFinalToken = true); //===--------------------------------------------------------------------===// @@ -846,7 +877,7 @@ private: //===--------------------------------------------------------------------===// // C99 6.5: Expressions. - + OwningExprResult ParseExpression(); OwningExprResult ParseConstantExpression(); // Expr that doesn't include commas. @@ -857,7 +888,7 @@ private: OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS, - unsigned MinPrec); + prec::Level MinPrec); OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, @@ -954,6 +985,8 @@ private: // C++ 5.2.3: Explicit type conversion (functional notation) OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); + bool isCXXSimpleTypeSpecifier() const; + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. @@ -998,18 +1031,6 @@ private: //===--------------------------------------------------------------------===// // Objective-C Expressions - - bool isTokObjCMessageIdentifierReceiver() const { - if (!Tok.is(tok::identifier)) - return false; - - IdentifierInfo *II = Tok.getIdentifierInfo(); - if (Actions.getTypeName(*II, Tok.getLocation(), CurScope)) - return true; - - return II == Ident_super; - } - OwningExprResult ParseObjCAtExpression(SourceLocation AtLocation); OwningExprResult ParseObjCStringLiteral(SourceLocation AtLoc); OwningExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); @@ -1017,12 +1038,13 @@ private: OwningExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); OwningExprResult ParseObjCMessageExpression(); OwningExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, - SourceLocation NameLoc, - IdentifierInfo *ReceiverName, + SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr); OwningExprResult ParseAssignmentExprWithObjCMessageExprStart( - SourceLocation LBracloc, SourceLocation NameLoc, - IdentifierInfo *ReceiverName, ExprArg ReceiverExpr); + SourceLocation LBracloc, SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr); + bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr); //===--------------------------------------------------------------------===// // C99 6.8: Statements and Blocks. @@ -1354,7 +1376,7 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. TypeResult ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS = 0); + CXXScopeSpec *SS = 0); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index c9825f6..d7a0e35 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -52,8 +52,8 @@ public: /// BlockScope - This is a scope that corresponds to a block object. /// Blocks serve as top-level scopes for some objects like labels, they - /// also prevent things like break and continue. BlockScopes have the - /// other flags set as well. + /// also prevent things like break and continue. BlockScopes always have + /// the FnScope, BreakScope, ContinueScope, and DeclScope flags set as well. BlockScope = 0x40, /// TemplateParamScope - This is a scope that corresponds to the @@ -68,7 +68,15 @@ public: /// AtCatchScope - This is a scope that corresponds to the Objective-C /// @catch statement. - AtCatchScope = 0x200 + AtCatchScope = 0x200, + + /// ObjCMethodScope - This scope corresponds to an Objective-C method body. + /// It always has FnScope and DeclScope set as well. + ObjCMethodScope = 0x400, + + /// ElseScope - This scoep corresponds to an 'else' scope of an if/then/else + /// statement. + ElseScope = 0x800 }; private: /// The parent scope for this scope. This is null for the translation-unit @@ -77,15 +85,11 @@ private: /// Depth - This is the depth of this scope. The translation-unit scope has /// depth 0. - unsigned Depth : 16; + unsigned short Depth; /// Flags - This contains a set of ScopeFlags, which indicates how the scope /// interrelates with other control flow statements. - unsigned Flags : 10; - - /// WithinElse - Whether this scope is part of the "else" branch in - /// its parent ControlScope. - bool WithinElse : 1; + unsigned short Flags; /// FnParent - If this scope has a parent scope that is a function body, this /// pointer is non-null and points to it. This is used for label processing. @@ -140,6 +144,7 @@ public: /// getFlags - Return the flags for this scope. /// unsigned getFlags() const { return Flags; } + void setFlags(unsigned F) { Flags = F; } /// isBlockScope - Return true if this scope does not correspond to a /// closure. @@ -233,6 +238,17 @@ public: } return false; } + + /// isInObjcMethodScope - Return true if this scope is, or is contained in, an + /// Objective-C method body. Note that this method is not constant time. + bool isInObjcMethodScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } /// isTemplateParamScope - Return true if this scope is a C++ /// template parameter scope. @@ -251,12 +267,6 @@ public: return getFlags() & Scope::AtCatchScope; } - /// isWithinElse - Whether we are within the "else" of the - /// ControlParent (if any). - bool isWithinElse() const { return WithinElse; } - - void setWithinElse(bool WE) { WithinElse = WE; } - typedef UsingDirectivesTy::iterator udir_iterator; typedef UsingDirectivesTy::const_iterator const_udir_iterator; @@ -286,7 +296,6 @@ public: AnyParent = Parent; Depth = AnyParent ? AnyParent->Depth+1 : 0; Flags = ScopeFlags; - WithinElse = false; if (AnyParent) { FnParent = AnyParent->FnParent; diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h index 1692180..adda866 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -16,18 +16,20 @@ #define LLVM_CLANG_REWRITER_H #include "clang/Basic/SourceLocation.h" +#include "clang/Rewrite/DeltaTree.h" #include "clang/Rewrite/RewriteRope.h" -#include -#include +#include "llvm/ADT/StringRef.h" #include +#include #include -#include "clang/Rewrite/DeltaTree.h" -#include "llvm/ADT/StringRef.h" +#include + +namespace llvm { class raw_ostream; } namespace clang { - class SourceManager; class LangOptions; class Rewriter; + class SourceManager; class Stmt; /// RewriteBuffer - As code is rewritten, SourceBuffer's from the original @@ -53,6 +55,8 @@ public: iterator end() const { return Buffer.end(); } unsigned size() const { return Buffer.size(); } + llvm::raw_ostream &write(llvm::raw_ostream &) const; + /// RemoveText - Remove the specified text. void RemoveText(unsigned OrigOffset, unsigned Size); @@ -125,6 +129,8 @@ class Rewriter { const LangOptions *LangOpts; std::map RewriteBuffers; public: + typedef std::map::iterator buffer_iterator; + explicit Rewriter(SourceManager &SM, const LangOptions &LO) : SourceMgr(&SM), LangOpts(&LO) {} explicit Rewriter() : SourceMgr(0), LangOpts(0) {} @@ -192,6 +198,12 @@ public: /// could not be rewritten, or false if successful. bool ReplaceStmt(Stmt *From, Stmt *To); + /// getEditBuffer - This is like getRewriteBufferFor, but always returns a + /// buffer, and allows you to write on it directly. This is useful if you + /// want efficient low-level access to apis for scribbling on one specific + /// FileID's buffer. + RewriteBuffer &getEditBuffer(FileID FID); + /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. /// If no modification has been made to it, return null. const RewriteBuffer *getRewriteBufferFor(FileID FID) const { @@ -200,11 +212,9 @@ public: return I == RewriteBuffers.end() ? 0 : &I->second; } - /// getEditBuffer - This is like getRewriteBufferFor, but always returns a - /// buffer, and allows you to write on it directly. This is useful if you - /// want efficient low-level access to apis for scribbling on one specific - /// FileID's buffer. - RewriteBuffer &getEditBuffer(FileID FID); + // Iterators over rewrite buffers. + buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } + buffer_iterator buffer_end() { return RewriteBuffers.end(); } private: unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 50a6e0a..731d5e0 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -48,7 +48,8 @@ const APValue &APValue::operator=(const APValue &RHS) { else if (isFloat()) setFloat(RHS.getFloat()); else if (isVector()) - setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength()); + setVector(((const Vec *)(const char *)RHS.Data)->Elts, + RHS.getVectorLength()); else if (isComplexInt()) setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c77acce..eea727d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -41,6 +41,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, Builtin::Context &builtins, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + NSConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), @@ -325,55 +326,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } -CXXMethodVector::iterator CXXMethodVector::begin() const { - if ((Storage & 0x01) == 0) - return reinterpret_cast(&Storage); - - vector_type *Vec = reinterpret_cast(Storage & ~0x01); - return &Vec->front(); -} - -CXXMethodVector::iterator CXXMethodVector::end() const { - if ((Storage & 0x01) == 0) { - if (Storage == 0) - return reinterpret_cast(&Storage); - - return reinterpret_cast(&Storage) + 1; - } - - vector_type *Vec = reinterpret_cast(Storage & ~0x01); - return &Vec->front() + Vec->size(); -} - -void CXXMethodVector::push_back(const CXXMethodDecl *Method) { - if (Storage == 0) { - // 0 -> 1 element. - Storage = reinterpret_cast(Method); - return; - } - - vector_type *Vec; - if ((Storage & 0x01) == 0) { - // 1 -> 2 elements. Allocate a new vector and push the element into that - // vector. - Vec = new vector_type; - Vec->push_back(reinterpret_cast(Storage)); - Storage = reinterpret_cast(Vec) | 0x01; - } else - Vec = reinterpret_cast(Storage & ~0x01); - - // Add the new method to the vector. - Vec->push_back(Method); -} - -void CXXMethodVector::Destroy() { - if (Storage & 0x01) - delete reinterpret_cast(Storage & ~0x01); - - Storage = 0; -} - - ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap::const_iterator Pos @@ -515,7 +467,7 @@ ASTContext::getTypeInfo(const Type *T) { Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. - if (VT->getNumElements() & (VT->getNumElements()-1)) { + if (Align & (Align-1)) { Align = llvm::NextPowerOf2(Align); Width = llvm::RoundUpToAlignment(Width, Align); } @@ -701,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast(T)->getNamedType().getTypePtr()); - case Type::InjectedClassName: - return getTypeInfo(cast(T) - ->getUnderlyingType().getTypePtr()); - case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); @@ -833,9 +781,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, CollectInheritedProtocols(SD, Protocols); SD = SD->getSuperClass(); } - return; - } - if (const ObjCCategoryDecl *OC = dyn_cast(CDecl)) { + } else if (const ObjCCategoryDecl *OC = dyn_cast(CDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -844,9 +790,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; - } - if (const ObjCProtocolDecl *OP = dyn_cast(CDecl)) { + } else if (const ObjCProtocolDecl *OP = dyn_cast(CDecl)) { for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -855,26 +799,20 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; } } unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; // Count ivars declared in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { - for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); I != E; ++I) { - ++count; - } - } - + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) + count += CDecl->ivar_size(); + // Count ivar defined in this class's implementation. This // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) - for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); I != E; ++I) - ++count; + count += ImplDecl->ivar_size(); + return count; } @@ -998,6 +936,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { ASTRecordLayoutBuilder::ComputeLayout(*this, D); ASTRecordLayouts[D] = NewEntry; + if (getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::errs()); + } + return *NewEntry; } @@ -1735,8 +1678,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa(Decl->TypeForDecl)); } else { - Decl->TypeForDecl = new (*this, TypeAlignment) - InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal()); + Decl->TypeForDecl = + new (*this, TypeAlignment) InjectedClassNameType(Decl, TST); Types.push_back(Decl->TypeForDecl); } return QualType(Decl->TypeForDecl, 0); @@ -1867,7 +1810,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { unsigned NumArgs = Args.size(); llvm::SmallVector ArgVec; @@ -1875,17 +1819,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); - return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon); + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, + Canon, IsCurrentInstantiation); } QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { if (!Canon.isNull()) Canon = getCanonicalType(Canon); else { + assert(!IsCurrentInstantiation && + "current-instantiation specializations should always " + "have a canonical type"); + // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); llvm::SmallVector CanonArgs; @@ -1896,7 +1846,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, + TemplateSpecializationType::Profile(ID, CanonTemplate, false, CanonArgs.data(), NumArgs, *this); void *InsertPos = 0; @@ -1908,7 +1858,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), TypeAlignment); - Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, + Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false, CanonArgs.data(), NumArgs, Canon); Types.push_back(Spec); @@ -1928,7 +1878,9 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, sizeof(TemplateArgument) * NumArgs), TypeAlignment); TemplateSpecializationType *Spec - = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs, + = new (Mem) TemplateSpecializationType(*this, Template, + IsCurrentInstantiation, + Args, NumArgs, Canon); Types.push_back(Spec); @@ -2108,10 +2060,10 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, if (!InterfaceT.isCanonical() || !areSortedAndUniqued(Protocols, NumProtocols)) { if (!areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector Sorted(NumProtocols); + llvm::SmallVector Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); SortAndUniqueProtocols(&Sorted[0], UniqueCount); Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), @@ -2154,8 +2106,8 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, // Sort the protocol list alphabetically to canonicalize it. QualType Canonical; if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector Sorted(NumProtocols); - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); + llvm::SmallVector Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; SortAndUniqueProtocols(&Sorted[0], UniqueCount); @@ -2634,14 +2586,9 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { QualType ASTContext::getBaseElementType(QualType QT) { QualifierCollector Qs; - while (true) { - const Type *UT = Qs.strip(QT); - if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { - QT = AT->getElementType(); - } else { - return Qs.apply(QT); - } - } + while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0))) + QT = AT->getElementType(); + return Qs.apply(QT); } QualType ASTContext::getBaseElementType(const ArrayType *AT) { @@ -2886,6 +2833,7 @@ QualType ASTContext::getCFConstantStringType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -2901,6 +2849,46 @@ void ASTContext::setCFConstantStringType(QualType T) { CFConstantStringTypeDecl = Rec->getDecl(); } +// getNSConstantStringType - Return the type used for constant NSStrings. +QualType ASTContext::getNSConstantStringType() { + if (!NSConstantStringTypeDecl) { + NSConstantStringTypeDecl = + CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__builtin_NSString")); + NSConstantStringTypeDecl->startDefinition(); + + QualType FieldTypes[3]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.withConst()); + // const char *str; + FieldTypes[1] = getPointerType(CharTy.withConst()); + // unsigned int length; + FieldTypes[2] = UnsignedIntTy; + + // Create fields + for (unsigned i = 0; i < 3; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + Field->setAccess(AS_public); + NSConstantStringTypeDecl->addDecl(Field); + } + + NSConstantStringTypeDecl->completeDefinition(); + } + + return getTagDeclType(NSConstantStringTypeDecl); +} + +void ASTContext::setNSConstantStringType(QualType T) { + const RecordType *Rec = T->getAs(); + assert(Rec && "Invalid NSConstantStringType"); + NSConstantStringTypeDecl = Rec->getDecl(); +} + QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = @@ -2923,6 +2911,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } @@ -2960,6 +2949,7 @@ QualType ASTContext::getBlockDescriptorType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3008,6 +2998,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3085,6 +3076,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3129,6 +3121,7 @@ QualType ASTContext::getBlockParmType( &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3149,6 +3142,7 @@ QualType ASTContext::getBlockParmType( FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), Name, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3192,7 +3186,7 @@ std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } -/// getObjCEncodingForBlockDecl - Return the encoded type for this method +/// getObjCEncodingForBlockDecl - Return the encoded type for this block /// declaration. void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) { @@ -3207,7 +3201,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, SourceLocation Loc; CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); CharUnits ParmOffset = PtrSize; - for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); @@ -3258,7 +3252,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // their size. CharUnits ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); assert (sz.isPositive() && @@ -3272,7 +3266,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Argument types. ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = @@ -3494,13 +3488,18 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } + // encoding for pointer or r3eference types. + QualType PointeeTy; if (const PointerType *PT = T->getAs()) { if (PT->isObjCSelType()) { S += ':'; return; } - QualType PointeeTy = PT->getPointeeType(); - + PointeeTy = PT->getPointeeType(); + } + else if (const ReferenceType *RT = T->getAs()) + PointeeTy = RT->getPointeeType(); + if (!PointeeTy.isNull()) { bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -3524,12 +3523,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Another legacy compatibility encoding. Some ObjC qualifier and type // combinations need to be rearranged. // Rewrite "in const" from "nr" to "rn" - const char * s = S.c_str(); - int len = S.length(); - if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') { - std::string replace = "rn"; - S.replace(S.end()-2, S.end(), replace); - } + if (llvm::StringRef(S).endswith("nr")) + S.replace(S.end()-2, S.end(), "rn"); } if (PointeeTy->isCharType()) { @@ -3559,7 +3554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, NULL); return; } - + if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast(T->getCanonicalTypeInternal())) { @@ -4136,15 +4131,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { - if (RHSOPT->isObjCBuiltinType() || - LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType()) + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); } - if (RHSOPT->isObjCQualifiedIdType()) + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); @@ -4190,7 +4184,8 @@ void getIntersectionOfProtocols(ASTContext &Context, unsigned RHSNumProtocols = RHS->getNumProtocols(); if (RHSNumProtocols > 0) { - ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin(); + ObjCProtocolDecl **RHSProtocols = + const_cast(RHS->qual_begin()); for (unsigned i = 0; i < RHSNumProtocols; ++i) if (InheritedProtocolSet.count(RHSProtocols[i])) IntersectionOfProtocols.push_back(RHSProtocols[i]); diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 866b7f7..e4cd2a9 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, continue; } - // ...or an injected class name... - if (isa(Ty)) { - QT = cast(Ty)->desugar(); - continue; - } - // ...or a substituted template type parameter. if (isa(Ty)) { QT = cast(Ty)->desugar(); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 5dfb99f..ae09d79 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const InjectedClassNameType *Inj1 = cast(T1); const InjectedClassNameType *Inj2 = cast(T2); if (!IsStructurallyEquivalent(Context, - Inj1->getUnderlyingType(), - Inj2->getUnderlyingType())) + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) return false; break; } @@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { for (DeclContext::lookup_result Lookup = DC->lookup(Name); Lookup.first != Lookup.second; ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; if (NamespaceDecl *FoundNS = dyn_cast(*Lookup.first)) { @@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { } if (!ConflictingDecls.empty()) { - Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(), ConflictingDecls.size()); } @@ -1905,6 +1905,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc, Name, T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); } @@ -2125,7 +2126,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, - D->getStorageClass()); + D->getStorageClass(), + D->getStorageClassAsWritten()); // Import the qualifier, if any. if (D->getQualifier()) { NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); @@ -2197,6 +2199,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), /*FIXME: Default argument*/ 0); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); @@ -2312,7 +2315,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ToMethod->addDecl(ToParams[I]); } ToMethod->setMethodParams(Importer.getToContext(), - ToParams.data(), ToParams.size()); + ToParams.data(), ToParams.size(), + ToParams.size()); ToMethod->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToMethod); @@ -2881,8 +2885,11 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { if (!SubExpr) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), - SubExpr, + SubExpr, BasePath, E->isLvalueCast()); } @@ -2899,8 +2906,11 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { if (!TInfo && E->getTypeInfoAsWritten()) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(), - SubExpr, TInfo, + SubExpr, BasePath, TInfo, Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc())); } @@ -3086,7 +3096,7 @@ FileID ASTImporter::Import(FileID FromID) { FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags()); + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM); llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dc9fb59..ffe4967 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -25,7 +25,6 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Parse/DeclSpec.h" #include "llvm/Support/ErrorHandling.h" -#include using namespace clang; @@ -286,6 +285,28 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { } Linkage NamedDecl::getLinkage() const { + + // Objective-C: treat all Objective-C declarations as having external + // linkage. + switch (getKind()) { + default: + break; + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCClass: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCForwardProtocol: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCIvar: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + return ExternalLinkage; + } + // Handle linkage for namespace-scope names. if (getDeclContext()->getLookupContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) @@ -354,88 +375,79 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { - // FIXME: Collect contexts, then accumulate names to avoid unnecessary - // std::string thrashing. - std::vector Names; - std::string QualName; const DeclContext *Ctx = getDeclContext(); if (Ctx->isFunctionOrMethod()) return getNameAsString(); - while (Ctx) { + typedef llvm::SmallVector ContextsTy; + ContextsTy Contexts; + + // Collect contexts. + while (Ctx && isa(Ctx)) { + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + }; + + std::string QualName; + llvm::raw_string_ostream OS(QualName); + + for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend(); + I != E; ++I) { if (const ClassTemplateSpecializationDecl *Spec - = dyn_cast(Ctx)) { + = dyn_cast(*I)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), P); - Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); - } else if (const NamespaceDecl *ND = dyn_cast(Ctx)) { + OS << Spec->getName() << TemplateArgsStr; + } else if (const NamespaceDecl *ND = dyn_cast(*I)) { if (ND->isAnonymousNamespace()) - Names.push_back(""); + OS << ""; else - Names.push_back(ND->getNameAsString()); - } else if (const RecordDecl *RD = dyn_cast(Ctx)) { - if (!RD->getIdentifier()) { - std::string RecordString = "getKindName(); - RecordString += ">"; - Names.push_back(RecordString); - } else { - Names.push_back(RD->getNameAsString()); - } - } else if (const FunctionDecl *FD = dyn_cast(Ctx)) { - std::string Proto = FD->getNameAsString(); - + OS << ND; + } else if (const RecordDecl *RD = dyn_cast(*I)) { + if (!RD->getIdentifier()) + OS << "getKindName() << '>'; + else + OS << RD; + } else if (const FunctionDecl *FD = dyn_cast(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) FT = dyn_cast(FD->getType()->getAs()); - Proto += "("; + OS << FD << '('; if (FT) { - llvm::raw_string_ostream POut(Proto); unsigned NumParams = FD->getNumParams(); for (unsigned i = 0; i < NumParams; ++i) { if (i) - POut << ", "; + OS << ", "; std::string Param; FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); - POut << Param; + OS << Param; } if (FT->isVariadic()) { if (NumParams > 0) - POut << ", "; - POut << "..."; + OS << ", "; + OS << "..."; } } - Proto += ")"; - - Names.push_back(Proto); - } else if (const NamedDecl *ND = dyn_cast(Ctx)) - Names.push_back(ND->getNameAsString()); - else - break; - - Ctx = Ctx->getParent(); + OS << ')'; + } else { + OS << cast(*I); + } + OS << "::"; } - std::vector::reverse_iterator - I = Names.rbegin(), - End = Names.rend(); - - for (; I!=End; ++I) - QualName += *I + "::"; - if (getDeclName()) - QualName += getNameAsString(); + OS << this; else - QualName += ""; + OS << ""; - return QualName; + return OS.str(); } bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { @@ -494,6 +506,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { } } +bool NamedDecl::isCXXInstanceMember() const { + assert(isCXXClassMember() && + "checking whether non-member is instance member"); + + const NamedDecl *D = this; + if (isa(D)) + D = cast(D)->getTargetDecl(); + + if (isa(D)) + return true; + if (isa(D)) + return cast(D)->isInstance(); + if (isa(D)) + return cast(cast(D) + ->getTemplatedDecl())->isInstance(); + return false; +} + //===----------------------------------------------------------------------===// // DeclaratorDecl Implementation //===----------------------------------------------------------------------===// @@ -568,8 +598,8 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S) { - return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S); + StorageClass S, StorageClass SCAsWritten) { + return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } void VarDecl::Destroy(ASTContext& C) { @@ -793,8 +823,10 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, + S, SCAsWritten, DefArg); } Expr *ParmVarDecl::getDefaultArg() { @@ -874,6 +906,12 @@ void FunctionDecl::getNameForDiagnostic(std::string &S, } +bool FunctionDecl::isVariadic() const { + if (const FunctionProtoType *FT = getType()->getAs()) + return FT->isVariadic(); + return false; +} + Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { if (I->Body) { @@ -1291,6 +1329,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, } } +void +FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs) { + assert(TemplateOrSpecialization.isNull()); + size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); + Size += Templates.size() * sizeof(FunctionTemplateDecl*); + Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc); + void *Buffer = Context.Allocate(Size); + DependentFunctionTemplateSpecializationInfo *Info = + new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, + TemplateArgs); + TemplateOrSpecialization = Info; +} + +DependentFunctionTemplateSpecializationInfo:: +DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, + const TemplateArgumentListInfo &TArgs) + : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + + d.NumTemplates = Ts.size(); + d.NumArgs = TArgs.size(); + + FunctionTemplateDecl **TsArray = + const_cast(getTemplates()); + for (unsigned I = 0, E = Ts.size(); I != E; ++I) + TsArray[I] = cast(Ts[I]->getUnderlyingDecl()); + + TemplateArgumentLoc *ArgsArray = + const_cast(getTemplateArgs()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) + new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); +} + TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. @@ -1407,6 +1479,10 @@ void TagDecl::startDefinition() { if (TagType *TagT = const_cast(TypeForDecl->getAs())) { TagT->decl.setPointer(this); TagT->decl.setInt(1); + } else if (InjectedClassNameType *Injected + = const_cast( + TypeForDecl->getAs())) { + Injected->Decl = cast(this); } if (isa(this)) { @@ -1428,6 +1504,11 @@ void TagDecl::completeDefinition() { assert(TagT->decl.getPointer() == this && "Attempt to redefine a tag definition?"); TagT->decl.setInt(0); + } else if (InjectedClassNameType *Injected + = const_cast( + TypeForDecl->getAs())) { + assert(Injected->Decl == this && + "Attempt to redefine a class template definition?"); } } @@ -1606,10 +1687,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass S, bool isInline, - bool hasWrittenPrototype) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); + StorageClass S, StorageClass SCAsWritten, + bool isInline, bool hasWrittenPrototype) { + FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, + S, SCAsWritten, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index c693e15..b5aec0c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -231,24 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConstructor: case CXXDestructor: case CXXConversion: - case Typedef: case EnumConstant: case Var: case ImplicitParam: case ParmVar: case NonTypeTemplateParm: case ObjCMethod: - case ObjCContainer: - case ObjCInterface: case ObjCProperty: - case ObjCCompatibleAlias: return IDNS_Ordinary; + case ObjCCompatibleAlias: + case ObjCInterface: + return IDNS_Ordinary | IDNS_Type; + + case Typedef: + case UnresolvedUsingTypename: + case TemplateTypeParm: + return IDNS_Ordinary | IDNS_Type; + case UsingShadow: return 0; // we'll actually overwrite this later case UnresolvedUsingValue: - case UnresolvedUsingTypename: return IDNS_Ordinary | IDNS_Using; case Using: @@ -257,13 +261,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProtocol: return IDNS_ObjCProtocol; - case ObjCImplementation: - return IDNS_ObjCImplementation; - - case ObjCCategory: - case ObjCCategoryImpl: - return IDNS_ObjCCategoryName; - case Field: case ObjCAtDefsField: case ObjCIvar: @@ -272,16 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Record: case CXXRecord: case Enum: - case TemplateTypeParm: - return IDNS_Tag; + return IDNS_Tag | IDNS_Type; case Namespace: - case Template: + case NamespaceAlias: + return IDNS_Namespace; + case FunctionTemplate: + return IDNS_Ordinary; + case ClassTemplate: case TemplateTemplateParm: - case NamespaceAlias: - return IDNS_Tag | IDNS_Ordinary; + return IDNS_Ordinary | IDNS_Tag | IDNS_Type; // Never have names. case Friend: @@ -295,10 +294,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Block: case TranslationUnit: - // Aren't looked up? case UsingDirective: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: + case ObjCImplementation: + case ObjCCategory: + case ObjCCategoryImpl: + // Never looked up by name. return 0; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 94ed85c..68f4a82 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -587,9 +587,9 @@ CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isStatic, bool isInline) { + bool isStatic, StorageClass SCAsWritten, bool isInline) { return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, - isStatic, isInline); + isStatic, SCAsWritten, isInline); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -633,6 +633,27 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; } +bool CXXMethodDecl::isCopyAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared copy assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of + // type X, X&, const X&, volatile X& or const volatile X&. + if (/*operator=*/getOverloadedOperator() != OO_Equal || + /*non-static*/ isStatic() || + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || + /*exactly one parameter*/getNumParams() != 1) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (const LValueReferenceType *Ref = ParamType->getAs()) + ParamType = Ref->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && @@ -659,15 +680,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTypeDeclType(getParent()); - - // Aesthetically we prefer not to synthesize a type as the - // InjectedClassNameType of a template pattern: injected class names - // are printed without template arguments, which might - // surprise/confuse/distract our poor users if they didn't - // explicitly write one. - if (isa(ClassTy)) - ClassTy = cast(ClassTy)->getUnderlyingType(); - ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); @@ -686,9 +698,9 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, + TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual), LParenLoc(L), RParenLoc(R) { } @@ -745,11 +757,12 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isExplicit, - bool isInline, bool isImplicitlyDeclared) { + bool isInline, + bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared); + return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, + isInline, isImplicitlyDeclared); } bool CXXConstructorDecl::isDefaultConstructor() const { @@ -848,8 +861,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, - isImplicitlyDeclared); + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } void diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 821e38b..dc4aacd 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -330,11 +330,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isInstance, bool isVariadic, bool isSynthesized, - ImplementationControl impControl) { + ImplementationControl impControl, + unsigned numSelectorArgs) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, - isVariadic, isSynthesized, impControl); + isVariadic, isSynthesized, impControl, + numSelectorArgs); } void ObjCMethodDecl::Destroy(ASTContext &C) { @@ -841,6 +843,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCCategoryImplDecl *CID) { + OS << CID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCImplementationDecl //===----------------------------------------------------------------------===// @@ -853,6 +861,12 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCImplementationDecl *ID) { + OS << ID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCCompatibleAliasDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index a625865..53949247 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -301,17 +301,15 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { - Out << "enum " << D->getNameAsString() << " {\n"; + Out << "enum " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { Out << " {\n"; @@ -321,7 +319,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { } void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { - Out << D->getNameAsString(); + Out << D; if (Expr *Init = D->getInitExpr()) { Out << " = "; Init->printPretty(Out, Context, 0, Policy, Indentation); @@ -406,7 +404,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << ", "; if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); - Out << FD->getNameAsString(); + Out << FD; } else { Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } @@ -537,7 +535,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { - Out << "namespace " << D->getNameAsString() << " {\n"; + Out << "namespace " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } @@ -546,22 +544,20 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespaceAsWritten()->getNameAsString(); + Out << D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - Out << "namespace " << D->getNameAsString() << " = "; + Out << "namespace " << D << " = "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getAliasedNamespace()->getNameAsString(); + Out << D->getAliasedNamespace(); } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { // Print the base classes @@ -669,7 +665,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) { if (I != D->begin()) Out << ", "; - Out << I->getInterface()->getNameAsString(); + Out << I->getInterface(); } } @@ -688,8 +684,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { // FIXME: selector is missing here! pos = name.find_first_of(":", lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" - << (*PI)->getNameAsString(); + Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI; lastPos = pos + 1; } @@ -711,7 +706,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@implementation " << I << " : " << SID->getNameAsString(); + Out << "@implementation " << I << " : " << SID; else Out << "@implementation " << I; Out << "\n"; @@ -724,7 +719,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@interface " << I << " : " << SID->getNameAsString(); + Out << "@interface " << I << " : " << SID; else Out << "@interface " << I; @@ -733,7 +728,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { if (!Protocols.empty()) { for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); + Out << (I == Protocols.begin() ? '<' : ',') << *I; } if (!Protocols.empty()) @@ -744,8 +739,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << (*I)->getType().getAsString(Policy) - << ' ' << (*I)->getNameAsString() << ";\n"; + Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -762,20 +756,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; - Out << (*I)->getNameAsString(); + Out << *I; } } void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - Out << "@protocol " << PID->getNameAsString() << '\n'; + Out << "@protocol " << PID << '\n'; VisitDeclContext(PID, false); Out << "@end"; } void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { - Out << "@implementation " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -783,9 +775,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -793,8 +783,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID->getNameAsString() - << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; + Out << "@compatibility_alias " << AID + << ' ' << AID->getClassInterface() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -854,8 +844,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { } Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) - << ' ' << PDecl->getNameAsString(); + Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { @@ -863,28 +852,28 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { Out << "@synthesize "; else Out << "@dynamic "; - Out << PID->getPropertyDecl()->getNameAsString(); + Out << PID->getPropertyDecl(); if (PID->getPropertyIvarDecl()) - Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); + Out << '=' << PID->getPropertyIvarDecl(); } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; D->getTargetNestedNameDecl()->print(Out, Policy); - Out << D->getNameAsString(); + Out << D; } void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index b449398..c498dea 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -178,6 +178,20 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +void ClassTemplateDecl::getPartialSpecializations( + llvm::SmallVectorImpl &PS) { + llvm::FoldingSet &PartialSpecs + = CommonPtr->PartialSpecializations; + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSet::iterator + P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = &*P; + } +} + ClassTemplatePartialSpecializationDecl * ClassTemplateDecl::findPartialSpecialization(QualType T) { ASTContext &Context = getASTContext(); @@ -186,7 +200,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { for (partial_spec_iterator P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (Context.hasSameType(Context.getTypeDeclType(&*P), T)) + if (Context.hasSameType(P->getInjectedSpecializationType(), T)) return &*P; } @@ -456,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl) { + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) { unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; for (unsigned I = 0; I != N; ++I) @@ -468,7 +483,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, SpecializedTemplate, Builder, ClonedArgs, N, - PrevDecl); + PrevDecl, + SequenceNumber); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getInjectedClassNameType(Result, CanonInjectedType); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 19b58bc..4f85fca 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -18,7 +18,7 @@ #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include +#include "llvm/Support/raw_ostream.h" using namespace clang; namespace clang { @@ -202,32 +202,42 @@ bool DeclarationName::isDependentName() const { } std::string DeclarationName::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationName::printName(llvm::raw_ostream &OS) const { switch (getNameKind()) { case Identifier: if (const IdentifierInfo *II = getAsIdentifierInfo()) - return II->getName(); - return ""; + OS << II->getName(); + return; case ObjCZeroArgSelector: case ObjCOneArgSelector: case ObjCMultiArgSelector: - return getObjCSelector().getAsString(); + OS << getObjCSelector().getAsString(); + return; case CXXConstructorName: { QualType ClassType = getCXXNameType(); if (const RecordType *ClassRec = ClassType->getAs()) - return ClassRec->getDecl()->getNameAsString(); - return ClassType.getAsString(); + OS << ClassRec->getDecl(); + else + OS << ClassType.getAsString(); + return; } case CXXDestructorName: { - std::string Result = "~"; + OS << '~'; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXOperatorName: { @@ -240,32 +250,32 @@ std::string DeclarationName::getAsString() const { const char *OpName = OperatorNames[getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); - std::string Result = "operator"; + OS << "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') - Result += ' '; - Result += OpName; - return Result; + OS << ' '; + OS << OpName; + return; } - case CXXLiteralOperatorName: { - return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName()); - } + case CXXLiteralOperatorName: + OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); + return; case CXXConversionFunctionName: { - std::string Result = "operator "; + OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXUsingDirective: - return ""; + OS << ""; + return; } assert(false && "Unexpected declaration name kind"); - return ""; } QualType DeclarationName::getCXXNameType() const { @@ -369,7 +379,8 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - fprintf(stderr, "%s\n", getAsString().c_str()); + printName(llvm::errs()); + llvm::errs() << '\n'; } DeclarationNameTable::DeclarationNameTable() { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index ae4bc8c..00662a5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -27,6 +27,65 @@ #include using namespace clang; +/// isKnownToHaveBooleanValue - Return true if this is an integer expression +/// that is known to return 0 or 1. This happens for _Bool/bool expressions +/// but also int expressions which are produced by things like comparisons in +/// C. +bool Expr::isKnownToHaveBooleanValue() const { + // If this value has _Bool type, it is obvious 0/1. + if (getType()->isBooleanType()) return true; + // If this is a non-scalar-integer type, we don't care enough to try. + if (!getType()->isIntegralType()) return false; + + if (const ParenExpr *PE = dyn_cast(this)) + return PE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const UnaryOperator *UO = dyn_cast(this)) { + switch (UO->getOpcode()) { + case UnaryOperator::Plus: + case UnaryOperator::Extension: + return UO->getSubExpr()->isKnownToHaveBooleanValue(); + default: + return false; + } + } + + if (const CastExpr *CE = dyn_cast(this)) + return CE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const BinaryOperator *BO = dyn_cast(this)) { + switch (BO->getOpcode()) { + default: return false; + case BinaryOperator::LT: // Relational operators. + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: // Equality operators. + case BinaryOperator::NE: + case BinaryOperator::LAnd: // AND operator. + case BinaryOperator::LOr: // Logical OR operator. + return true; + + case BinaryOperator::And: // Bitwise AND operator. + case BinaryOperator::Xor: // Bitwise XOR operator. + case BinaryOperator::Or: // Bitwise OR operator. + // Handle things like (x==2)|(y==12). + return BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue(); + + case BinaryOperator::Comma: + case BinaryOperator::Assign: + return BO->getRHS()->isKnownToHaveBooleanValue(); + } + } + + if (const ConditionalOperator *CO = dyn_cast(this)) + return CO->getTrueExpr()->isKnownToHaveBooleanValue() && + CO->getFalseExpr()->isKnownToHaveBooleanValue(); + + return false; +} + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -231,14 +290,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { // For incorrect code, there might not be an ObjCInterfaceDecl. Do // a null check to avoid a crash. if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) - Out << ID->getNameAsString(); + Out << ID; if (const ObjCCategoryImplDecl *CID = - dyn_cast(MD->getDeclContext())) { - Out << '('; - Out << CID->getNameAsString(); - Out << ')'; - } + dyn_cast(MD->getDeclContext())) + Out << '(' << CID << ')'; + Out << ' '; Out << MD->getSelector().getAsString(); Out << ']'; @@ -492,17 +549,70 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } +OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, + TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, + exprsPtr, numExprs, RParenLoc); +} + +OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, + unsigned numComps, unsigned numExprs) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + return new (Mem) OffsetOfExpr(numComps, numExprs); +} + +OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) + : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false, + /*ValueDependent=*/tsi->getType()->isDependentType() || + hasAnyTypeDependentArguments(exprsPtr, numExprs) || + hasAnyValueDependentArguments(exprsPtr, numExprs)), + OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), + NumComps(numComps), NumExprs(numExprs) +{ + for(unsigned i = 0; i < numComps; ++i) { + setComponent(i, compsPtr[i]); + } + + for(unsigned i = 0; i < numExprs; ++i) { + setIndexExpr(i, exprsPtr[i]); + } +} + +IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { + assert(getKind() == Field || getKind() == Identifier); + if (getKind() == Field) + return getField()->getIdentifier(); + + return reinterpret_cast (Data & ~(uintptr_t)Mask); +} + MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, ValueDecl *memberdecl, - NamedDecl *founddecl, + DeclAccessPair founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); - bool hasQualOrFound = (qual != 0 || founddecl != memberdecl); + bool hasQualOrFound = (qual != 0 || + founddecl.getDecl() != memberdecl || + founddecl.getAccess() != memberdecl->getAccess()); if (hasQualOrFound) Size += sizeof(MemberNameQualifier); @@ -593,6 +703,12 @@ const char *CastExpr::getCastKindName() const { return 0; } +void CastExpr::DoDestroy(ASTContext &C) +{ + BasePath.Destroy(); + Expr::DoDestroy(C); +} + Expr *CastExpr::getSubExprAsWritten() { Expr *SubExpr = 0; CastExpr *E = this; @@ -720,10 +836,11 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(SourceLocation lbraceloc, +InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), false, false), + InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { @@ -734,24 +851,24 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc, ValueDependent = true; } - InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); + InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); } -void InitListExpr::reserveInits(unsigned NumInits) { +void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) - InitExprs.reserve(NumInits); + InitExprs.reserve(C, NumInits); } -void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { +void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx) - InitExprs[Idx]->Destroy(Context); - InitExprs.resize(NumInits, 0); + InitExprs[Idx]->Destroy(C); + InitExprs.resize(C, NumInits, 0); } -Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { +Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { - InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0); InitExprs.back() = expr; return 0; } @@ -835,19 +952,22 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, } case BinaryOperatorClass: { const BinaryOperator *BO = cast(this); - // Consider comma to have side effects if the LHS or RHS does. - if (BO->getOpcode() == BinaryOperator::Comma) { - // ((foo = ), 0) is an idiom for hiding the result (and - // lvalue-ness) of an assignment written in a macro. - if (IntegerLiteral *IE = - dyn_cast(BO->getRHS()->IgnoreParens())) - if (IE->getValue() == 0) - return false; - - return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || - BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + switch (BO->getOpcode()) { + default: + break; + // Consider ',', '||', '&&' to have side effects if the LHS or RHS does. + case BinaryOperator::Comma: + // ((foo = ), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } - if (BO->isAssignmentOp()) return false; Loc = BO->getOperatorLoc(); @@ -1219,11 +1339,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case ObjCPropertyRefExprClass: // FIXME: check if read-only property. return LV_Valid; - case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property. + case ObjCImplicitSetterGetterRefExprClass: + // FIXME: check if read-only property. return LV_Valid; case PredefinedExprClass: return LV_Valid; case UnresolvedLookupExprClass: + case UnresolvedMemberExprClass: return LV_Valid; case CXXDefaultArgExprClass: return cast(this)->getExpr()->isLvalue(Ctx); @@ -1821,7 +1943,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::AddrOf: case UnaryOperator::Deref: return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: case UnaryOperator::LNot: case UnaryOperator::Plus: @@ -1831,6 +1952,12 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::Imag: return CheckICE(Exp->getSubExpr(), Ctx); case UnaryOperator::OffsetOf: + break; + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { // Note that per C99, offsetof must be an ICE. And AFAIK, using // Evaluate matches the proposed gcc behavior for cases like // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect @@ -1838,7 +1965,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // array subscripts that aren't ICEs, and if the array subscripts // are ICEs, the value of the offsetof must be an integer constant. return CheckEvalInICE(E, Ctx); - } } case Expr::SizeOfAlignOfExprClass: { const SizeOfAlignOfExpr *Exp = cast(E); @@ -1936,7 +2062,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: - case Expr::CXXNamedCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: { @@ -1953,7 +2078,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // then only the true side is actually considered in an integer constant // expression, and it is fully evaluated. This is an important GNU // extension. See GCC PR38377 for discussion. - if (const CallExpr *CallCE = dyn_cast(Exp->getCond()->IgnoreParenCasts())) + if (const CallExpr *CallCE + = dyn_cast(Exp->getCond()->IgnoreParenCasts())) if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { Expr::EvalResult EVResult; if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || @@ -2176,101 +2302,156 @@ void ExtVectorElementExpr::getEncodedElementAccess( } } -// constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, - Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), - MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = receiver; - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -// FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, - ObjCMethodDecl *mproto, SourceLocation LBrac, - SourceLocation RBrac, Expr **ArgExprs, - unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false, + /*ValueDependent=*/false), + NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), + HasMethod(Method != 0), SuperLoc(SuperLoc), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} + setReceiverPointer(SuperType.getAsOpaquePtr()); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, T->isDependentType(), + (T->isDependentType() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(), + (Receiver->isTypeDependent() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper, + SuperType, Sel, Method, Args, NumArgs, + RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, + unsigned NumArgs) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf::Alignment); + return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); +} + +Selector ObjCMessageExpr::getSelector() const { + if (HasMethod) + return reinterpret_cast(SelectorOrMethod) + ->getSelector(); + return Selector(SelectorOrMethod); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + switch (getReceiverKind()) { + case Instance: + if (const ObjCObjectPointerType *Ptr + = getInstanceReceiver()->getType()->getAs()) + return Ptr->getInterfaceDecl(); + break; -ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { - uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - switch (x & Flags) { - default: - assert(false && "Invalid ObjCMessageExpr."); - case IsInstMeth: - return ClassInfo(0, 0, SourceLocation()); - case IsClsMethDeclUnknown: - return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc); - case IsClsMethDeclKnown: { - ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); - return ClassInfo(D, D->getIdentifier(), ClassNameLoc); - } - } -} + case Class: + if (const ObjCInterfaceType *Iface + = getClassReceiver()->getAs()) + return Iface->getDecl(); + break; -void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { - if (CI.Decl == 0 && CI.Name == 0) { - SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); - return; - } + case SuperInstance: + if (const ObjCObjectPointerType *Ptr + = getSuperType()->getAs()) + return Ptr->getInterfaceDecl(); + break; - if (CI.Decl == 0) - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown); - else - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown); - ClassNameLoc = CI.Loc; -} + case SuperClass: + if (const ObjCObjectPointerType *Iface + = getSuperType()->getAs()) + return Iface->getInterfaceDecl(); + break; + } -void ObjCMessageExpr::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (SubExprs) - C.Deallocate(SubExprs); - this->~ObjCMessageExpr(); - C.Deallocate((void*) this); + return 0; } bool ChooseExpr::isConditionTrue(ASTContext &C) const { @@ -2577,6 +2758,15 @@ Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } +// OffsetOfExpr +Stmt::child_iterator OffsetOfExpr::child_begin() { + return reinterpret_cast (reinterpret_cast (this + 1) + + NumComps); +} +Stmt::child_iterator OffsetOfExpr::child_end() { + return child_iterator(&*child_begin() + NumExprs); +} + // SizeOfAlignOfExpr Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { // If this is of a type and the type is a VLA type (and not a typedef), the @@ -2746,10 +2936,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() { // ObjCMessageExpr Stmt::child_iterator ObjCMessageExpr::child_begin() { - return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; + if (getReceiverKind() == Instance) + return reinterpret_cast(this + 1); + return getArgs(); } Stmt::child_iterator ObjCMessageExpr::child_end() { - return &SubExprs[0]+ARGS_START+getNumArgs(); + return getArgs() + getNumArgs(); } // Blocks diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index b9a4ee6..2e03beb 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -18,16 +18,25 @@ #include "clang/AST/TypeLoc.h" using namespace clang; + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// +QualType CXXTypeidExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + // CXXTypeidExpr - has child iterators if the operand is an expression Stmt::child_iterator CXXTypeidExpr::child_begin() { - return isTypeOperand() ? child_iterator() : &Operand.Ex; + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand); } Stmt::child_iterator CXXTypeidExpr::child_end() { - return isTypeOperand() ? child_iterator() : &Operand.Ex+1; + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand) + 1; } // CXXBoolLiteralExpr @@ -180,6 +189,13 @@ bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, return false; } +CXXRecordDecl *OverloadExpr::getNamingClass() const { + if (isa(this)) + return cast(this)->getNamingClass(); + else + return cast(this)->getNamingClass(); +} + Stmt::child_iterator UnresolvedLookupExpr::child_begin() { return child_iterator(); } @@ -443,9 +459,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, SourceLocation tyBeginLoc, Expr **Args, unsigned NumArgs, - SourceLocation rParenLoc) + SourceLocation rParenLoc, + bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc, - Cons, false, Args, NumArgs), + Cons, false, Args, NumArgs, ZeroInitialization), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } @@ -454,25 +471,25 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization, - bool BaseInitialization) { + ConstructionKind ConstructKind) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, NumArgs, ZeroInitialization, - BaseInitialization); + ConstructKind); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization, - bool BaseInitialization) + bool ZeroInitialization, + ConstructionKind ConstructKind) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), - BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), + Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -712,15 +729,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // If there was a nested name specifier, it names the naming class. // It can't be dependent: after all, we were actually able to do the // lookup. - const RecordType *RT; + CXXRecordDecl *Record = 0; if (getQualifier()) { Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); - RT = T->getAs(); - assert(RT && "qualifier in member expression does not name record"); - + Record = T->getAsCXXRecordDecl(); + assert(Record && "qualifier in member expression does not name record"); + } // Otherwise the naming class must have been the base class. - } else { + else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) { const PointerType *PT = BaseType->getAs(); @@ -728,11 +745,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { BaseType = PT->getPointeeType(); } - RT = BaseType->getAs(); - assert(RT && "base of member expression does not name record"); + Record = BaseType->getAsCXXRecordDecl(); + assert(Record && "base of member expression does not name record"); } - return cast(RT->getDecl()); + return Record; } Stmt::child_iterator UnresolvedMemberExpr::child_begin() { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eeeeb5c..c1a42d8 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -16,7 +16,9 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Expr.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" @@ -203,6 +205,13 @@ public: return Visit(E->getSubExpr()); } bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } + + // Has side effects if any element does. + bool VisitInitListExpr(InitListExpr *E) { + for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) + if (Visit(E->getInit(i))) return true; + return false; + } }; } // end anonymous namespace @@ -221,7 +230,7 @@ public: APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitDeclRefExpr(DeclRefExpr *E); APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); } @@ -821,6 +830,7 @@ public: bool VisitCallExpr(CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); @@ -961,7 +971,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return complex_type_class; else if (ArgTy->isFunctionType()) return function_type_class; - else if (ArgTy->isStructureType()) + else if (ArgTy->isStructureOrClassType()) return record_type_class; else if (ArgTy->isUnionType()) return union_type_class; @@ -1109,9 +1119,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { assert(E->getOpcode() == BinaryOperator::NE && "Invalid complex comparison."); return Success(((CR_r == APFloat::cmpGreaterThan || - CR_r == APFloat::cmpLessThan) && + CR_r == APFloat::cmpLessThan || + CR_r == APFloat::cmpUnordered) || (CR_i == APFloat::cmpGreaterThan || - CR_i == APFloat::cmpLessThan)), E); + CR_i == APFloat::cmpLessThan || + CR_i == APFloat::cmpUnordered)), E); } } else { if (E->getOpcode() == BinaryOperator::EQ) @@ -1154,7 +1166,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(CR == APFloat::cmpEqual, E); case BinaryOperator::NE: return Success(CR == APFloat::cmpGreaterThan - || CR == APFloat::cmpLessThan, E); + || CR == APFloat::cmpLessThan + || CR == APFloat::cmpUnordered, E); } } @@ -1191,8 +1204,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } if (E->getOpcode() == BinaryOperator::Sub) { - const QualType Type = E->getLHS()->getType(); - const QualType ElementType = Type->getAs()->getPointeeType(); + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs()->getPointeeType(); CharUnits ElementSize = CharUnits::One(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) @@ -1365,6 +1378,85 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E); } +bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { + CharUnits Result; + unsigned n = E->getNumComponents(); + OffsetOfExpr* OOE = const_cast(E); + if (n == 0) + return false; + QualType CurrentType = E->getTypeSourceInfo()->getType(); + for (unsigned i = 0; i != n; ++i) { + OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: { + Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); + APSInt IdxResult; + if (!EvaluateInteger(Idx, IdxResult, Info)) + return false; + const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType); + if (!AT) + return false; + CurrentType = AT->getElementType(); + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); + Result += IdxResult.getSExtValue() * ElementSize; + break; + } + + case OffsetOfExpr::OffsetOfNode::Field: { + FieldDecl *MemberDecl = ON.getField(); + const RecordType *RT = CurrentType->getAs(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + unsigned i = 0; + // FIXME: It would be nice if we didn't have to loop here! + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == MemberDecl) + break; + } + assert(i < RL.getFieldCount() && "offsetof field in wrong type"); + Result += CharUnits::fromQuantity( + RL.getFieldOffset(i) / Info.Ctx.getCharWidth()); + CurrentType = MemberDecl->getType().getNonReferenceType(); + break; + } + + case OffsetOfExpr::OffsetOfNode::Identifier: + llvm_unreachable("dependent __builtin_offsetof"); + return false; + + case OffsetOfExpr::OffsetOfNode::Base: { + CXXBaseSpecifier *BaseSpec = ON.getBase(); + if (BaseSpec->isVirtual()) + return false; + + // Find the layout of the class whose base we are looking into. + const RecordType *RT = CurrentType->getAs(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + // Find the base class itself. + CurrentType = BaseSpec->getType(); + const RecordType *BaseRT = CurrentType->getAs(); + if (!BaseRT) + return false; + + // Add the offset to the base. + Result += CharUnits::fromQuantity( + RL.getBaseClassOffset(cast(BaseRT->getDecl())) + / Info.Ctx.getCharWidth()); + break; + } + } + } + return Success(Result.getQuantity(), E); +} + bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Special case unary operators that do not need their subexpression // evaluated. offsetof/sizeof/alignof are all special. @@ -1373,12 +1465,12 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // directly Evaluate it as an l-value. APValue LV; if (!EvaluateLValue(E->getSubExpr(), LV, Info)) - return false; + return false; if (LV.getLValueBase()) - return false; + return false; return Success(LV.getLValueOffset().getQuantity(), E); } - + if (E->getOpcode() == UnaryOperator::LNot) { // LNot's operand isn't necessarily an integer, so we handle it specially. bool bres; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 93edb42..3782985 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -15,15 +15,16 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" -#include -#include +#include "llvm/Support/Format.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/MathExtras.h" using namespace clang; -ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) - : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0), - MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), - NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context) + : Context(Context), Size(0), Alignment(8), Packed(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false), + NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } /// IsNearlyEmpty - Indicates when a class has a vtable pointer, but /// no other data. @@ -31,29 +32,29 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { // FIXME: Audit the corners if (!RD->isDynamicClass()) return false; - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); - if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0)) + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0)) return true; return false; } void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = - Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo(); - + const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = + Context.getASTRecordLayout(RD).getPrimaryBaseInfo(); + // If the record has a primary base class that is virtual, add it to the set // of primary bases. if (BaseInfo.isVirtual()) IndirectPrimaryBases.insert(BaseInfo.getBase()); - + // Now traverse all bases and find primary bases for them. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - + // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. if (Base->getNumVBases()) @@ -64,10 +65,10 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); @@ -80,12 +81,12 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { /*IsVirtual=*/true); return; } - + // Is this the first nearly empty virtual base? if (!FirstNearlyEmptyVBase) FirstNearlyEmptyVBase = Base; } - + SelectPrimaryVBase(Base); if (PrimaryBase.getBase()) return; @@ -97,11 +98,11 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. if (!RD->isDynamicClass()) return; - + // Compute all the primary virtual bases for all of our direct and // indirect bases, and record all their primary virtual base classes. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot lay out class with dependent bases."); const CXXRecordDecl *Base = @@ -109,15 +110,15 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { IdentifyPrimaryBases(Base); } - // If the record has a dynamic base class, attempt to choose a primary base - // class. It is the first (in direct base class order) non-virtual dynamic + // If the record has a dynamic base class, attempt to choose a primary base + // class. It is the first (in direct base class order) non-virtual dynamic // base class, if one exists. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { + e = RD->bases_end(); i != e; ++i) { // Ignore virtual bases. if (i->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); @@ -139,44 +140,47 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // Otherwise, it is the first nearly empty virtual base that is not an // indirect primary virtual base class, if one exists. if (FirstNearlyEmptyVBase) { - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, /*IsVirtual=*/true); return; } - + // Otherwise there is no primary base class. assert(!PrimaryBase.getBase() && "Should not get here with a primary base!"); // Allocate the virtual table pointer at offset zero. assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); - + // Update the size. - Size += Ctx.Target.getPointerWidth(0); + Size += Context.Target.getPointerWidth(0); DataSize = Size; // Update the alignment. - UpdateAlignment(Ctx.Target.getPointerAlign(0)); + UpdateAlignment(Context.Target.getPointerAlign(0)); } void ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // First, determine the primary base class. DeterminePrimaryBase(RD); - + // If we have a primary base class, lay it out. if (const CXXRecordDecl *Base = PrimaryBase.getBase()) { if (PrimaryBase.isVirtual()) { // We have a virtual primary base, insert it as an indirect primary base. IndirectPrimaryBases.insert(Base); + assert(!VisitedVirtualBases.count(Base) && "vbase already visited!"); + VisitedVirtualBases.insert(Base); + LayoutVirtualBase(Base); } else LayoutNonVirtualBase(Base); } - + // Now lay out the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { // Ignore virtual bases. if (I->isVirtual()) @@ -197,83 +201,113 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { // Layout the base. uint64_t Offset = LayoutBase(RD); - + // Add its base class offset. if (!Bases.insert(std::make_pair(RD, Offset)).second) assert(false && "Added same base offset more than once!"); } -void -ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, +void +ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, const CXXRecordDecl *MostDerivedClass) { + // We already have the offset for the primary base of the most derived class. + if (RD != MostDerivedClass) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // If this is a primary virtual base and we haven't seen it before, add it. + if (PrimaryBase && Layout.getPrimaryBaseWasVirtual() && + !VBases.count(PrimaryBase)) + VBases.insert(std::make_pair(PrimaryBase, Offset)); + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + if (!BaseDecl->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + // Compute the offset of this base. + uint64_t BaseOffset; + + if (I->isVirtual()) { + // If we don't know this vbase yet, don't visit it. It will be visited + // later. + if (!VBases.count(BaseDecl)) { + continue; + } + + // Check if we've already visited this base. + if (!VisitedVirtualBases.insert(BaseDecl)) + continue; + + // We want the vbase offset from the class we're currently laying out. + BaseOffset = VBases[BaseDecl]; + } else if (RD == MostDerivedClass) { + // We want the base offset from the class we're currently laying out. + assert(Bases.count(BaseDecl) && "Did not find base!"); + BaseOffset = Bases[BaseDecl]; + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + } + + AddPrimaryVirtualBaseOffsets(BaseDecl, BaseOffset, MostDerivedClass); + } +} + +void +ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass) { const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseIsVirtual; - if (MostDerivedClass == RD) + if (MostDerivedClass == RD) { PrimaryBase = this->PrimaryBase.getBase(); - else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual(); + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); PrimaryBase = Layout.getPrimaryBase(); + PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); } for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); if (I->isVirtual()) { - bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); - - // We only want to visit this virtual base if it's either a primary base, - // or not an indirect primary base. - if (Base == PrimaryBase || !IndirectPrimaryBase) { - // Only lay things out once. - if (!VisitedVirtualBases.insert(Base)) - continue; - - if (Base == PrimaryBase) { - assert(IndirectPrimaryBase && - "Base is supposed to be an indirect primary base!"); - - // We only want to add a vbase offset if this primary base is not the - // primary base of the most derived class. - if (PrimaryBase != this->PrimaryBase.getBase() || - !this->PrimaryBase.isVirtual()) { - if (!VBases.insert(std::make_pair(Base, Offset)).second) - assert(false && "Added same vbase offset more than once!"); - } - } else { - // We actually do want to lay out this base. + if (PrimaryBase != Base || !PrimaryBaseIsVirtual) { + bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); + + // Only lay out the virtual base if it's not an indirect primary base. + if (!IndirectPrimaryBase) { + // Only visit virtual bases once. + if (!VisitedVirtualBases.insert(Base)) + continue; + LayoutVirtualBase(Base); } } } - + if (!Base->getNumVBases()) { // This base isn't interesting since it doesn't have any virtual bases. continue; } - // Compute the offset of this base. - uint64_t BaseOffset; - - if (I->isVirtual()) { - // We want the vbase offset from the class we're currently laying out. - assert(VBases.count(Base) && "Did not find virtual base!"); - BaseOffset = VBases[Base]; - } else if (RD == MostDerivedClass) { - // We want the base offset from the class we're currently laying out. - assert(Bases.count(Base) && "Did not find base!"); - BaseOffset = Bases[Base]; - } else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } - - LayoutVirtualBases(Base, BaseOffset, MostDerivedClass); + LayoutVirtualBases(Base, MostDerivedClass); } } @@ -287,7 +321,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { } uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); // If we have an empty base class, try to place it at offset 0. if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { @@ -298,17 +332,17 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { return 0; } - + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); - + // Round up the current record size to the base's alignment boundary. uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); - + // Try to place the base. while (true) { if (canPlaceRecordAtOffset(RD, Offset)) break; - + Offset += BaseAlign; } @@ -327,44 +361,44 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { return Offset; } -bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, +bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const { // Look for an empty class with the same type at the same offset. - for (EmptyClassOffsetsTy::const_iterator I = - EmptyClassOffsets.lower_bound(Offset), - E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { - + for (EmptyClassOffsetsTy::const_iterator I = + EmptyClassOffsets.lower_bound(Offset), + E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { + if (I->second == RD) return false; } - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); - + if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) return false; } - + // Check fields. unsigned FieldNo = 0; - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); - + if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset)) return false; } @@ -373,35 +407,35 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return true; } -bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, +bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const { QualType T = FD->getType(); if (const RecordType *RT = T->getAs()) { if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) return canPlaceRecordAtOffset(RD, Offset); } - - if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { - QualType ElemTy = Ctx.getBaseElementType(AT); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); const RecordType *RT = ElemTy->getAs(); if (!RT) return true; const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return true; - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); - uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { if (!canPlaceRecordAtOffset(RD, ElementOffset)) return false; - + ElementOffset += Info.getSize(); } } - + return true; } @@ -409,39 +443,39 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset) { if (RD->isEmpty()) EmptyClassOffsets.insert(std::make_pair(Offset, RD)); - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; - + const CXXRecordDecl *Base = cast(I->getType()->getAs()->getDecl()); - + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); } - + // Update fields. unsigned FieldNo = 0; - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); UpdateEmptyClassOffsets(FD, Offset + FieldOffset); } - + // FIXME: Update virtual bases. } void -ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, +ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset) { QualType T = FD->getType(); @@ -451,19 +485,19 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, return; } } - - if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { - QualType ElemTy = Ctx.getBaseElementType(AT); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); const RecordType *RT = ElemTy->getAs(); if (!RT) return; const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return; - - const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); - uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { @@ -495,20 +529,50 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { NonVirtualSize = Size; NonVirtualAlignment = Alignment; - // If this is a C++ class, lay out its virtual bases. - if (RD) - LayoutVirtualBases(RD, 0, RD); + // If this is a C++ class, lay out its virtual bases and add its primary + // virtual base offsets. + if (RD) { + LayoutVirtualBases(RD, RD); + + VisitedVirtualBases.clear(); + AddPrimaryVirtualBaseOffsets(RD, 0, RD); + } // Finally, round the size of the total struct up to the alignment of the // struct itself. FinishLayout(); + +#ifndef NDEBUG + if (RD) { + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } + } +#endif } // FIXME. Impl is no longer needed. void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) { if (ObjCInterfaceDecl *SD = D->getSuperClass()) { - const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); + const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD); UpdateAlignment(SL.getAlignment()); @@ -528,7 +592,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector Ivars; - Ctx.ShallowCollectObjCIvars(D, Ivars); + Context.ShallowCollectObjCIvars(D, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) LayoutField(Ivars[i]); @@ -541,20 +605,82 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) LayoutField(*Field); } +void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, + uint64_t TypeSize) { + assert(Context.getLangOptions().CPlusPlus && + "Can only have wide bit-fields in C++!"); + + // Itanium C++ ABI 2.4: + // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // sizeof(T')*8 <= n. + + QualType IntegralPODTypes[] = { + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedLongTy, Context.UnsignedLongLongTy + }; + + QualType Type; + for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes); + I != E; ++I) { + uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]); + + if (Size > FieldSize) + break; + + Type = IntegralPODTypes[I]; + } + assert(!Type.isNull() && "Did not find a type!"); + + unsigned TypeAlign = Context.getTypeAlign(Type); + + // We're not going to use any of the unfilled bits in the last byte. + UnfilledBitsInLastByte = 0; + + uint64_t FieldOffset; + + if (IsUnion) { + DataSize = std::max(DataSize, FieldSize); + FieldOffset = 0; + } else { + // The bitfield is allocated starting at the next offset aligned appropriately + // for T', with length n bits. + FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign); + + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); + UnfilledBitsInLastByte = DataSize - NewSizeInBits; + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Update the size. + Size = std::max(Size, DataSize); + + // Remember max struct/class alignment. + UpdateAlignment(TypeAlign); +} + void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); - uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue(); - - std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + std::pair FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; - - if (FieldPacked) + + if (FieldSize > TypeSize) { + LayoutWideBitField(FieldSize, TypeSize); + return; + } + + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; if (const AlignedAttr *AA = D->getAttr()) FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); @@ -562,33 +688,32 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) FieldAlign = std::min(FieldAlign, MaxFieldAlignment); - - // Check if we need to add padding to give the field the correct - // alignment. + + // Check if we need to add padding to give the field the correct alignment. if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - - // Padding members don't affect overall alignment + + // Padding members don't affect overall alignment. if (!D->getIdentifier()) FieldAlign = 1; - + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); - + // Update DataSize to include the last byte containing (part of) the bitfield. if (IsUnion) { // FIXME: I think FieldSize should be TypeSize here. DataSize = std::max(DataSize, FieldSize); } else { uint64_t NewSizeInBits = FieldOffset + FieldSize; - + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); UnfilledBitsInLastByte = DataSize - NewSizeInBits; } - + // Update the size. Size = std::max(Size, DataSize); - + // Remember max struct/class alignment. UpdateAlignment(FieldAlign); } @@ -606,21 +731,21 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { uint64_t FieldOffset = IsUnion ? 0 : DataSize; uint64_t FieldSize; unsigned FieldAlign; - + if (D->getType()->isIncompleteArrayType()) { // This is a flexible array member; we can't directly // query getTypeInfo about these, so we figure it out here. // Flexible array members don't have any size, but they // have to be aligned appropriately for their element type. FieldSize = 0; - const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); - FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); + const ArrayType* ATy = Context.getAsArrayType(D->getType()); + FieldAlign = Context.getTypeAlign(ATy->getElementType()); } else if (const ReferenceType *RT = D->getType()->getAs()) { unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Ctx.Target.getPointerWidth(AS); - FieldAlign = Ctx.Target.getPointerAlign(AS); + FieldSize = Context.Target.getPointerWidth(AS); + FieldAlign = Context.Target.getPointerAlign(AS); } else { - std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + std::pair FieldInfo = Context.getTypeInfo(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; } @@ -636,20 +761,20 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { // Round up the current record size to the field's alignment boundary. FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); - + if (!IsUnion) { while (true) { // Check if we can place the field at this offset. if (canPlaceFieldAtOffset(D, FieldOffset)) break; - + // We couldn't place the field at the offset. Try again at a new offset. FieldOffset += FieldAlign; } - + UpdateEmptyClassOffsets(D, FieldOffset); } - + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); @@ -668,7 +793,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { void ASTRecordLayoutBuilder::FinishLayout() { // In C++, records cannot be of size 0. - if (Ctx.getLangOptions().CPlusPlus && Size == 0) + if (Context.getLangOptions().CPlusPlus && Size == 0) Size = 8; // Finally, round the size of the record up to the alignment of the // record itself. @@ -735,7 +860,7 @@ const CXXMethodDecl * ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); - // If a class isnt' polymorphic it doesn't have a key function. + // If a class isn't polymorphic it doesn't have a key function. if (!RD->isPolymorphic()) return 0; @@ -745,13 +870,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace()) return 0; - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *MD = *I; - + if (!MD->isVirtual()) continue; - + if (MD->isPure()) continue; @@ -759,17 +884,134 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { // they don't have a body until they're defined. if (MD->isImplicit()) continue; - + if (MD->isInlineSpecified()) continue; if (MD->hasInlineBody()) continue; - + // We found it. return MD; } - + return 0; } +static void PrintOffset(llvm::raw_ostream &OS, + uint64_t Offset, unsigned IndentLevel) { + OS << llvm::format("%4d | ", Offset); + OS.indent(IndentLevel * 2); +} + +static void DumpCXXRecordLayout(llvm::raw_ostream &OS, + const CXXRecordDecl *RD, ASTContext &C, + uint64_t Offset, + unsigned IndentLevel, + const char* Description, + bool IncludeVirtualBases) { + const ASTRecordLayout &Info = C.getASTRecordLayout(RD); + + PrintOffset(OS, Offset, IndentLevel); + OS << C.getTypeDeclType(const_cast(RD)).getAsString(); + if (Description) + OS << ' ' << Description; + if (RD->isEmpty()) + OS << " (empty)"; + OS << '\n'; + + IndentLevel++; + + const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); + + // Vtable pointer. + if (RD->isDynamicClass() && !PrimaryBase) { + PrintOffset(OS, Offset, IndentLevel); + OS << '(' << RD << " vtable pointer)\n"; + } + // Dump (non-virtual) bases + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; + + DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel, + Base == PrimaryBase ? "(primary base)" : "(base)", + /*IncludeVirtualBases=*/false); + } + + // Dump fields. + uint64_t FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *Field = *I; + uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; + + if (const RecordType *RT = Field->getType()->getAs()) { + if (const CXXRecordDecl *D = dyn_cast(RT->getDecl())) { + DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, + Field->getNameAsCString(), + /*IncludeVirtualBases=*/true); + continue; + } + } + + PrintOffset(OS, FieldOffset, IndentLevel); + OS << Field->getType().getAsString() << ' ' << Field << '\n'; + } + + if (!IncludeVirtualBases) + return; + + // Dump virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + assert(I->isVirtual() && "Found non-virtual class!"); + const CXXRecordDecl *VBase = + cast(I->getType()->getAs()->getDecl()); + + uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; + DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, + VBase == PrimaryBase ? + "(primary virtual base)" : "(virtual base)", + /*IncludeVirtualBases=*/false); + } + + OS << " sizeof=" << Info.getSize() / 8; + OS << ", dsize=" << Info.getDataSize() / 8; + OS << ", align=" << Info.getAlignment() / 8 << '\n'; + OS << " nvsize=" << Info.getNonVirtualSize() / 8; + OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; + OS << '\n'; +} + +void ASTContext::DumpRecordLayout(const RecordDecl *RD, + llvm::raw_ostream &OS) { + const ASTRecordLayout &Info = getASTRecordLayout(RD); + + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) + return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0, + /*IncludeVirtualBases=*/true); + + OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n"; + OS << "Record: "; + RD->dump(); + OS << "\nLayout: "; + OS << "\n"; +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index a4bce75..f277c29 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -26,7 +26,7 @@ namespace clang { class RecordDecl; class ASTRecordLayoutBuilder { - ASTContext &Ctx; + ASTContext &Context; /// Size - The current size of the record layout. uint64_t Size; @@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); void LayoutBitField(const FieldDecl *D); /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -112,8 +113,11 @@ class ASTRecordLayoutBuilder { /// LayoutNonVirtualBase - Lays out a single non-virtual base. void LayoutNonVirtualBase(const CXXRecordDecl *RD); + void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *MostDerivedClass); + /// LayoutVirtualBases - Lays out all the virtual bases. - void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset, + void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass); /// LayoutVirtualBase - Lays out a single virtual base. diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 9702382..67fd74c 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include using namespace clang; @@ -240,6 +241,8 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, // asm string. std::string CurStringPiece; + bool HasVariants = !C.Target.hasNoAsmVariants(); + while (1) { // Done with the string? if (CurPtr == StrEnd) { @@ -251,9 +254,9 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; - case '{': CurStringPiece += "$("; continue; - case '|': CurStringPiece += "$|"; continue; - case '}': CurStringPiece += "$)"; continue; + case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; + case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; + case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: @@ -389,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, RParenLoc = RPL; } - -ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, - SourceLocation rparenloc, - ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, - Stmt *atCatchList) -: Stmt(ObjCAtCatchStmtClass) { - ExceptionDecl = catchVarDecl; - SubExprs[BODY] = atCatchStmt; - SubExprs[NEXT_CATCH] = NULL; - // FIXME: O(N^2) in number of catch blocks. - if (atCatchList) { - ObjCAtCatchStmt *AtCatchList = static_cast(atCatchList); - - while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) - AtCatchList = NextCatch; - - AtCatchList->SubExprs[NEXT_CATCH] = this; - } - AtCatchLoc = atCatchLoc; - RParenLoc = rparenloc; +ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt) + : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), + NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) +{ + Stmt **Stmts = getStmts(); + Stmts[0] = atTryStmt; + for (unsigned I = 0; I != NumCatchStmts; ++I) + Stmts[I + 1] = CatchStmts[I]; + + if (HasFinally) + Stmts[NumCatchStmts + 1] = atFinallyStmt; +} + +ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, + SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, + unsigned NumCatchStmts, + Stmt *atFinallyStmt) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof()); + return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, + atFinallyStmt); +} + +ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof()); + return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); +} + +SourceRange ObjCAtTryStmt::getSourceRange() const { + SourceLocation EndLoc; + if (HasFinally) + EndLoc = getFinallyStmt()->getLocEnd(); + else if (NumCatchStmts) + EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd(); + else + EndLoc = getTryBody()->getLocEnd(); + + return SourceRange(AtTryLoc, EndLoc); } CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, @@ -627,19 +657,18 @@ Stmt::child_iterator AsmStmt::child_end() { } // ObjCAtCatchStmt -Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ObjCAtCatchStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} +Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; } +Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; } // ObjCAtFinallyStmt Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } // ObjCAtTryStmt -Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } -Stmt::child_iterator ObjCAtTryStmt::child_end() { - return &SubStmts[0]+END_EXPR; +Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); } + +Stmt::child_iterator ObjCAtTryStmt::child_end() { + return getStmts() + 1 + NumCatchStmts + HasFinally; } // ObjCAtThrowStmt diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index ba6218b..ca62ed1 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -143,6 +143,7 @@ namespace { void DumpCXXTemporary(CXXTemporary *Temporary); // ObjC + void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); @@ -219,7 +220,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast(D)) { OS << "\"typedef " << localType->getUnderlyingType().getAsString() - << " " << localType->getNameAsString() << "\""; + << ' ' << localType << '"'; } else if (ValueDecl *VD = dyn_cast(D)) { OS << "\""; // Emit storage class for vardecls. @@ -299,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } +static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { + if (Node->getBasePath().empty()) + return; + + OS << " ("; + bool First = true; + for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(), + E = Node->getBasePath().end(); I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + if (!First) + OS << " -> "; + + const CXXRecordDecl *RD = + cast(Base->getType()->getAs()->getDecl()); + + if (Base->isVirtual()) + OS << "virtual "; + OS << RD->getName(); + First = false; + } + + OS << ')'; +} + void StmtDumper::VisitCastExpr(CastExpr *Node) { DumpExpr(Node); - OS << " <" << Node->getCastKindName() << ">"; + OS << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { @@ -328,15 +355,14 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { case Decl::ObjCClass: OS << "ObjCClass"; break; } - OS << "='" << Node->getDecl()->getNameAsString() - << "' " << (void*)Node->getDecl(); + OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl(); } void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { DumpExpr(Node); OS << " ("; if (!Node->requiresADL()) OS << "no "; - OS << "ADL) = '" << Node->getName().getAsString() << "'"; + OS << "ADL) = '" << Node->getName() << '\''; UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(), E = Node->decls_end(); @@ -349,7 +375,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); OS << " " << Node->getDecl()->getDeclKindName() - << "Decl='" << Node->getDecl()->getNameAsString() + << "Decl='" << Node->getDecl() << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) OS << " isFreeIvar"; @@ -408,7 +434,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") - << Node->getMemberDecl()->getNameAsString() << " " + << Node->getMemberDecl() << ' ' << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); OS << " " << Node->getCastName() << "<" << Node->getTypeAsWritten().getAsString() << ">" - << " <" << Node->getCastKindName() << ">"; + << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { @@ -506,8 +534,33 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); OS << " selector=" << Node->getSelector().getAsString(); - if (IdentifierInfo *clsName = Node->getClassName()) - OS << " class=" << clsName->getNameStart(); + switch (Node->getReceiverKind()) { + case ObjCMessageExpr::Instance: + break; + + case ObjCMessageExpr::Class: + OS << " class="; + DumpType(Node->getClassReceiver()); + break; + + case ObjCMessageExpr::SuperInstance: + OS << " super (instance)"; + break; + + case ObjCMessageExpr::SuperClass: + OS << " super (class)"; + break; + } +} + +void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) { + DumpStmt(Node); + if (VarDecl *CatchParam = Node->getCatchParamDecl()) { + OS << " catch parm = "; + DumpDeclarator(CatchParam); + } else { + OS << " catch all"; + } } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { @@ -525,14 +578,13 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - OS << " " << Node->getProtocol()->getNameAsString(); + OS << ' ' << Node->getProtocol(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - OS << " Kind=PropertyRef Property=\"" - << Node->getProperty()->getNameAsString() << "\""; + OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"'; } void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index da43878..52f627d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Format.h" +#include "clang/AST/Expr.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -388,11 +389,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { OS << "\n"; } - for (ObjCAtCatchStmt *catchStmt = - static_cast(Node->getCatchStmts()); - catchStmt; - catchStmt = - static_cast(catchStmt->getNextCatchStmt())) { + for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I); Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { if (Decl *DS = catchStmt->getCatchParamDecl()) @@ -474,7 +472,7 @@ void StmtPrinter::VisitExpr(Expr *Node) { void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), @@ -509,7 +507,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { @@ -527,7 +525,7 @@ void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( OS << "."; } if (Node->getGetterMethod()) - OS << Node->getGetterMethod()->getNameAsString(); + OS << Node->getGetterMethod(); } @@ -695,7 +693,7 @@ bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { } else { MemberExpr *ME = cast(E); bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); - OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString(); + OS << (IsFirst ? "" : ".") << ME->getMemberDecl(); return false; } } @@ -706,6 +704,39 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { OS << ")"; } +void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { + OS << "__builtin_offsetof("; + OS << Node->getTypeSourceInfo()->getType().getAsString() << ", "; + bool PrintedSomething = false; + for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) { + OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i); + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) { + // Array node + OS << "["; + PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex())); + OS << "]"; + PrintedSomething = true; + continue; + } + + // Skip implicit base indirections. + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base) + continue; + + // Field or identifier node. + IdentifierInfo *Id = ON.getFieldName(); + if (!Id) + continue; + + if (PrintedSomething) + OS << "."; + else + PrintedSomething = true; + OS << Id->getName(); + } + OS << ")"; +} + void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); if (Node->isArgumentType()) @@ -746,7 +777,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getMemberDecl()->getNameAsString(); + OS << Node->getMemberDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -1242,14 +1273,26 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { } void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')'; + OS << "@protocol(" << Node->getProtocol() << ')'; } void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "["; - Expr *receiver = Mess->getReceiver(); - if (receiver) PrintExpr(receiver); - else OS << Mess->getClassName()->getName(); + switch (Mess->getReceiverKind()) { + case ObjCMessageExpr::Instance: + PrintExpr(Mess->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + OS << Mess->getClassReceiver().getAsString(Policy); + break; + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + OS << "Super"; + break; + } + OS << ' '; Selector selector = Mess->getSelector(); if (selector.isUnarySelector()) { @@ -1304,7 +1347,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { } void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } //===----------------------------------------------------------------------===// // Stmt method implementations diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 3a19ec2..d45bb2f 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -261,6 +261,34 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { ID.AddInteger(S->getOpcode()); } +void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { + VisitType(S->getTypeSourceInfo()->getType()); + unsigned n = S->getNumComponents(); + for (unsigned i = 0; i < n; ++i) { + const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i); + ID.AddInteger(ON.getKind()); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + // Expressions handled below. + break; + + case OffsetOfExpr::OffsetOfNode::Field: + VisitDecl(ON.getField()); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + ID.AddPointer(ON.getFieldName()); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // These nodes are implicit, and therefore don't need profiling. + break; + } + } + + VisitExpr(S); +} + void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { VisitExpr(S); ID.AddBoolean(S->isSizeOf()); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index b56c0ceb..14722f7 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -15,9 +15,11 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace llvm; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast()) @@ -45,13 +47,13 @@ void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast()) - OS << Template->getNameAsString(); + OS << Template; else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getDecl()->getNameAsString(); + OS << QTN->getDecl(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); @@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, } } +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + TemplateName N) { + std::string NameStr; + raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + N.print(OS, PrintingPolicy(LO)); + OS.flush(); + return DB << NameStr; +} + void TemplateName::dump() const { LangOptions LO; // FIXME! LO.CPlusPlus = true; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 27a277d..05e7fdc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -225,6 +225,11 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isStructureOrClassType() const { + if (const RecordType *RT = getAs()) + return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return false; +} bool Type::isVoidPointerType() const { if (const PointerType *PT = getAs()) return PT->getPointeeType()->isVoidType(); @@ -410,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { return 0; } +CXXRecordDecl *Type::getAsCXXRecordDecl() const { + if (const RecordType *RT = getAs()) + return dyn_cast(RT->getDecl()); + else if (const InjectedClassNameType *Injected + = getAs()) + return Injected->getDecl(); + + return 0; +} + bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && @@ -999,12 +1014,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { TemplateSpecializationType:: TemplateSpecializationType(ASTContext &Context, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Context(Context), + ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation), Template(T), NumArgs(NumArgs) { assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && @@ -1039,9 +1055,11 @@ TemplateSpecializationType::getArg(unsigned Idx) const { void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, ASTContext &Context) { + ID.AddBoolean(IsCurrentInstantiation); T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) Args[Idx].Profile(ID, Context); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 340e373..915d7af 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -29,7 +29,7 @@ namespace { public: explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } - + void Print(QualType T, std::string &S); void AppendScope(DeclContext *DC, std::string &S); void PrintTag(TagDecl *T, std::string &S); @@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization( void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, std::string &S) { - PrintTemplateSpecialization(T->getUnderlyingTST(), S); + PrintTemplateSpecialization(T->getInjectedTST(), S); } void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index f94f6b3..7f71e0a 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -46,7 +46,7 @@ public: AddStmtChoice(Kind kind) : k(kind) {} bool alwaysAdd() const { return (unsigned)k & 0x1; } - bool asLValue() const { return k >= AlwaysAddAsLValue; } + bool asLValue() const { return k >= AsLValueNotAlwaysAdd; } private: Kind k; @@ -108,16 +108,16 @@ private: CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); + CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); + CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); CFGBlock *VisitCompoundStmt(CompoundStmt *C); - CFGBlock *VisitConditionalOperator(ConditionalOperator *C, - AddStmtChoice asc); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); - CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -127,6 +127,7 @@ private: CFGBlock *VisitIfStmt(IfStmt *I); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); CFGBlock *VisitLabelStmt(LabelStmt *L); + CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); @@ -337,6 +338,10 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) { /// DeclStmts (which may contain nested control-flow). CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { tryAgain: + if (!S) { + badCFG = true; + return 0; + } switch (S->getStmtClass()) { default: return VisitStmt(S, asc); @@ -374,6 +379,9 @@ tryAgain: case Stmt::CXXCatchStmtClass: return VisitCXXCatchStmt(cast(S)); + case Stmt::CXXMemberCallExprClass: + return VisitCXXMemberCallExpr(cast(S), asc); + case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast(S)); @@ -404,6 +412,9 @@ tryAgain: case Stmt::LabelStmtClass: return VisitLabelStmt(cast(S)); + case Stmt::MemberExprClass: + return VisitMemberExpr(cast(S), asc); + case Stmt::ObjCAtCatchStmtClass: return VisitObjCAtCatchStmt(cast(S)); @@ -491,8 +502,16 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, Succ = ConfluenceBlock; Block = NULL; CFGBlock* RHSBlock = addStmt(B->getRHS()); - if (!FinishBlock(RHSBlock)) - return 0; + + if (RHSBlock) { + if (!FinishBlock(RHSBlock)) + return 0; + } + else { + // Create an empty block for cases where the RHS doesn't require + // any explicit statements in the CFG. + RHSBlock = createBlock(); + } // See if this is a known constant. TryResult KnownVal = TryEvaluateBool(B->getLHS()); @@ -627,15 +646,18 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = addStmt(C->getLHS()); + CFGBlock* LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -676,6 +698,9 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + // Create a block for the LHS expression if there is an LHS expression. A // GCC extension allows LHS to be NULL, causing the condition to be the // value that is returned instead. @@ -684,7 +709,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, Block = NULL; CFGBlock* LHSBlock = NULL; if (C->getLHS()) { - LHSBlock = addStmt(C->getLHS()); + LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Block = NULL; @@ -692,7 +717,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // Create the block for the RHS expression. Succ = ConfluenceBlock; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -1074,6 +1099,16 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { } } +CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { + if (asc.alwaysAdd()) { + autoCreateBlock(); + AppendStmt(Block, M, asc); + } + return Visit(M->getBase(), + M->isArrow() ? AddStmtChoice::NotAlwaysAdd + : AddStmtChoice::AsLValueNotAlwaysAdd); +} + CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Objective-C fast enumeration 'for' statements: // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC @@ -1694,6 +1729,15 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } +CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, + AddStmtChoice asc) { + AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + autoCreateBlock(); + AppendStmt(Block, C, AddStmtChoice(K)); + return VisitChildren(C); +} + CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { // Lazily create the indirect-goto dispatch block if there isn't one already. CFGBlock* IBlock = cfg->getIndirectGotoBlock(); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 2b7fcd0..1870195 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -11,24 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/PartialDiagnostic.h" - -#include "clang/Lex/LexDiagnostic.h" -#include "clang/Parse/ParseDiagnostic.h" #include "clang/AST/ASTDiagnostic.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Analysis/AnalysisDiagnostic.h" -#include "clang/Driver/DriverDiagnostic.h" - +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" + #include #include #include @@ -223,9 +223,12 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ErrorOccurred = false; FatalErrorOccurred = false; - NumDiagnostics = 0; - + ErrorLimit = 0; + TemplateBacktraceLimit = 0; + + NumWarnings = 0; NumErrors = 0; + NumErrorsSuppressed = 0; CustomDiagInfo = 0; CurDiagID = ~0U; LastDiagLevel = Ignored; @@ -286,11 +289,18 @@ bool Diagnostic::isBuiltinNote(unsigned DiagID) { } /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic -/// ID is for an extension of some sort. +/// ID is for an extension of some sort. This also returns EnabledByDefault, +/// which is set to indicate whether the diagnostic is ignored by default (in +/// which case -pedantic enables it) or treated as a warning/error by default. /// -bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) { - return DiagID < diag::DIAG_UPPER_LIMIT && - getBuiltinDiagClass(DiagID) == CLASS_EXTENSION; +bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID, + bool &EnabledByDefault) { + if (DiagID >= diag::DIAG_UPPER_LIMIT || + getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) + return false; + + EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE; + return true; } @@ -529,8 +539,14 @@ bool Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. - if (FatalErrorOccurred) + if (FatalErrorOccurred) { + if (DiagLevel >= Diagnostic::Error) { + ++NumErrors; + ++NumErrorsSuppressed; + } + return false; + } // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. @@ -551,11 +567,20 @@ bool Diagnostic::ProcessDiag() { if (DiagLevel >= Diagnostic::Error) { ErrorOccurred = true; ++NumErrors; + + // If we've emitted a lot of errors, emit a fatal error after it to stop a + // flood of bogus errors. + if (ErrorLimit && NumErrors >= ErrorLimit && + DiagLevel == Diagnostic::Error) + SetDelayedDiagnostic(diag::fatal_too_many_errors); } // Finally, report it. Client->HandleDiagnostic(DiagLevel, Info); - if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == Diagnostic::Warning) + ++NumWarnings; + } CurDiagID = ~0U; @@ -1026,8 +1051,15 @@ static void WriteSourceLocation(llvm::raw_ostream &OS, Location = SM->getInstantiationLoc(Location); std::pair Decomposed = SM->getDecomposedLoc(Location); - - WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName()); + + const FileEntry *FE = SM->getFileEntryForID(Decomposed.first); + if (FE) + WriteString(OS, FE->getName()); + else { + // Fallback to using the buffer name when there is no entry. + WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier()); + } + WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second)); WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 3da19ca..ed0de8c 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -78,9 +78,9 @@ namespace { /// identifiers because they are language keywords. This causes the lexer to /// automatically map matching identifiers to specialized token codes. /// -/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be +/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be /// enabled in the specified langauge, set to 1 if it is an extension -/// in the specified language, and set to 2 if disabled in the +/// in the specified language, and set to 0 if disabled in the /// specified language. static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, @@ -90,7 +90,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; - else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1; + else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 27cb9be..3ecab1d 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -60,6 +60,8 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { } const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, + const SourceManager &SM, + SourceLocation Loc, bool *Invalid) const { if (Invalid) *Invalid = false; @@ -94,22 +96,67 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, Entry->getName(), ErrorStr); else - Diag.Report(diag::err_cannot_open_file) + Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file) << Entry->getName() << ErrorStr; Buffer.setInt(true); + + // FIXME: This conditionalization is horrible, but we see spurious failures + // in the test suite due to this warning and no one has had time to hunt it + // down. So for now, we just don't emit this diagnostic on Win32, and hope + // nothing bad happens. + // + // PR6812. +#if !defined(LLVM_ON_WIN32) } else if (FileInfo.st_size != Entry->getSize() || FileInfo.st_mtime != Entry->getModificationTime()) { - // Check that the file's size, modification time, and inode are - // the same as in the file entry (which may have come from a - // stat cache). + // Check that the file's size and modification time are the same + // as in the file entry (which may have come from a stat cache). if (Diag.isDiagnosticInFlight()) - Diag.SetDelayedDiagnostic(diag::err_file_modified, + Diag.SetDelayedDiagnostic(diag::err_file_modified, Entry->getName()); - else - Diag.Report(diag::err_file_modified) << Entry->getName(); + else + Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified) + << Entry->getName(); Buffer.setInt(true); +#endif + } + + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + if (!Buffer.getInt()) { + llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); + const char *BOM = 0; + if (BufStr.startswith("\xFE\xBB\xBF")) + BOM = "UTF-8"; + else if (BufStr.startswith("\xFE\xFF")) + BOM = "UTF-16 (BE)"; + else if (BufStr.startswith("\xFF\xFE")) + BOM = "UTF-16 (LE)"; + else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4))) + BOM = "UTF-32 (BE)"; + else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4))) + BOM = "UTF-32 (LE)"; + else if (BufStr.startswith("\x2B\x2F\x76")) + BOM = "UTF-7"; + else if (BufStr.startswith("\xF7\x64\x4C")) + BOM = "UTF-1"; + else if (BufStr.startswith("\xDD\x73\x66\x73")) + BOM = "UTF-EBCDIC"; + else if (BufStr.startswith("\x0E\xFE\xFF")) + BOM = "SDSU"; + else if (BufStr.startswith("\xFB\xEE\x28")) + BOM = "BOCU-1"; + else if (BufStr.startswith("\x84\x31\x95\x33")) + BOM = "BOCU-1"; + + if (BOM) { + Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom) + << BOM << Entry->getName(); + Buffer.setInt(1); + } } } @@ -470,7 +517,7 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); assert(IR && "getOrCreateContentCache() cannot return NULL"); - return IR->getBuffer(Diag, Invalid); + return IR->getBuffer(Diag, *this, SourceLocation(), Invalid); } bool SourceManager::overrideFileContents(const FileEntry *SourceFile, @@ -717,8 +764,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL, // Note that calling 'getBuffer()' may lazily page in a source file. bool CharDataInvalid = false; const llvm::MemoryBuffer *Buffer - = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag, - &CharDataInvalid); + = getSLocEntry(LocInfo.first).getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); @@ -757,14 +804,16 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } -static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag, - ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, - bool &Invalid); -static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, bool &Invalid) { +static DISABLE_INLINE void +ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid); +static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. - const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid); + const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(), + &Invalid); if (Invalid) return; @@ -825,7 +874,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (Invalid) *Invalid = MyInvalid; if (MyInvalid) @@ -991,8 +1040,11 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. - const char *Filename = - C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier(); + const char *Filename; + if (C->Entry) + Filename = C->Entry->getName(); + else + Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); SourceLocation IncludeLoc = FI.getIncludeLoc(); @@ -1050,7 +1102,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (MyInvalid) return SourceLocation(); } @@ -1082,15 +1134,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, return SourceLocation(); if (Line > Content->NumLines) { - unsigned Size = Content->getBuffer(Diag)->getBufferSize(); + unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); if (Size > 0) --Size; return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); } unsigned FilePos = Content->SourceLineCache[Line - 1]; - const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos; - unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf; + const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos; + unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf; unsigned i = 0; // Check that the given column is valid. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 136089f..4c0c59a 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -20,10 +20,10 @@ using namespace clang; // TargetInfo Constructor. TargetInfo::TargetInfo(const std::string &T) : Triple(T) { - // Set defaults. Defaults are set for a 32-bit RISC platform, - // like PPC or SPARC. - // These should be overridden by concrete targets as needed. + // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or + // SPARC. These should be overridden by concrete targets as needed. TLSSupported = true; + NoAsmVariants = false; PointerWidth = PointerAlign = 32; IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; @@ -45,6 +45,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char32Type = UnsignedInt; Int64Type = SignedLongLong; SigAtomicType = SignedInt; + UseBitFieldTypeAlignment = true; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; @@ -142,9 +143,10 @@ bool TargetInfo::isTypeSigned(IntType T) const { /// Apply changes to the target information with respect to certain /// language options which change the target configuration. void TargetInfo::setForcedLangOptions(LangOptions &Opts) { - if (Opts.ShortWChar) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + if (Opts.ShortWChar) WCharType = UnsignedShort; - } } //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1797804..3d5048c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -219,6 +219,8 @@ protected: Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); } public: LinuxTargetInfo(const std::string& triple) @@ -1221,6 +1223,27 @@ public: Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Haiku target +class HaikuX86_32TargetInfo : public X86_32TargetInfo { +public: + HaikuX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__HAIKU__"); } }; } // end anonymous namespace @@ -1373,6 +1396,10 @@ public: SizeType = UnsignedInt; PtrDiffType = SignedInt; + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + // FIXME: Should we just treat this as a feature? IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { @@ -1397,6 +1424,10 @@ public: DoubleAlign = LongLongAlign = LongDoubleAlign = 32; SizeType = UnsignedLong; + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" @@ -2351,6 +2382,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MinGWX86_32TargetInfo(T); case llvm::Triple::Win32: return new VisualStudioWindowsX86_32TargetInfo(T); + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(T); default: return new X86_32TargetInfo(T); } diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index 810d0fb..e7275ca 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -31,13 +31,22 @@ using namespace clang; static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { - const Expr* Receiver = ME->getReceiver(); - - if (!Receiver) - return NULL; + QualType T; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + T = ME->getInstanceReceiver()->getType(); + break; + + case ObjCMessageExpr::SuperInstance: + T = ME->getSuperType(); + break; + + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + return 0; + } - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs()) + if (const ObjCObjectPointerType *PT = T->getAs()) return PT->getInterfaceType(); return NULL; @@ -509,11 +518,21 @@ public: void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - - const IdentifierInfo *ClsName = ME->getClassName(); - if (!ClsName) + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + Class = ME->getClassReceiver()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + Class = ME->getSuperType()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: return; - + } + Selector S = ME->getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; @@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, llvm::raw_svector_ostream os(buf); os << "The '" << S.getAsString() << "' message should be sent to instances " - "of class '" << ClsName->getName() + "of class '" << Class->getName() << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 7c53991..34470af 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, const VarDecl *VD = VR->getDecl(); // BasicStore does not model arrays and structs. - if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) + if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType()) return store; if (VD->hasGlobalStorage()) { diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 4475872..3bcc03f 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (D) { GetRawInt = false; - os << D->getNameAsString(); + os << D; } } diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 06cee5b..776e12b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) { } const Stmt* -clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){ - const Stmt *S = N->getLocationAs()->getStmt(); - if (const ObjCMessageExpr *ME = dyn_cast(S)) - return ME->getReceiver(); - return NULL; -} - -const Stmt* clang::bugreporter::GetDenomExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs()->getStmt(); if (const BinaryOperator *BE = dyn_cast(S)) @@ -144,7 +136,7 @@ public: if (const DeclStmt *DS = PS->getStmtAs()) { if (const VarRegion *VR = dyn_cast(R)) { - os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; + os << "Variable '" << VR->getDecl() << "' "; } else return NULL; @@ -206,7 +198,7 @@ public: return NULL; if (const VarRegion *VR = dyn_cast(R)) { - os << '\'' << VR->getDecl()->getNameAsString() << '\''; + os << '\'' << VR->getDecl() << '\''; } else return NULL; @@ -402,7 +394,7 @@ public: const ObjCMessageExpr *ME = P->getStmtAs(); if (!ME) return 0; - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); if (!Receiver) return 0; const GRState *state = N->getState(); diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 3c4a27c..d26ee1d 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -603,12 +603,33 @@ public: Selector S = ME->getSelector(); - if (Expr* Receiver = ME->getReceiver()) { - const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); - return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + const ObjCInterfaceDecl* OD = 0; + bool IsInstanceMessage = false; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + OD = getReceiverDecl(ME->getInstanceReceiver()); + IsInstanceMessage = true; + break; + + case ObjCMessageExpr::SuperInstance: + IsInstanceMessage = true; + OD = ME->getSuperType()->getAs() + ->getInterfaceDecl(); + break; + + case ObjCMessageExpr::Class: + OD = ME->getClassReceiver()->getAs()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + OD = ME->getSuperType()->getAs()->getDecl(); + break; } - return M[ObjCSummaryKey(ME->getClassName(), S)]; + if (IsInstanceMessage) + return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + + return M[ObjCSummaryKey(OD->getIdentifier(), S)]; } RetainSummary*& operator[](ObjCSummaryKey K) { @@ -836,7 +857,7 @@ public: RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { - return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), + return getInstanceMethodSummary(ME->getSelector(), 0, ID, ME->getMethodDecl(), ME->getType()); } @@ -851,8 +872,21 @@ public: QualType RetTy); RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { - return getClassMethodSummary(ME->getSelector(), ME->getClassName(), - ME->getClassInfo().Decl, + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + Class = ME->getReceiverInterface(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: + break; + } + + return getClassMethodSummary(ME->getSelector(), + Class? Class->getIdentifier() : 0, + Class, ME->getMethodDecl(), ME->getType()); } @@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, // We need the type-information of the tracked receiver object // Retrieve it from the state. - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); const ObjCInterfaceDecl* ID = 0; // FIXME: Is this really working as expected? There are cases where // we just use the 'ID' from the message expression. - SVal receiverV = state->getSValAsScalarOrLoc(Receiver); + SVal receiverV; + + if (const Expr *Receiver = ME->getInstanceReceiver()) { + receiverV = state->getSValAsScalarOrLoc(Receiver); - // FIXME: Eventually replace the use of state->get with - // a generic API for reasoning about the Objective-C types of symbolic - // objects. - if (SymbolRef Sym = receiverV.getAsLocSymbol()) - if (const RefVal *T = state->get(Sym)) - if (const ObjCObjectPointerType* PT = + // FIXME: Eventually replace the use of state->get with + // a generic API for reasoning about the Objective-C types of symbolic + // objects. + if (SymbolRef Sym = receiverV.getAsLocSymbol()) + if (const RefVal *T = state->get(Sym)) + if (const ObjCObjectPointerType* PT = T->getType()->getAs()) - ID = PT->getInterfaceDecl(); + ID = PT->getInterfaceDecl(); - // FIXME: this is a hack. This may or may not be the actual method - // that is called. - if (!ID) { - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs()) - ID = PT->getInterfaceDecl(); + // FIXME: this is a hack. This may or may not be the actual method + // that is called. + if (!ID) { + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs()) + ID = PT->getInterfaceDecl(); + } + } else { + // FIXME: Hack for 'super'. + ID = ME->getReceiverInterface(); } - + // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. RetainSummary *Summ = getInstanceMethodSummary(ME, ID); // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. - if (isa(LC->getDecl())) { + if (isa(LC->getDecl()) && Receiver) { if (const loc::MemRegionVal *L = dyn_cast(&receiverV)) { // Get the region associated with 'self'. if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { @@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); if (const FunctionDecl* FD = X.getAsFunctionDecl()) - os << "Call to function '" << FD->getNameAsString() <<'\''; + os << "Call to function '" << FD << '\''; else os << "function call"; } @@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } } else if (const ObjCMessageExpr *ME = dyn_cast(S)) { - if (const Expr *receiver = ME->getReceiver()) + if (const Expr *receiver = ME->getInstanceReceiver()) if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { // The symbol we are tracking is the receiver. AEffects.push_back(Summ->getReceiverEffect()); @@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). - const ObjCInterfaceDecl *D = ME->getClassInfo().Decl; + const ObjCInterfaceDecl *D = ME->getReceiverInterface(); return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); } @@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, RetEffect RE = Summ.getRetEffect(); if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { - assert(Receiver); - SVal V = state->getSValAsScalarOrLoc(Receiver); bool found = false; - if (SymbolRef Sym = V.getAsLocSymbol()) - if (state->get(Sym)) { - found = true; - RE = Summaries.getObjAllocRetEffect(); - } - + if (Receiver) { + SVal V = state->getSValAsScalarOrLoc(Receiver); + if (SymbolRef Sym = V.getAsLocSymbol()) + if (state->get(Sym)) { + found = true; + RE = Summaries.getObjAllocRetEffect(); + } + } // FIXME: Otherwise, this is a send-to-super instance message. if (!found) RE = RetEffect::MakeNoRet(); } @@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, ExplodedNode* Pred, const GRState *state) { RetainSummary *Summ = - ME->getReceiver() + ME->isInstanceMessage() ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); - EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL, + EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL, ME->arg_begin(), ME->arg_end(), Pred, state); } diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index dec375e..82e93a4 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -31,6 +31,7 @@ add_clang_library(clangChecker FlatStore.cpp GRBlockCounter.cpp GRCoreEngine.cpp + GRCXXExprEngine.cpp GRExprEngine.cpp GRExprEngineExperimentalChecks.cpp GRState.cpp diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index dd1856c9..c619d75 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, os << "Passed-by-value struct argument contains uninitialized data"; if (F.FieldChain.size() == 1) - os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() - << "')"; + os << " (e.g., field: '" << F.FieldChain[0] << "')"; else { os << " (e.g., via the field chain: '"; bool first = true; @@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, first = false; else os << '.'; - os << (*DI)->getNameAsString(); + os << *DI; } os << "')"; } @@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, const GRState *state = C.getState(); - if (const Expr *receiver = ME->getReceiver()) + // FIXME: Handle 'super'? + if (const Expr *receiver = ME->getInstanceReceiver()) if (state->getSVal(receiver).isUndef()) { if (ExplodedNode *N = C.GenerateSink()) { if (!BT_msg_undef) @@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, << ME->getType().getAsString() << "' that will be garbage"; EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); - const Expr *receiver = ME->getReceiver(); - report->addRange(receiver->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - receiver); + if (const Expr *receiver = ME->getInstanceReceiver()) { + report->addRange(receiver->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + } C.EmitReport(report); } @@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); - if (CanRetTy->isStructureType()) { + if (CanRetTy->isStructureOrClassType()) { // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead // have the "use of undefined value" be smarter about where the // undefined value came from. diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index 2c16f89..eeaed97 100644 --- a/lib/Checker/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, QualType OrigPointeeTy = OrigPTy->getPointeeType(); QualType ToPointeeTy = ToPTy->getPointeeType(); - if (!ToPointeeTy->isStructureType()) + if (!ToPointeeTy->isStructureOrClassType()) return; // We allow cast from void*. diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index d9606f1..c23be87 100644 --- a/lib/Checker/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -27,10 +27,14 @@ using namespace clang; static bool scan_dealloc(Stmt* S, Selector Dealloc) { if (ObjCMessageExpr* ME = dyn_cast(S)) - if (ME->getSelector() == Dealloc) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) - return isa(Receiver); + if (ME->getSelector() == Dealloc) { + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: return false; + case ObjCMessageExpr::SuperInstance: return true; + case ObjCMessageExpr::Class: break; + case ObjCMessageExpr::SuperClass: break; + } + } // Recurse to children. @@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, // [mMyIvar release] if (ObjCMessageExpr* ME = dyn_cast(S)) if (ME->getSelector() == Release) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (ObjCIvarRefExpr* E = dyn_cast(Receiver)) if (E->getDecl() == ID) return true; // [self setMyIvar:nil]; if (ObjCMessageExpr* ME = dyn_cast(S)) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (DeclRefExpr* E = dyn_cast(Receiver)) if (E->getDecl()->getIdentifier() == SelfII) if (ME->getMethodDecl() == PD->getSetterMethodDecl() && @@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "Objective-C class '" << D->getNameAsString() - << "' lacks a 'dealloc' instance method"; + os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method"; BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; @@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "The 'dealloc' instance method in Objective-C class '" - << D->getNameAsString() + os << "The 'dealloc' instance method in Objective-C class '" << D << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; @@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "missing ivar release (leak)" : "missing ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was retained by a synthesized property but " "wasn't released in 'dealloc'"; } else { @@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "extra ivar release (use-after-release)" : "extra ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was not retained by a synthesized property " "but was released in 'dealloc'"; } diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp index 8c43a45..76a0923 100644 --- a/lib/Checker/CheckObjCInstMethSignature.cpp +++ b/lib/Checker/CheckObjCInstMethSignature.cpp @@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, llvm::raw_string_ostream os(sbuf); os << "The Objective-C class '" - << MethDerived->getClassInterface()->getNameAsString() + << MethDerived->getClassInterface() << "', which is derived from class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "', defines the instance method '" << MethDerived->getSelector().getAsString() << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "' and has a return type of '" << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index efbce61..74e12b1 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; + os1 << '\'' << FD << "' is a poor random number generator"; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "Function '" << FD->getNameAsString() + os2 << "Function '" << FD << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; @@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "Return value is not checked in call to '" << FD->getNameAsString() - << "'"; + os1 << "Return value is not checked in call to '" << FD << '\''; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "The return value from the call to '" << FD->getNameAsString() - << "' is not checked. If an error occurs in '" - << FD->getNameAsString() + os2 << "The return value from the call to '" << FD + << "' is not checked. If an error occurs in '" << FD << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index be1a677..addfc21 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { return ValMgr.makeIntVal(C->getValue(), C->getType()); } + case Stmt::CXXBoolLiteralExprClass: { + const SVal *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast(E)); + } case Stmt::IntegerLiteralClass: { // In C++, this expression may have been bound to a temporary object. SVal const *X = ExprBindings.lookup(E); diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp new file mode 100644 index 0000000..00ac995 --- /dev/null +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -0,0 +1,246 @@ +//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ expression evaluation engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; + +void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE, + const FunctionProtoType *FnType, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + llvm::SmallVector WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + Dst.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AI; + bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType() + : false; + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); +} + +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + +void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } + + const CXXConstructorDecl *CD = E->getConstructor(); + assert(CD); + + if (!CD->isThisDeclarationADefinition()) + // FIXME: invalidate the object. + return; + + + // Evaluate other arguments. + ExplodedNodeSet ArgsEvaluated; + const FunctionProtoType *FnType = CD->getType()->getAs(); + EvalArguments(const_cast(E)->arg_begin(), + const_cast(E)->arg_end(), + FnType, Pred, ArgsEvaluated); + // The callee stack frame context used to create the 'this' parameter region. + const StackFrameContext *SFC = AMgr.getStackFrame(CD, + Pred->getLocationContext(), + E, Builder->getBlock(), Builder->getIndex()); + + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); + + CallEnter Loc(E, CD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), + NE = ArgsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region. + state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + ExplodedNodeSet ArgsEvaluated; + EvalArguments(const_cast(MCE)->arg_begin(), + const_cast(MCE)->arg_end(), + FnType, Pred, ArgsEvaluated); + + // Evaluate the implicit object argument. + ExplodedNodeSet AllArgsEvaluated; + const MemberExpr *ME = dyn_cast(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(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (CNE->isArray()) { + // FIXME: allocating an array has not been handled. + return; + } + + unsigned Count = Builder->getCurrentBlockCount(); + DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, + CNE->getType(), Count); + const MemRegion *NewReg = cast(SymVal).getRegion(); + + QualType ObjTy = CNE->getType()->getAs()->getPointeeType(); + + const ElementRegion *EleReg = + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + + // Evaluate constructor arguments. + const FunctionProtoType *FnType = NULL; + const CXXConstructorDecl *CD = CNE->getConstructor(); + if (CD) + FnType = CD->getType()->getAs(); + ExplodedNodeSet ArgsEvaluated; + EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), + FnType, Pred, ArgsEvaluated); + + // Initialize the object region and bind the 'new' expression. + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + if (ObjTy->isRecordType()) { + Store store = state->getStore(); + StoreManager::InvalidatedSymbols IS; + store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS); + state = state->makeWithStore(store); + } else { + if (CNE->hasInitializer()) { + SVal V = state->getSVal(*CNE->constructor_arg_begin()); + state = state->bindLoc(loc::MemRegionVal(EleReg), V); + } else { + // Explicitly set to undefined, because currently we retrieve symbolic + // value from symbolic region. + state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); + } + } + state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); + MakeNode(Dst, CNE, *I, state); + } +} + +void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Should do more checking. + ExplodedNodeSet ArgEvaluated; + Visit(CDE->getArgument(), Pred, ArgEvaluated); + for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(), + E = ArgEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + MakeNode(Dst, CDE, *I, state); + } +} + +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the this object region from StoreManager. + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion( + getContext().getCanonicalType(TE->getType()), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); +} diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index e4ef6b0..23a87d3 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { Eng.WList->Enqueue(Succ, B, Idx+1); } +ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K) { + const GRState* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; +} + static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const void *tag){ switch (K) { diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index bab8922..67090b8 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXNamedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXReinterpretCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::CXXTypeidExprClass: - case Stmt::CXXBoolLiteralExprClass: - case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXThrowExprClass: - case Stmt::CXXDefaultArgExprClass: - case Stmt::CXXZeroInitValueExprClass: - case Stmt::CXXNewExprClass: - case Stmt::CXXDeleteExprClass: - case Stmt::CXXPseudoDestructorExprClass: - case Stmt::UnresolvedLookupExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::DependentScopeDeclRefExprClass: - case Stmt::CXXConstructExprClass: + case Stmt::CXXBindReferenceExprClass: case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXTryStmtClass: + case Stmt::CXXTypeidExprClass: case Stmt::CXXUnresolvedConstructExprClass: - case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: - case Stmt::CXXCatchStmtClass: - case Stmt::CXXTryStmtClass: { + { SaveAndRestore OldSink(Builder->BuildSinks); Builder->BuildSinks = true; MakeNode(Dst, S, Pred, GetState(Pred)); break; } - default: - // Cases we intentionally have "default" handle: - // AddrLabelExpr, IntegerLiteral, CharacterLiteral + // Cases that should never be evaluated simply because they shouldn't + // appear in the CFG. + case Stmt::BreakStmtClass: + case Stmt::CaseStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::DoStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::LabelStmtClass: + case Stmt::NoStmtClass: + case Stmt::NullStmtClass: + case Stmt::SwitchCaseClass: + llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + break; + // Cases not handled yet; but will handle some day. + case Stmt::DesignatedInitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::GNUNullExprClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ObjCSuperExprClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::VAArgExprClass: + // Fall through. + + // Cases we intentionally don't evaluate, since they don't need + // to be explicitly evaluated. + case Stmt::AddrLabelExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::FloatingLiteralClass: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; @@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXNewExprClass: { + CXXNewExpr *NE = cast(S); + VisitCXXNewExpr(NE, Pred, Dst); + break; + } + + case Stmt::CXXDeleteExprClass: { + CXXDeleteExpr *CDE = cast(S); + VisitCXXDeleteExpr(CDE, Pred, Dst); + break; + } // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: { + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: { CastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; @@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitReturnStmt(cast(S), Pred, Dst); break; + case Stmt::OffsetOfExprClass: + VisitOffsetOfExpr(cast(S), Pred, Dst); + break; + case Stmt::SizeOfAlignOfExprClass: VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); break; @@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::CXXBoolLiteralExprClass: case Stmt::IntegerLiteralClass: CreateCXXTemporaryObject(Ex, Pred, Dst); return; @@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } } -//===----------------------------------------------------------------------===// -// Transfer function: Function calls. -//===----------------------------------------------------------------------===// - -namespace { -class CallExprWLItem { -public: - CallExpr::arg_iterator I; - ExplodedNode *N; - - CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} // end anonymous namespace - void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, @@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, continue; } - const GRState* state = Pred->getState(); + const GRState* state = GetState(Pred); SVal V = state->getSVal(Ex); if (nonloc::SymExprVal *SEV = dyn_cast(&V)) { // First assume that the condition is true. @@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // But first evaluate the receiver (if any). ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (Expr *Receiver = ME->getReceiver()) { + if (Expr *Receiver = ME->getInstanceReceiver()) { ExplodedNodeSet Tmp; Visit(Receiver, Pred, Tmp); @@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, SaveAndRestore OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); - if (const Expr *Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); + if (const Expr *Receiver = ME->getInstanceReceiver()) { + const GRState *state = GetState(Pred); // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = @@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Dispatch to plug-in transfer function. EvalObjCMessageExpr(DstEval, ME, Pred, notNilState); } - else { - IdentifierInfo* ClsName = ME->getClassName(); + else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { + IdentifierInfo* ClsName = Iface->getIdentifier(); Selector S = ME->getSelector(); // Check for special instance methods. @@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, QualType T = getContext().getCanonicalType(E->getType()); unsigned NumInitElements = E->getNumInits(); - if (T->isArrayType() || T->isStructureType() || - T->isUnionType() || T->isVectorType()) { - + if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { llvm::ImmutableList StartVals = getBasicVals().getEmptySValList(); // Handle base case where the initializer has no elements. @@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } +void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + Expr::EvalResult Res; + if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); + assert(OOE->getType()->isIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.Add(Pred); +} void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { @@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, case UnaryOperator::OffsetOf: { Expr::EvalResult Res; if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); - assert(U->getType()->isIntegerType()); - assert(IV.isSigned() == U->getType()->isSignedIntegerType()); - SVal X = ValMgr.makeIntVal(IV); - MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); - return; - } + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); + assert(U->getType()->isIntegerType()); + assert(IV.isSigned() == U->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); + return; + } // FIXME: Handle the case where __builtin_offsetof is not a constant. Dst.Add(Pred); return; } - + case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH. case UnaryOperator::Extension: { @@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } - -void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet & Dst) { - // Get the this object region from StoreManager. - const MemRegion *R = - ValMgr.getRegionManager().getCXXThisRegion( - getContext().getCanonicalType(TE->getType()), - Pred->getLocationContext()); - - const GRState *state = GetState(Pred); - SVal V = state->getSVal(loc::MemRegionVal(R)); - MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); -} - void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); @@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, ExplodedNodeSet Tmp3; for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { - SVal LeftV = (*I1)->getState()->getSVal(LHS); + SVal LeftV = GetState(*I1)->getSVal(LHS); ExplodedNodeSet Tmp2; Visit(RHS, *I1, Tmp2); @@ -3147,184 +3190,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } -void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - const GRState *state = GetState(*I); - - // Bind the temporary object to the value of the expression. Then bind - // the expression to the location of the object. - SVal V = state->getSVal(Ex); - - const MemRegion *R = - ValMgr.getRegionManager().getCXXObjectRegion(Ex, - Pred->getLocationContext()); - - state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } -} - -void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (E->isElidable()) { - VisitAggExpr(E->getArg(0), Dest, Pred, Dst); - return; - } - - const CXXConstructorDecl *CD = E->getConstructor(); - assert(CD); - - if (!CD->isThisDeclarationADefinition()) - // FIXME: invalidate the object. - return; - - - // Evaluate other arguments. - CXXConstructExpr::arg_iterator AB - = const_cast(E)->arg_begin(); - CXXConstructExpr::arg_iterator AE - = const_cast(E)->arg_end(); - llvm::SmallVector WorkList; - WorkList.reserve(AE - AB); - WorkList.push_back(CallExprWLItem(AB, Pred)); - ExplodedNodeSet ArgsEvaluated; - const FunctionProtoType *Proto = CD->getType()->getAs(); - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - // Evaluate the argument. - ExplodedNodeSet Tmp; - const unsigned ParamIdx = Item.I - AB; - - bool VisitAsLvalue = false; - - if (ParamIdx < Proto->getNumArgs()) - VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - - if (VisitAsLvalue) - VisitLValue(*Item.I, Item.N, Tmp); - else - Visit(*Item.I, Item.N, Tmp); - - ++(Item.I); - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } - // The callee stack frame context used to create the 'this' parameter region. - const StackFrameContext *SFC = AMgr.getStackFrame(CD, - Pred->getLocationContext(), - E, Builder->getBlock(), Builder->getIndex()); - - const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); - - CallEnter Loc(E, CD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), - NE = ArgsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); - // Setup 'this' region. - state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) - Dst.Add(N); - } -} - -void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - CallExpr::arg_iterator AB = const_cast(MCE)->arg_begin(), - AE = const_cast(MCE)->arg_end(); - llvm::SmallVector 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(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(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - - if (!MD->isThisDeclarationADefinition()) - // FIXME: conservative method call evaluation. - return; - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, MD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), - E = AllArgsEvaluated.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); - ExplodedNode *N = Builder->generateNode(Loc, state, *I); - if (N) - Dst.Add(N); - } -} - -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, - const StackFrameContext *SFC) { - Type *T = D->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); - return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); -} - //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9f12ab6..9a664c7 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { } void FieldRegion::dumpToStream(llvm::raw_ostream& os) const { - os << superRegion << "->" << getDecl()->getNameAsString(); + os << superRegion << "->" << getDecl(); } void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}'; + os << "ivar{" << superRegion << ',' << getDecl() << '}'; } void StringRegion::dumpToStream(llvm::raw_ostream& os) const { @@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const { } void VarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << cast(D)->getNameAsString(); + os << cast(D); } void RegionRawOffset::dump() const { @@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { const MemRegion *MemRegion::getBaseRegion() const { const MemRegion *R = this; while (true) { - if (const ElementRegion *ER = dyn_cast(R)) { - R = ER->getSuperRegion(); - continue; - } - if (const FieldRegion *FR = dyn_cast(R)) { - R = FR->getSuperRegion(); - continue; + switch (R->getKind()) { + case MemRegion::ElementRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + R = cast(R)->getSuperRegion(); + continue; + default: + break; } break; } diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp index 29bac9c..48f03a3 100644 --- a/lib/Checker/NSAutoreleasePoolChecker.cpp +++ b/lib/Checker/NSAutoreleasePoolChecker.cpp @@ -56,7 +56,7 @@ void NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - const Expr *receiver = ME->getReceiver(); + const Expr *receiver = ME->getInstanceReceiver(); if (!receiver) return; diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index 9130bfa..e30d54c 100644 --- a/lib/Checker/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, else os << "documented in CoreFoundation/CFError.h the parameter '"; - os << Param->getNameAsString() << "' may be null."; + os << Param << "' may be null."; BugReport *report = new BugReport(*this, os.str(), *I); // FIXME: Notable symbols are now part of the report. We should diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index 04d897a..0e47621 100644 --- a/lib/Checker/ObjCUnusedIVarsChecker.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << "Instance variable '" << I->first->getNameAsString() - << "' in class '" << ID->getNameAsString() + os << "Instance variable '" << I->first << "' in class '" << ID << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index c97da33..1e15d43 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -14,22 +14,22 @@ // parameters are created lazily. // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Support/Optional.h" -#include "clang/Basic/TargetInfo.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" - -#include "llvm/ADT/ImmutableMap.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/MemRegion.h" #include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using llvm::Optional; //===----------------------------------------------------------------------===// // Representation of binding keys. @@ -346,8 +346,6 @@ public: // Part of public interface to class. Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store, const TypedRegion *R); - const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); - //===------------------------------------------------------------------===// // State pruning. //===------------------------------------------------------------------===// @@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { return true; } -const ElementRegion * -RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) { - ASTContext &Ctx = getContext(); - SVal idx = ValMgr.makeZeroArrayIndex(); - assert(!T.isNull()); - return MRMgr.getElementRegion(T, idx, R, Ctx); -} - SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } #endif - if (RTy->isStructureType() || RTy->isClassType()) + if (RTy->isStructureOrClassType()) return RetrieveStruct(store, R); // FIXME: Handle unions. @@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); - assert(T->isStructureType() || T->isClassType()); + assert(T->isStructureOrClassType()); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast(R)) - if (TR->getValueType(getContext())->isStructureType()) + if (TR->getValueType(getContext())->isStructureOrClassType()) return BindStruct(store, TR, V); // Special case: the current region represents a cast and it and the super @@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR, if (T->isArrayType()) return BindArray(store, VR, InitVal); - if (T->isStructureType()) + if (T->isStructureOrClassType()) return BindStruct(store, VR, InitVal); return Bind(store, ValMgr.makeLoc(VR), InitVal); @@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store, V = ValMgr.makeNull(); else if (T->isIntegerType()) V = ValMgr.makeZeroVal(T); - else if (T->isStructureType() || T->isArrayType()) { + else if (T->isStructureOrClassType() || T->isArrayType()) { // Set the default value to a zero constant when it is a structure // or array. The type doesn't really matter. V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy); @@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, SVal Idx = ValMgr.makeArrayIndex(i); const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); - if (ElementTy->isStructureType()) + if (ElementTy->isStructureOrClassType()) store = BindStruct(store, ER, *VI); else store = Bind(store, ValMgr.makeLoc(ER), *VI); @@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, return store; QualType T = R->getValueType(getContext()); - assert(T->isStructureType()); + assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs(); RecordDecl* RD = RT->getDecl(); @@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, if (FTy->isArrayType()) store = BindArray(store, FR, *VI); - else if (FTy->isStructureType()) + else if (FTy->isStructureOrClassType()) store = BindStruct(store, FR, *VI); else store = Bind(store, ValMgr.makeLoc(FR), *VI); diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp index 4bfa2cd..d756be7 100644 --- a/lib/Checker/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const { } case nonloc::LazyCompoundValKind: { const nonloc::LazyCompoundVal &C = *cast(this); - os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion() + os << "lazyCompoundVal{" << const_cast(C.getStore()) + << ',' << C.getRegion() << '}'; break; } diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp index fb1d74a..dd38a43 100644 --- a/lib/Checker/SimpleSValuator.cpp +++ b/lib/Checker/SimpleSValuator.cpp @@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) { if (castTy->isUnionType()) return UnknownVal(); - assert(castTy->isIntegerType()); - unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); + if (castTy->isIntegerType()) { + unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); - if (!isa(val)) - return ValMgr.makeLocAsInteger(val, BitWidth); + if (!isa(val)) + return ValMgr.makeLocAsInteger(val, BitWidth); - llvm::APSInt i = cast(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); - i.extOrTrunc(BitWidth); - return ValMgr.makeIntVal(i); + llvm::APSInt i = cast(val).getValue(); + i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); + i.extOrTrunc(BitWidth); + return ValMgr.makeIntVal(i); + } + + // All other cases: return 'UnknownVal'. This includes casting pointers + // to floats, which is probably badness it itself, but this is a good + // intermediate solution until we do something better. + return UnknownVal(); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp index e524cb3..c12065b 100644 --- a/lib/Checker/Store.cpp +++ b/lib/Checker/Store.cpp @@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { return true; } +const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, + QualType T) { + SVal idx = ValMgr.makeZeroArrayIndex(); + assert(!T.isNull()); + return MRMgr.getElementRegion(T, idx, R, Ctx); +} + const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) { ASTContext& Ctx = StateMgr.getContext(); @@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); - - // Is the offset a multiple of the size? If so, we can layer the - // ElementRegion (with elementType == PointeeTy) directly on top of - // the base region. - if (off % pointeeTySize == 0) { - newIndex = off / pointeeTySize; - newSuperR = baseR; + if (!pointeeTySize.isZero()) { + // Is the offset a multiple of the size? If so, we can layer the + // ElementRegion (with elementType == PointeeTy) directly on top of + // the base region. + if (off % pointeeTySize == 0) { + newIndex = off / pointeeTySize; + newSuperR = baseR; + } } } diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index d75e5d2..e9b8f09 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -13,23 +13,30 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include using namespace clang; +using llvm::Optional; namespace { class UnixAPIChecker : public CheckerVisitor { enum SubChecks { OpenFn = 0, + PthreadOnceFn = 1, NumChecks }; BugType *BTypes[NumChecks]; public: + Optional Val_O_CREAT; + +public: UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } static void *getTag() { static unsigned tag = 0; return &tag; } @@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) { // "open" (man 2 open) //===----------------------------------------------------------------------===// -static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { +static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT) { + // The definition of O_CREAT is platform specific. We need a better way + // of querying this information from the checking environment. + if (!UC.Val_O_CREAT.hasValue()) { + if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + UC.Val_O_CREAT = 0x0200; + else { + // FIXME: We need a more general way of getting the O_CREAT value. + // We could possibly grovel through the preprocessor state, but + // that would require passing the Preprocessor object to the GRExprEngine. + return; + } + } + LazyInitialize(BT, "Improper use of 'open'"); // Look at the 'oflags' argument for the O_CREAT flag. @@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } NonLoc oflags = cast(V); NonLoc ocreateFlag = - cast(C.getValueManager().makeIntVal((uint64_t) O_CREAT, + cast(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(), oflagsEx->getType())); SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, oflags, ocreateFlag, @@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } //===----------------------------------------------------------------------===// +// pthread_once +//===----------------------------------------------------------------------===// + +static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &, + const CallExpr *CE, BugType *&BT) { + + // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. + // They can possibly be refactored. + + LazyInitialize(BT, "Improper use of 'pthread_once'"); + + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is stack allocated. If so, issue a warning + // because that's likely to be bad news. + const GRState *state = C.getState(); + const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); + if (!R || !isa(R->getMemorySpace())) + return; + + ExplodedNode *N = C.GenerateSink(state); + if (!N) + return; + + llvm::SmallString<256> S; + llvm::raw_svector_ostream os(S); + os << "Call to 'pthread_once' uses"; + if (const VarRegion *VR = dyn_cast(R)) + os << " the local variable '" << VR->getDecl()->getName() << '\''; + else + os << " stack allocated memory"; + os << " for the \"control\" value. Using such transient memory for " + "the control value is potentially dangerous."; + if (isa(R) && isa(R->getMemorySpace())) + os << " Perhaps you intended to declare the variable as 'static'?"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// // Central dispatch function. //===----------------------------------------------------------------------===// -typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT); +typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT); namespace { class SubCheck { SubChecker SC; + UnixAPIChecker *UC; BugType **BT; public: - SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} - SubCheck() : SC(NULL), BT(NULL) {} + SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc), + BT(&bt) {} + SubCheck() : SC(NULL), UC(NULL), BT(NULL) {} void run(CheckerContext &C, const CallExpr *CE) const { if (SC) - SC(C, CE, *BT); + SC(C, *UC, CE, *BT); } }; } // end anonymous namespace @@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const SubCheck &SC = llvm::StringSwitch(FI->getName()) - .Case("open", SubCheck(CheckOpen, BTypes[OpenFn])) + .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn])) + .Case("pthread_once", SubCheck(CheckPthreadOnce, this, + BTypes[PthreadOnceFn])) .Default(SubCheck()); SC.run(C, CE); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 5097341..db24def 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -706,7 +706,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, BlockDeclRefDecls); // FIXME: This leaks ImplicitParamDecl *SelfDecl = - ImplicitParamDecl::Create(getContext(), 0, + ImplicitParamDecl::Create(getContext(), const_cast(BD), SourceLocation(), II, ParmTy); @@ -812,7 +812,8 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { Pad.getQuantity()), ArrayType::Normal, 0); ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), - 0, QualType(PadTy), 0, VarDecl::None); + 0, QualType(PadTy), 0, + VarDecl::None, VarDecl::None); Expr *E; E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), SourceLocation()); @@ -860,7 +861,9 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -941,8 +944,9 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); if (NoteForHelperp) { @@ -1025,8 +1029,9 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); // dst->x @@ -1089,8 +1094,9 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); llvm::Value *V = CGF.GetAddrOfLocalVar(Src); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index efee0e3..5646d00 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -38,6 +38,7 @@ namespace llvm { class GlobalValue; class TargetData; class FunctionType; + class PointerType; class Value; class LLVMContext; } @@ -127,7 +128,7 @@ protected: llvm::LLVMContext &VMContext; public: - const llvm::Type *PtrToInt8Ty; + const llvm::PointerType *PtrToInt8Ty; struct HelperInfo { int index; int flag; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 38c40ed..95c41db 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -682,13 +682,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BIsqrt: case Builtin::BIsqrtf: case Builtin::BIsqrtl: { - // Rewrite sqrt to intrinsic if allowed. - if (!FD->hasAttr()) - break; - Value *Arg0 = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ArgType = Arg0->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1); - return RValue::get(Builder.CreateCall(F, Arg0, "tmp")); + // TODO: there is currently no set of optimizer flags + // sufficient for us to rewrite sqrt to @llvm.sqrt. + // -fmath-errno=0 is not good enough; we need finiteness. + // We could probably precondition the call with an ult + // against 0, but is that worth the complexity? + break; } case Builtin::BIpow: @@ -983,8 +982,38 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateStore(Ops[1], Ops[0]); } case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); + unsigned shiftVal = cast(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 9 bytes, + // emit a shuffle instruction. + if (shiftVal <= 8) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector Indices; + for (unsigned i = 0; i != 8; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 8 but less + // than 16 bytes, emit a logical right shift of the destination. + if (shiftVal < 16) { + // MMX has these as 1 x i64 vectors for some odd optimization reasons. + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); } case X86::BI__builtin_ia32_palignr128: { unsigned shiftVal = cast(Ops[2])->getZExtValue(); @@ -1025,5 +1054,49 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + llvm::SmallVector Ops; + + for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: return 0; + + // vec_st + case PPC::BI__builtin_altivec_stvx: + case PPC::BI__builtin_altivec_stvxl: + case PPC::BI__builtin_altivec_stvebx: + case PPC::BI__builtin_altivec_stvehx: + case PPC::BI__builtin_altivec_stvewx: + { + Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext)); + Ops[1] = !isa(Ops[1]) || !cast(Ops[1])->isNullValue() + ? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2]; + Ops.pop_back(); + + switch (BuiltinID) { + default: assert(0 && "Unsupported vavg intrinsic!"); + case PPC::BI__builtin_altivec_stvx: + ID = Intrinsic::ppc_altivec_stvx; + break; + case PPC::BI__builtin_altivec_stvxl: + ID = Intrinsic::ppc_altivec_stvxl; + break; + case PPC::BI__builtin_altivec_stvebx: + ID = Intrinsic::ppc_altivec_stvebx; + break; + case PPC::BI__builtin_altivec_stvehx: + ID = Intrinsic::ppc_altivec_stvehx; + break; + case PPC::BI__builtin_altivec_stvewx: + ID = Intrinsic::ppc_altivec_stvewx; + break; + } + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), ""); + } + } return 0; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 93a182f..74cf113 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -297,15 +297,15 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name, getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer()); } -static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty); - Vtable = CGF.Builder.CreateLoad(Vtable); + llvm::Value *VTable = CGF.Builder.CreateBitCast(This, Ty); + VTable = CGF.Builder.CreateLoad(VTable); llvm::Value *VFuncPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn"); + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); return CGF.Builder.CreateLoad(VFuncPtr); } @@ -313,7 +313,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } @@ -323,7 +323,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast(DD->getCanonicalDecl()); uint64_t VTableIndex = - CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type)); + CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index cb1ecc1..92d15d9 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -528,7 +528,7 @@ static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) { } const llvm::Type * -CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) { +CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->getAs(); if (!HasIncompleteReturnTypeOrArgumentTypes(FPT)) @@ -586,8 +586,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, case ABIArgInfo::Indirect: PAL.push_back(llvm::AttributeWithIndex::get(Index, - llvm::Attribute::StructRet | - llvm::Attribute::NoAlias)); + llvm::Attribute::StructRet)); ++Index; // sret disables readnone and readonly FuncAttrs &= ~(llvm::Attribute::ReadOnly | @@ -870,7 +869,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &CallArgs, - const Decl *TargetDecl) { + const Decl *TargetDecl, + llvm::Instruction **callOrInvoke) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. llvm::SmallVector Args; @@ -996,6 +996,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Args.data(), Args.data()+Args.size()); EmitBlock(Cont); } + if (callOrInvoke) { + *callOrInvoke = CS.getInstruction(); + } CS.setAttributes(Attrs); CS.setCallingConv(static_cast(CallingConv)); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 177e862..a604eef 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -20,65 +20,61 @@ using namespace clang; using namespace CodeGen; static uint64_t -ComputeNonVirtualBaseClassOffset(ASTContext &Context, - const CXXBasePath &Path, - unsigned Start) { +ComputeNonVirtualBaseClassOffset(ASTContext &Context, + const CXXRecordDecl *DerivedClass, + CXXBaseSpecifierArray::iterator Start, + CXXBaseSpecifierArray::iterator End) { uint64_t Offset = 0; - - for (unsigned i = Start, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; + + const CXXRecordDecl *RD = DerivedClass; + + for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) { + const CXXBaseSpecifier *Base = *I; + assert(!Base->isVirtual() && "Should not see virtual bases here!"); // Get the layout. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXBaseSpecifier *BS = Element.Base; - assert(!BS->isVirtual() && "Should not see virtual bases here!"); - - const CXXRecordDecl *Base = - cast(BS->getType()->getAs()->getDecl()); + const CXXRecordDecl *BaseDecl = + cast(Base->getType()->getAs()->getDecl()); // Add the offset. - Offset += Layout.getBaseClassOffset(Base) / 8; + Offset += Layout.getBaseClassOffset(BaseDecl); + + RD = BaseDecl; } - - return Offset; + + // FIXME: We should not use / 8 here. + return Offset / 8; } llvm::Constant * -CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass) { - if (Class == BaseClass) - return 0; - - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(Class)-> - isDerivedFrom(const_cast(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } +CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, + const CXXBaseSpecifierArray &BasePath) { + assert(!BasePath.empty() && "Base path should not be empty!"); - uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), - Paths.front(), 0); + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, + BasePath.begin(), BasePath.end()); if (!Offset) return 0; - + const llvm::Type *PtrDiffTy = - Types.ConvertType(getContext().getPointerDiffType()); - + Types.ConvertType(getContext().getPointerDiffType()); + return llvm::ConstantInt::get(PtrDiffTy, Offset); } -/// Gets the address of a virtual base class within a complete object. +/// Gets the address of a direct base class within a complete object. /// This should only be used for (1) non-virtual bases or (2) virtual bases /// when the type is known to be complete (e.g. in complete destructors). /// /// The object pointed to by 'This' is assumed to be non-null. llvm::Value * -CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, - bool isBaseVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base) { +CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual) { // 'this' must be a pointer (in some address space) to Derived. assert(This->getType()->isPointerTy() && cast(This->getType())->getElementType() @@ -87,7 +83,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, // Compute the offset of the virtual base. uint64_t Offset; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); - if (isBaseVirtual) + if (BaseIsVirtual) Offset = Layout.getVBaseClassOffset(Base); else Offset = Layout.getBaseClassOffset(Base); @@ -105,51 +101,63 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, return V; } -llvm::Value * -CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool NullCheckValue) { - QualType BTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(BaseClass)); - const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); - - if (Class == BaseClass) { - // Just cast back. - return Builder.CreateBitCast(Value, BasePtrTy); - } +static llvm::Value * +ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, + uint64_t NonVirtual, llvm::Value *Virtual) { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + llvm::Value *NonVirtualOffset = 0; + if (NonVirtual) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual); + + llvm::Value *BaseOffset; + if (Virtual) { + if (NonVirtualOffset) + BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset); + else + BaseOffset = Virtual; + } else + BaseOffset = NonVirtualOffset; + + // Apply the base offset. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); + ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr"); - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(Class)-> - isDerivedFrom(const_cast(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } + return ThisPtr; +} - unsigned Start = 0; - llvm::Value *VirtualOffset = 0; +llvm::Value * +CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, + bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); - const CXXBasePath &Path = Paths.front(); + CXXBaseSpecifierArray::iterator Start = BasePath.begin(); const CXXRecordDecl *VBase = 0; - for (unsigned i = 0, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; - if (Element.Base->isVirtual()) { - Start = i+1; - QualType VBaseType = Element.Base->getType(); - VBase = cast(VBaseType->getAs()->getDecl()); - } + + // Get the virtual base. + if ((*Start)->isVirtual()) { + VBase = + cast((*Start)->getType()->getAs()->getDecl()); + ++Start; } + + uint64_t NonVirtualOffset = + ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, + Start, BasePath.end()); - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); + // Get the base pointer type. + const llvm::Type *BasePtrTy = + ConvertType((BasePath.end()[-1])->getType())->getPointerTo(); - if (!Offset && !VBase) { + if (!NonVirtualOffset && !VBase) { // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } - + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -165,28 +173,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } - + + llvm::Value *VirtualOffset = 0; + if (VBase) - VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase); + VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = 0; - if (Offset) - NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - llvm::Value *BaseOffset; - if (VBase) { - if (NonVirtualOffset) - BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - else - BaseOffset = VirtualOffset; - } else - BaseOffset = NonVirtualOffset; - - // Apply the base offset. - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - Value = Builder.CreateBitCast(Value, Int8PtrTy); - Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr"); + // Apply the offsets. + Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, + VirtualOffset); // Cast back. Value = Builder.CreateBitCast(Value, BasePtrTy); @@ -210,21 +205,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); + QualType DerivedTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast(DerivedClass))); + getContext().getCanonicalType(getContext().getTagDeclType(Derived)); const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); - if (Class == DerivedClass) { - // Just cast back. - return Builder.CreateBitCast(Value, DerivedPtrTy); - } - llvm::Value *NonVirtualOffset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class); + CGM.GetNonVirtualBaseClassOffset(Derived, BasePath); if (!NonVirtualOffset) { // No offset, we can just cast back. @@ -274,23 +265,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, /// EmitCopyCtorCall - Emit a call to a copy constructor. static void -EmitCopyCtorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType, - llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) { - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType); +EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor, + llvm::Value *ThisPtr, llvm::Value *Src) { + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete); CallArgList CallArgs; // Push the this ptr. CallArgs.push_back(std::make_pair(RValue::get(ThisPtr), CopyCtor->getThisType(CGF.getContext()))); - - // Push the VTT parameter if necessary. - if (VTT) { - QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy); - CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); - } - + // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); @@ -325,13 +309,8 @@ EmitCopyCtorCall(CodeGenFunction &CGF, // FIXME. Consolidate this with EmitCXXAggrConstructorCall. void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast(Array); - assert(CA && "VLA cannot be copied over"); - bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); - + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl) { // Create a temporary for the loop index and initialize it with 0. llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), "loop.index"); @@ -347,7 +326,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::BasicBlock *ForBody = createBasicBlock("for.body"); // Generate: if (loop-index < number-of-elements fall to the loop body, // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + uint64_t NumElements = getContext().getConstantArrayElementCount(Array); llvm::Value * NumElementsPtr = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); @@ -362,95 +341,8 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, Counter = Builder.CreateLoad(IndexPtr); Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - if (BitwiseCopy) - EmitAggregateCopy(Dest, Src, Ty); - else if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) - EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitClassAggrCopyAssignment - This routine generates code to assign a class -/// array of objects from SrcValue to DestValue. Assignment can be either a -/// bitwise assignment or via a copy assignment operator function call. -/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy -void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, - llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast(Array); - assert(CA && "VLA cannot be asssigned"); - bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr); - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the assignment operator call on array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - const CXXMethodDecl *MD = 0; - if (BitwiseAssign) - EmitAggregateCopy(Dest, Src, Ty); - else { - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassAggrCopyAssignment - No user assign"); - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); - } + EmitClassMemberwiseCopy(Dest, Src, ClassDecl); + EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -468,7 +360,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. -static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { +static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, + bool ForVirtualBase) { if (!CodeGenVTables::needsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return 0; @@ -486,9 +379,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { if (RD == Base) { assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && "doing no-op VTT offset in base dtor/ctor?"); + assert(!ForVirtualBase && "Can't have same class as virtual base!"); SubVTTIndex = 0; } else { - SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base); + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = ForVirtualBase ? + Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base); + + SubVTTIndex = + CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } @@ -511,75 +411,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { /// or via a copy constructor call. void CodeGenFunction::EmitClassMemberwiseCopy( llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, QualType Ty) { - CXXCtorType CtorType = Ctor_Complete; - - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - - // We want to call the base constructor. - CtorType = Ctor_Base; - } - if (BaseClassDecl->hasTrivialCopyConstructor()) { - EmitAggregateCopy(Dest, Src, Ty); + const CXXRecordDecl *ClassDecl) { + if (ClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl)); return; } - CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0); - if (!BaseCopyCtor) - return; + CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0); + assert(CopyCtor && "Did not have copy ctor!"); - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType)); - EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src); -} - -/// EmitClassCopyAssignment - This routine generates code to copy assign a class -/// object from SrcValue to DestValue. Assignment can be either a bitwise -/// assignment of via an assignment operator call. -// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. -void CodeGenFunction::EmitClassCopyAssignment( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - } - if (BaseClassDecl->hasTrivialCopyAssignment()) { - EmitAggregateCopy(Dest, Src, Ty); - return; - } - - const CXXMethodDecl *MD = 0; - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassCopyAssignment - missing copy assign"); - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); + EmitCopyCtorCall(*this, CopyCtor, Dest, Src); } /// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a @@ -600,30 +441,25 @@ void CodeGenFunction::EmitClassCopyAssignment( void CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { const CXXConstructorDecl *Ctor = cast(CurGD.getDecl()); + CXXCtorType CtorType = CurGD.getCtorType(); + (void) CtorType; + const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "SynthesizeCXXCopyConstructor - copy constructor has definition already"); assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy constrution of virtual base NYI - if (Base->isVirtual()) - continue; + llvm::Value *ThisPtr = LoadCXXThis(); - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } + // Find the source pointer. + unsigned SrcArgIndex = Args.size() - 1; + assert(CtorType == Ctor_Base || SrcArgIndex == 1); + assert(CtorType != Ctor_Base || + (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) || + SrcArgIndex == 1); + + llvm::Value *SrcPtr = + Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first)); for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { @@ -638,27 +474,26 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { if (const RecordType *FieldClassType = FieldType->getAs()) { CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForField(ThisPtr, Field, 0); + LValue RHS = EmitLValueForField(SrcPtr, Field, 0); if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); + const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo(); llvm::Value *DestBaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr); llvm::Value *SrcBaseAddrPtr = Builder.CreateBitCast(RHS.getAddress(), BasePtr); EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); + FieldClassDecl); } else EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); + FieldClassDecl); continue; } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0); if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); @@ -675,100 +510,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { InitializeVTablePointers(ClassDecl); } -/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. -/// Before the implicitly-declared copy assignment operator for a class is -/// implicitly defined, all implicitly- declared copy assignment operators for -/// its direct base classes and its nonstatic data members shall have been -/// implicitly defined. [12.8-p12] -/// The implicitly-defined copy assignment operator for class X performs -/// memberwise assignment of its subob- jects. The direct base classes of X are -/// assigned first, in the order of their declaration in -/// the base-specifier-list, and then the immediate nonstatic data members of X -/// are assigned, in the order in which they were declared in the class -/// definition.Each subobject is assigned in the manner appropriate to its type: -/// if the subobject is of class type, the copy assignment operator for the -/// class is used (as if by explicit qualification; that is, ignoring any -/// possible virtual overriding functions in more derived classes); -/// -/// if the subobject is an array, each element is assigned, in the manner -/// appropriate to the element type; -/// -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) { - const CXXMethodDecl *CD = cast(CurGD.getDecl()); - const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); - - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs()) { - CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); - } - else - EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); - continue; - } - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - // return *this; - Builder.CreateStore(LoadOfThis, ReturnValue); -} - static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXBaseOrMemberInitializer *BaseInit, @@ -782,15 +523,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); - // FIXME: This method of determining whether a base is virtual is ridiculous; - // it should be part of BaseInit. - bool isBaseVirtual = false; - for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); I != E; ++I) - if (I->getType()->getAs()->getDecl() == BaseClassDecl) { - isBaseVirtual = true; - break; - } + bool isBaseVirtual = BaseInit->isBaseVirtual(); // The base constructor doesn't construct virtual bases. if (CtorType == Ctor_Base && isBaseVirtual) @@ -798,9 +531,10 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, // We can pretend to be a complete class because it only matters for // virtual bases, and we only do virtual bases for complete ctors. - llvm::Value *V = ThisPtr; - V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual, - ClassDecl, BaseClassDecl); + llvm::Value *V = + CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl, + BaseClassDecl, + BaseInit->isBaseVirtual()); CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); @@ -809,7 +543,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CodeGenFunction::EHCleanupBlock Cleanup(CGF); CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Base, V); + CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V); } } @@ -850,7 +584,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LHS.isVolatileQualified()); } else { CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), - LHS.isVolatileQualified(), false, true); + LHS.isVolatileQualified(), + /*IgnoreResult*/ false, + /*IsInitializer*/ true); if (!CGF.Exceptions) return; @@ -868,7 +604,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress()); + CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } } } @@ -976,8 +713,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, llvm::SmallVector MemberInitializers; - // FIXME: Add vbase initialization - for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1028,7 +763,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // variant, then call the appropriate operator delete() on the way // out. if (DtorType == Dtor_Deleting) { - EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // If this is the complete variant, just invoke the base variant; @@ -1036,7 +772,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // this optimization if the body is a function-try-block, because // we'd introduce *two* handler blocks. } else if (!isTryBody && DtorType == Dtor_Complete) { - EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // Otherwise, we're in the base variant, so we need to ensure the @@ -1117,11 +854,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, if (BaseClassDecl->hasTrivialDestructor()) continue; const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), - true, - ClassDecl, - BaseClassDecl); - EmitCXXDestructorCall(D, Dtor_Base, V); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*BaseIsVirtual=*/true); + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V); } return; } @@ -1175,7 +912,8 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, Array, BaseAddrPtr); } else EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); + Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } // Destroy non-virtual bases. @@ -1193,12 +931,14 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - - llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(D, Dtor_Base, V); + + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl, + BaseClassDecl, + /*BaseIsVirtual=*/false); + + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V); } } @@ -1271,7 +1011,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, { CXXTemporariesCleanupScope Scope(*this); - EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address, + ArgBeg, ArgEnd); } EmitBlock(ContinueBlock); @@ -1345,7 +1086,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One); llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - EmitCXXDestructorCall(D, Dtor_Complete, Address); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address); EmitBlock(ContinueBlock); @@ -1390,6 +1131,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, FunctionDecl::Static, + FunctionDecl::None, false, true); StartFunction(FD, R, Fn, Args, SourceLocation()); QualType BaseElementTy = getContext().getBaseElementType(Array); @@ -1407,7 +1149,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, + CXXCtorType Type, bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -1429,7 +1171,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, return; } - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); @@ -1450,7 +1192,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ++I; // vtt - if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) { + if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), + /*ForVirtualBase=*/false)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); @@ -1502,8 +1245,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, + bool ForVirtualBase, llvm::Value *This) { - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), + ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); @@ -1538,7 +1283,8 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, void CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass) { const CXXRecordDecl *RD = Base.getBase(); @@ -1548,7 +1294,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, // Check if we need to use a vtable from the VTT. if (CodeGenVTables::needsVTTParameter(CurGD) && - (RD->getNumVBases() || BaseIsMorallyVirtual)) { + (RD->getNumVBases() || NearestVBase)) { // Get the secondary vpointer index. uint64_t VirtualPointerIndex = CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); @@ -1567,20 +1313,27 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, } // Compute where to store the address point. - llvm::Value *VTableField; + llvm::Value *VirtualOffset = 0; + uint64_t NonVirtualOffset = 0; - if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) { + if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. - VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD, - /*NullCheckValue=*/false); + VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass, + NearestVBase); + NonVirtualOffset = OffsetFromNearestVBase / 8; } else { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy); - VTableField = - Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8); + // We can just use the base offset in the complete class. + NonVirtualOffset = Base.getBaseOffset() / 8; } + + // Apply the offsets. + llvm::Value *VTableField = LoadCXXThis(); + + if (NonVirtualOffset || VirtualOffset) + VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField, + NonVirtualOffset, + VirtualOffset); // Finally, store the address point. const llvm::Type *AddressPointPtrTy = @@ -1591,7 +1344,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, void CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -1600,7 +1354,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, // been set. if (!BaseIsNonVirtualPrimaryBase) { // Initialize the vtable pointer for this base. - InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass); + InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase, + VTable, VTableClass); } const CXXRecordDecl *RD = Base.getBase(); @@ -1616,7 +1371,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, continue; uint64_t BaseOffset; - bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + uint64_t BaseOffsetFromNearestVBase; bool BaseDeclIsNonVirtualPrimaryBase; if (I->isVirtual()) { @@ -1628,17 +1383,20 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, getContext().getASTRecordLayout(VTableClass); BaseOffset = Layout.getVBaseClassOffset(BaseDecl); - BaseDeclIsMorallyVirtual = true; + BaseOffsetFromNearestVBase = 0; BaseDeclIsNonVirtualPrimaryBase = false; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + BaseOffsetFromNearestVBase = + OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl); BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; } InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset), - BaseDeclIsMorallyVirtual, + I->isVirtual() ? BaseDecl : NearestVBase, + BaseOffsetFromNearestVBase, BaseDeclIsNonVirtualPrimaryBase, VTable, VTableClass, VBases); } @@ -1654,8 +1412,8 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { // Initialize the vtable pointers for this class and all of its bases. VisitedVirtualBasesSetTy VBases; - InitializeVTablePointers(BaseSubobject(RD, 0), - /*BaseIsMorallyVirtual=*/false, + InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0, + /*OffsetFromNearestVBase=*/0, /*BaseIsNonVirtualPrimaryBase=*/false, VTable, RD, VBases); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index bcbda8a..4963e73 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -320,27 +320,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); - FieldOffset += FieldSize; - FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "Size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTys.clear(); @@ -360,49 +342,13 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__FuncPtr", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); - FieldOffset += FieldSize; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; FieldSize = CGM.getContext().getTypeSize(Ty); @@ -525,13 +471,20 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + unsigned Flags = 0; + AccessSpecifier Access = I->getAccess(); + if (Access == clang::AS_private) + Flags |= llvm::DIType::FlagPrivate; + else if (Access == clang::AS_protected) + Flags |= llvm::DIType::FlagProtected; + // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); + FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } } @@ -626,7 +579,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa(Method)) - VIndex = CGM.getVTables().getMethodVtableIndex(Method); + VIndex = CGM.getVTables().getMethodVTableIndex(Method); ContainingType = RecordTy; } @@ -734,8 +687,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { return VTablePtrType; } -/// getVtableName - Get vtable name for the given Class. -llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { +/// getVTableName - Get vtable name for the given Class. +llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Otherwise construct gdb compatible name name. std::string Name = "_vptr$" + RD->getNameAsString(); @@ -746,10 +699,10 @@ llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { } -/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate +/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate /// debug info entry in EltTys vector. void CGDebugInfo:: -CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, +CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -764,7 +717,7 @@ CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType VPTR = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - getVtableName(RD), Unit, + getVTableName(RD), Unit, 0, Size, 0, 0, 0, getOrCreateVTablePtrType(Unit)); EltTys.push_back(VPTR); @@ -832,7 +785,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, const CXXRecordDecl *CXXDecl = dyn_cast(RD); if (CXXDecl) { CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); - CollectVtableInfo(CXXDecl, Unit, EltTys); + CollectVTableInfo(CXXDecl, Unit, EltTys); } CollectRecordFields(RD, Unit, EltTys); llvm::MDNode *ContainingType = NULL; @@ -1293,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast(Ty), Unit); - case Type::InjectedClassName: case Type::TemplateSpecialization: case Type::Elaborated: case Type::QualifiedName: @@ -1318,6 +1270,21 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, return llvm::DIType(); } +/// CreateMemberType - Create new member and increase Offset by FType's size. +llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, + uint64_t *Offset) { + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + uint64_t FieldSize = CGM.getContext().getTypeSize(FType); + unsigned FieldAlign = CGM.getContext().getTypeAlign(FType); + llvm::DIType Ty = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, + Unit, Name, Unit, 0, + FieldSize, FieldAlign, + *Offset, 0, FieldTy); + *Offset += FieldSize; + return Ty; +} + /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, @@ -1341,17 +1308,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, } } Name = getFunctionName(FD); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. CGM.getMangledName(LinkageName, GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); LinkageName.setString(Name); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); } + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); // It is expected that CurLoc is set before using EmitFunctionStart. // Usually, CurLoc points to the left bracket location of compound @@ -1437,72 +1402,19 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__forwarding", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__copy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__destroy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", + &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", + &FieldOffset)); } CharUnits Align = CGM.getContext().getDeclAlign(VD); @@ -1517,20 +1429,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, llvm::APInt pad(32, NumPaddingBytes); FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, - Unit, "", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); } } FType = Type; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align.getQuantity()*8; @@ -1558,13 +1462,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Value *Storage, CGBuilderTy &Builder) { assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel) - return; - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); llvm::DIType Ty; uint64_t XOffset = 0; @@ -1608,11 +1505,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, const ValueDecl *VD = BDRE->getDecl(); assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) + if (Builder.GetInsertBlock() == 0) return; uint64_t XOffset = 0; @@ -1708,7 +1601,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = Var->getName(); + llvm::StringRef DeclName = D->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast(D->getDeclContext()), Unit); DebugFactory.CreateGlobalVariable(DContext, DeclName, diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8397245..c16379a 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -112,7 +112,7 @@ class CGDebugInfo { void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &E); - void CollectVtableInfo(const CXXRecordDecl *Decl, + void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &EltTys); @@ -196,13 +196,17 @@ private: /// CreateTypeNode - Create type metadata for a source language type. llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); + /// CreateMemberType - Create new member and increase Offset by FType's size. + llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, uint64_t *Offset); + /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. llvm::StringRef getFunctionName(const FunctionDecl *FD); - /// getVtableName - Get vtable name for the given Class. - llvm::StringRef getVtableName(const CXXRecordDecl *Decl); + /// getVTableName - Get vtable name for the given Class. + llvm::StringRef getVTableName(const CXXRecordDecl *Decl); }; } // namespace CodeGen diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 07d219f..ba3a2b4 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -31,11 +31,44 @@ using namespace CodeGen; void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { - default: - CGM.ErrorUnsupported(&D, "decl"); - return; + case Decl::TranslationUnit: + case Decl::Namespace: + case Decl::UnresolvedUsingTypename: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + case Decl::TemplateTypeParm: + case Decl::UnresolvedUsingValue: + case Decl::NonTypeTemplateParm: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: case Decl::ParmVar: - assert(0 && "Parmdecls should not be in declstmts!"); + case Decl::ImplicitParam: + case Decl::ClassTemplate: + case Decl::FunctionTemplate: + case Decl::TemplateTemplateParm: + case Decl::ObjCMethod: + case Decl::ObjCCategory: + case Decl::ObjCProtocol: + case Decl::ObjCInterface: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCProperty: + case Decl::ObjCCompatibleAlias: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::ObjCClass: + case Decl::ObjCForwardProtocol: + case Decl::FileScopeAsm: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::Block: + + assert(0 && "Declaration not should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; @@ -44,6 +77,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -197,6 +231,9 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) { + // Bail out early if the block is unreachable. + if (!Builder.GetInsertBlock()) return; + llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -205,6 +242,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, // Store into LocalDeclMap before generating initializer to handle // circular references. DMEntry = GV; + if (getContext().getLangOptions().CPlusPlus) + CGM.setStaticLocalDeclAddress(&D, GV); // Make sure to evaluate VLA bounds now so that we have them for later. // @@ -610,6 +649,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs()) if (CXXRecordDecl *ClassDecl = dyn_cast(RT->getDecl())) { + llvm::Value *Loc = DeclPtr; + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + if (!ClassDecl->hasTrivialDestructor()) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); @@ -622,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); // Make sure to jump to the exit block. @@ -634,20 +678,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); } } else { { DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); } if (Exceptions) { EHCleanupBlock Cleanup(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); } } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 40c18ca..f6c805f 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -219,9 +219,14 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, SourceLocation()); // Emit the dtors, in reverse order from construction. - for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) - Builder.CreateCall(DtorsAndObjects[e - i - 1].first, - DtorsAndObjects[e - i - 1].second); + for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) { + llvm::Constant *Callee = DtorsAndObjects[e - i - 1].first; + llvm::CallInst *CI = Builder.CreateCall(Callee, + DtorsAndObjects[e - i - 1].second); + // Make sure the call and the callee agree on calling convention. + if (llvm::Function *F = dyn_cast(Callee)) + CI->setCallingConv(F->getCallingConv()); + } FinishFunction(); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 1e15066..c1d05bf 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); } -// CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// DestPtr is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, - llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { - QualType ObjectType = E->getType(); - - // Store the throw exception in the exception object. - if (!CGF.hasAggregateLLVMType(ObjectType)) { - llvm::Value *Value = CGF.EmitScalarExpr(E); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); - - CGF.Builder.CreateStore(Value, - CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); - } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); - const CXXRecordDecl *RD = - cast(ObjectType->getAs()->getDecl()); - - llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); - if (RD->hasTrivialCopyConstructor()) { - CGF.EmitAggExpr(E, This, false); - } else if (CXXConstructorDecl *CopyCtor - = RD->getCopyConstructor(CGF.getContext(), 0)) { - llvm::Value *CondPtr = 0; - if (CGF.Exceptions) { - CodeGenFunction::EHCleanupBlock Cleanup(CGF); - llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); - - llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free"); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), - "doEHfree"); - - CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr), - CondBlock, Cont); - CGF.EmitBlock(CondBlock); - - // Load the exception pointer. - llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); - CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); - - CGF.EmitBlock(Cont); - } - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), - CondPtr); - - llvm::Value *Src = CGF.EmitLValue(E).getAddress(); - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), - CondPtr); - - llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); - CGF.setInvokeDest(TerminateHandler); - - // Stolen from EmitClassAggrMemberwiseCopy - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, - Ctor_Complete); - CallArgList CallArgs; - CallArgs.push_back(std::make_pair(RValue::get(This), - CopyCtor->getThisType(CGF.getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - CopyCtor->getParamDecl(0)->getType())); - const FunctionProtoType *FPT - = CopyCtor->getType()->getAs(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, CopyCtor); - CGF.setInvokeDest(PrevLandingPad); - } else - llvm_unreachable("uncopyable object"); +// Emits an exception expression into the given location. This +// differs from EmitAnyExprToMem only in that, if a final copy-ctor +// call is required, an exception within that copy ctor causes +// std::terminate to be invoked. +static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, + llvm::Value *ExnLoc) { + // We want to release the allocated exception object if this + // expression throws. We do this by pushing an EH-only cleanup + // block which, furthermore, deactivates itself after the expression + // is complete. + llvm::AllocaInst *ShouldFreeVar = + CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), + "should-free-exnobj.var"); + CGF.InitTempAlloca(ShouldFreeVar, + llvm::ConstantInt::getFalse(CGF.getLLVMContext())); + + // A variable holding the exception pointer. This is necessary + // because the throw expression does not necessarily dominate the + // cleanup, for example if it appears in a conditional expression. + llvm::AllocaInst *ExnLocVar = + CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var"); + + llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest(); + { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj"); + llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done"); + + llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar, + "should-free-exnobj"); + CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB); + CGF.EmitBlock(FreeBB); + llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj"); + CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal); + CGF.EmitBlock(DoneBB); } + llvm::BasicBlock *Cleanup = CGF.getInvokeDest(); + + CGF.Builder.CreateStore(ExnLoc, ExnLocVar); + CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), + ShouldFreeVar); + + // __cxa_allocate_exception returns a void*; we need to cast this + // to the appropriate type for the object. + const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo(); + llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty); + + // FIXME: this isn't quite right! If there's a final unelided call + // to a copy constructor, then according to [except.terminate]p1 we + // must call std::terminate() if that constructor throws, because + // technically that copy occurs after the exception expression is + // evaluated but before the exception is caught. But the best way + // to handle that is to teach EmitAggExpr to do the final copy + // differently if it can't be elided. + CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false); + + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), + ShouldFreeVar); + + // Pop the cleanup block if it's still the top of the cleanup stack. + // Otherwise, temporaries have been created and our cleanup will get + // properly removed in time. + // TODO: this is not very resilient. + if (CGF.getInvokeDest() == Cleanup) + CGF.setInvokeDest(SavedInvokeDest); } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. @@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; + uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); llvm::Value *ExceptionPtr = @@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - llvm::Value *ExceptionPtrPtr = - CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); - Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); - - - CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType); - llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true); + + // The address of the destructor. If the exception type has a + // trivial destructor (or isn't a record), we just pass null. + llvm::Constant *Dtor = 0; + if (const RecordType *RecordTy = ThrowType->getAs()) { + CXXRecordDecl *Record = cast(RecordTy->getDecl()); + if (!Record->hasTrivialDestructor()) { + CXXDestructorDecl *DtorD = Record->getDestructor(getContext()); + Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete); + Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy); + } + } + if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy); if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); @@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { QualType Ty = Proto->getExceptionType(i); QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true); SelectorArgs.push_back(EHType); } if (Proto->getNumExceptions()) @@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, // are ignored. QualType CaughtType = C->getCaughtType().getNonReferenceType(); llvm::Value *EHTypeInfo - = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); + = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true); SelectorArgs.push_back(EHTypeInfo); } else { // null indicates catch all @@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, } CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { - llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); - CGF.EmitBranch(Cont1); CGF.setInvokeDest(PreviousInvokeDest); + llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock(); - CGF.EmitBlock(CleanupHandler); - + // Jump to the beginning of the cleanup. + CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin()); + + // The libstdc++ personality function. + // TODO: generalize to work with other libraries. llvm::Constant *Personality = CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (CGF.VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + + // %exception = call i8* @llvm.eh.exception() + // Magic intrinsic which tells gives us a handle to the caught + // exception. llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); - llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); - const llvm::IntegerType *Int8Ty; - const llvm::PointerType *PtrToInt8Ty; - Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); - // C string type. Used in lots of places. - PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); - llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + + llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty); + + // %ignored = call i32 @llvm.eh.selector(i8* %exception, + // i8* @__gxx_personality_v0, + // i8* null) + // Magic intrinsic which tells LLVM that this invoke landing pad is + // just a cleanup block. llvm::Value *Args[] = { Exc, Personality, Null }; + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); - CGF.EmitBlock(CleanupEntryBB); - - CGF.EmitBlock(Cont1); + // And then we fall through into the code that the user put there. + // Jump back to the end of the cleanup. + CGF.Builder.SetInsertPoint(EndOfCleanup); + // Rethrow the exception. if (CGF.getInvokeDest()) { llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, @@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { CGF.EmitBlock(Cont); } else CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); - CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(Cont); + // Resume inserting where we started, but put the new cleanup + // handler in place. + if (PreviousInsertionBlock) + CGF.Builder.SetInsertPoint(PreviousInsertionBlock); + else + CGF.Builder.ClearInsertionPoint(); + if (CGF.Exceptions) CGF.setInvokeDest(CleanupHandler); } @@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { if (TerminateHandler) return TerminateHandler; - llvm::BasicBlock *Cont = 0; - - if (HaveInsertPoint()) { - Cont = createBasicBlock("cont"); - EmitBranch(Cont); - } + // We don't want to change anything at the current location, so + // save it aside and clear the insert point. + llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock(); + llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint(); + Builder.ClearInsertionPoint(); llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { TerminateCall->setDoesNotThrow(); Builder.CreateUnreachable(); - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); - - if (Cont) - EmitBlock(Cont); + // Restore the saved insertion state. + Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint); return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 0aa4438..9ade916 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -37,6 +37,13 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } +void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var, + llvm::Value *Init) { + llvm::StoreInst *Store = new llvm::StoreInst(Init, Var); + llvm::BasicBlock *Block = AllocaInsertPt->getParent(); + Block->getInstList().insertAfter(&*AllocaInsertPt, Store); +} + llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty, const llvm::Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name); @@ -111,6 +118,23 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, IsInitializer); } +/// EmitAnyExprToMem - Evaluate an expression into a given memory +/// location. +void CodeGenFunction::EmitAnyExprToMem(const Expr *E, + llvm::Value *Location, + bool IsLocationVolatile, + bool IsInit) { + if (E->getType()->isComplexType()) + EmitComplexExprIntoAddr(E, Location, IsLocationVolatile); + else if (hasAggregateLLVMType(E->getType())) + EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit); + else { + RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); + LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType())); + EmitStoreThroughLValue(RV, LV, E->getType()); + } +} + RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer) { bool ShouldDestroyTemporaries = false; @@ -150,16 +174,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, PopCXXTemporary(); } } else { - const CXXRecordDecl *BaseClassDecl = 0; + const CXXBaseSpecifierArray *BasePath = 0; const CXXRecordDecl *DerivedClassDecl = 0; if (const CastExpr *CE = dyn_cast(E->IgnoreParenNoopCasts(getContext()))) { if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { E = CE->getSubExpr(); - - BaseClassDecl = - cast(CE->getType()->getAs()->getDecl()); + + BasePath = &CE->getBasePath(); DerivedClassDecl = cast(E->getType()->getAs()->getDecl()); } @@ -185,6 +208,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, { DelayedCleanupBlock Scope(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); // Make sure to jump to the exit block. @@ -193,6 +217,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (Exceptions) { EHCleanupBlock Cleanup(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); } } @@ -201,10 +226,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } // Check if need to perform the derived-to-base cast. - if (BaseClassDecl) { + if (BasePath) { llvm::Value *Derived = Val.getAggregateAddr(); llvm::Value *Base = - GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, + GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath, /*NullCheckValue=*/false); return RValue::get(Base); } @@ -240,18 +265,15 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { if (!CatchUndefined) return; - const llvm::IntegerType *Size_tTy + const llvm::Type *Size_tTy = llvm::IntegerType::get(VMContext, LLVMPointerWidth); Address = Builder.CreateBitCast(Address, PtrToInt8Ty); - const llvm::Type *ResType[] = { - Size_tTy - }; - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1); - const llvm::IntegerType *IntTy = cast( - CGM.getTypes().ConvertType(CGM.getContext().IntTy)); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &Size_tTy, 1); + const llvm::IntegerType *Int1Ty = llvm::IntegerType::get(VMContext, 1); + // In time, people may want to control this and use a 1 here. - llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0); + llvm::Value *Arg = llvm::ConstantInt::get(Int1Ty, 0); llvm::Value *C = Builder.CreateCall2(F, Address, Arg); llvm::BasicBlock *Cont = createBasicBlock(); llvm::BasicBlock *Check = createBasicBlock(); @@ -457,6 +479,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitObjCIsaExpr(cast(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast(E)); + case Expr::CompoundAssignOperatorClass: + return EmitCompoundAssignOperatorLValue(cast(E)); case Expr::CallExprClass: case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: @@ -606,63 +630,73 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = LV.getBitFieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertType(ExprType); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // In some cases the bitfield may straddle two memory locations. Currently we - // load the entire bitfield, then do the magic to sign-extend it if - // necessary. This results in somewhat more code than necessary for the common - // case (one load), since two shifts accomplish both the masking and sign - // extension. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp"); + // Compute the result as an OR of all of the individual component accesses. + llvm::Value *Res = 0; + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Shift to proper location. - if (StartBit) - Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); + // Get the field pointer. + llvm::Value *Ptr = LV.getBitFieldBaseAddr(); - // Mask off unused bits. - llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, LowBits)); - Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared"); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // Fetch the high bits if necessary. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - LV.isVolatileQualified(), - "tmp"); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Mask off unused bits. - llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, HighBits)); - HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + ExprType.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); - // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, LowBits); - Val = Builder.CreateOr(Val, HighVal, "bf.val"); - } + // Perform the load. + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); - // Sign extend if necessary. - if (Info.IsSigned) { - llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy, - EltTySize - BitfieldSize); - Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits), - ExtraBits, "bf.val.sext"); + // Shift out unused low bits and mask out unused high bits. + llvm::Value *Val = Load; + if (AI.FieldBitStart) + Val = Builder.CreateLShr(Load, AI.FieldBitStart); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth, + AI.TargetBitWidth), + "bf.clear"); + + // Extend or truncate to the target size. + if (AI.AccessWidth < ResSizeInBits) + Val = Builder.CreateZExt(Val, ResLTy); + else if (AI.AccessWidth > ResSizeInBits) + Val = Builder.CreateTrunc(Val, ResLTy); + + // Shift into place, and OR into the result. + if (AI.TargetBitOffset) + Val = Builder.CreateShl(Val, AI.TargetBitOffset); + Res = Res ? Builder.CreateOr(Res, Val) : Val; } - // The bitfield type and the normal type differ when the storage sizes differ - // (currently just _Bool). - Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp"); + // If the bit-field is signed, perform the sign-extension. + // + // FIXME: This can easily be folded into the load of the high bits, which + // could also eliminate the mask of high bits in some situations. + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits), + ExtraBits, "bf.val.sext"); + } - return RValue::get(Val); + return RValue::get(Res); } RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, @@ -783,88 +817,103 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty, llvm::Value **Result) { const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = Dst.getBitFieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertTypeForMem(Ty); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // Get the new value, cast to the appropriate type and masked to exactly the - // size of the bit-field. + // Get the source value, truncated to the width of the bit-field. llvm::Value *SrcVal = Src.getScalarVal(); - llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp"); - llvm::Constant *Mask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize)); - NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value"); + + if (Ty->isBooleanType()) + SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false); + + SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits, + Info.getSize()), + "bf.value"); // Return the new value of the bit-field, if requested. if (Result) { // Cast back to the proper type for result. - const llvm::Type *SrcTy = SrcVal->getType(); - llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false, - "bf.reload.val"); + const llvm::Type *SrcTy = Src.getScalarVal()->getType(); + llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false, + "bf.reload.val"); // Sign extend if necessary. - if (Info.IsSigned) { - unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy); - llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy, - SrcTySize - BitfieldSize); - SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), - ExtraBits, "bf.reload.sext"); + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits), + ExtraBits, "bf.reload.sext"); } - *Result = SrcTrunc; + *Result = ReloadVal; } - // In some cases the bitfield may straddle two memory locations. Emit the low - // part first and check to see if the high needs to be done. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), - "bf.prev.low"); - - // Compute the mask for zero-ing the low part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, - ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits)); + // Iterate over the components, writing each piece to memory. + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Compute the new low part as - // LowVal = (LowVal & InvMask) | (NewVal << StartBit), - // with the shift of NewVal implicitly stripping the high bits. - llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); - LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); - LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); + // Get the field pointer. + llvm::Value *Ptr = Dst.getBitFieldBaseAddr(); - // Write back. - Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified()); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // If the low part doesn't cover the bitfield emit a high part. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - Dst.isVolatileQualified(), - "bf.prev.hi"); - - // Compute the mask for zero-ing the high part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize, - HighBits)); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Compute the new high part as - // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits), - // where the high bits of NewVal have already been cleared and the - // shift stripping the low bits. - llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); - HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); - HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + Ty.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); + + // Extract the piece of the bit-field value to write in this access, limited + // to the values that are part of this access. + llvm::Value *Val = SrcVal; + if (AI.TargetBitOffset) + Val = Builder.CreateLShr(Val, AI.TargetBitOffset); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits, + AI.TargetBitWidth)); + + // Extend or truncate to the access size. + const llvm::Type *AccessLTy = + llvm::Type::getIntNTy(VMContext, AI.AccessWidth); + if (ResSizeInBits < AI.AccessWidth) + Val = Builder.CreateZExt(Val, AccessLTy); + else if (ResSizeInBits > AI.AccessWidth) + Val = Builder.CreateTrunc(Val, AccessLTy); + + // Shift into the position in memory. + if (AI.FieldBitStart) + Val = Builder.CreateShl(Val, AI.FieldBitStart); + + // If necessary, load and OR in bits that are outside of the bit-field. + if (AI.TargetBitWidth != AI.AccessWidth) { + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); + + // Compute the mask for zeroing the bits that are part of the bit-field. + llvm::APInt InvMask = + ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart, + AI.FieldBitStart + AI.TargetBitWidth); + + // Apply the mask and OR in to the value to write. + Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val); + } - // Write back. - Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified()); + // Write the value. + llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr, + Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Store->setAlignment(AI.AccessAlignment); } } @@ -1084,6 +1133,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr(); llvm::Value *V = LocalDeclMap[VD]; + if (!V && getContext().getLangOptions().CPlusPlus && + VD->isStaticLocal()) + V = CGM.getStaticLocalDeclAddress(VD); assert(V && "DeclRefExpr not entered in LocalDeclMap?"); Qualifiers Quals = MakeQualifiers(E->getType()); @@ -1474,19 +1526,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(Field->getParent()); const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - // FIXME: CodeGenTypes should expose a method to get the appropriate type for - // FieldTy (the appropriate type is ABI-dependent). - const llvm::Type *FieldTy = - CGM.getTypes().ConvertTypeForMem(Field->getType()); - const llvm::PointerType *BaseTy = - cast(BaseValue->getType()); - unsigned AS = BaseTy->getAddressSpace(); - BaseValue = Builder.CreateBitCast(BaseValue, - llvm::PointerType::get(FieldTy, AS)); - llvm::Value *V = Builder.CreateConstGEP1_32(BaseValue, Info.FieldNo); - - return LValue::MakeBitfield(V, Info, + return LValue::MakeBitfield(BaseValue, Info, Field->getType().getCVRQualifiers()|CVRQualifiers); } @@ -1548,12 +1588,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); - if (E->getType()->isComplexType()) - EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); - else if (hasAggregateLLVMType(E->getType())) - EmitAnyExpr(InitExpr, DeclPtr, false); - else - EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType()); + EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false); return Result; } @@ -1647,27 +1682,19 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { E->getSubExpr()->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); - - const RecordType *BaseClassTy = E->getType()->getAs(); - CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); LValue LV = EmitLValue(E->getSubExpr()); // Perform the derived-to-base conversion llvm::Value *Base = GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl, - BaseClassDecl, /*NullCheckValue=*/false); + E->getBasePath(), /*NullCheckValue=*/false); return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } case CastExpr::CK_ToUnion: return EmitAggExprToLValue(E); case CastExpr::CK_BaseToDerived: { - const RecordType *BaseClassTy = - E->getSubExpr()->getType()->getAs(); - CXXRecordDecl *BaseClassDecl = - cast(BaseClassTy->getDecl()); - const RecordType *DerivedClassTy = E->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); @@ -1676,8 +1703,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the base-to-derived conversion llvm::Value *Derived = - GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl, - DerivedClassDecl, /*NullCheckValue=*/false); + GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, + E->getBasePath(),/*NullCheckValue=*/false); return LValue::MakeAddr(Derived, MakeQualifiers(E->getType())); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 4d5160f..d1b0dff 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -263,7 +263,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) { if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); else @@ -321,6 +321,11 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { (void) MPT; assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); + + // The creation of member function pointers has no side effects; if + // there is no destination pointer, we have nothing to do. + if (!DestPtr) + return; const DeclRefExpr *DRE = cast(E->getSubExpr()); const CXXMethodDecl *MD = @@ -329,17 +334,23 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { const llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); llvm::Value *FuncPtr; if (MD->isVirtual()) { - int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD); + int64_t Index = CGF.CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGF.CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + FuncPtr = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty = @@ -738,6 +749,14 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs()) { + if (cast(RT->getDecl())->isEmpty()) + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 1fd1da8..b57cdc9 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -205,20 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); EmitBlock(FnVirtual); - const llvm::Type *VtableTy = + const llvm::Type *VTableTy = FTy->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo()); - Vtable = Builder.CreateLoad(Vtable); + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); + VTable = Builder.CreateLoad(VTable); - Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy); - llvm::Value *VtableOffset = + VTable = Builder.CreateBitCast(VTable, Int8PtrTy); + llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn"); - Vtable = Builder.CreateBitCast(Vtable, VtableTy); + VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); + VTable = Builder.CreateBitCast(VTable, VTableTy); - llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn"); + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); EmitBranch(FnEnd); EmitBlock(FnNonVirtual); @@ -316,17 +316,22 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(Dest, BasePtr); + Builder.CreateBitCast(Dest, BasePtr); EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, E->arg_begin(), E->arg_end()); } - else + else { + CXXCtorType Type = + (E->getConstructionKind() == CXXConstructExpr::CK_Complete) + ? Ctor_Complete : Ctor_Base; + bool ForVirtualBase = + E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; + // Call the constructor. - EmitCXXConstructorCall(CD, - E->isBaseInitialization()? Ctor_Base : Ctor_Complete, - Dest, + EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest, E->arg_begin(), E->arg_end()); + } } static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { @@ -460,18 +465,20 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *NewPtr, llvm::Value *NumElements) { if (E->isArray()) { - if (CXXConstructorDecl *Ctor = E->getConstructor()) - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - return; + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + if (!Ctor->getParent()->hasTrivialConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + return; + } } QualType AllocType = E->getAllocatedType(); if (CXXConstructorDecl *Ctor = E->getConstructor()) { - CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, + NewPtr, E->constructor_arg_begin(), E->constructor_arg_end()); return; @@ -760,7 +767,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { // The dtor took care of deleting the object. ShouldCallDelete = false; } else - EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + Ptr); } } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 172a77d..2595ff0 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -27,359 +27,387 @@ using namespace clang; using namespace CodeGen; -namespace { +//===----------------------------------------------------------------------===// +// ConstStructBuilder +//===----------------------------------------------------------------------===// + +namespace { class ConstStructBuilder { CodeGenModule &CGM; CodeGenFunction *CGF; bool Packed; - unsigned NextFieldOffsetInBytes; - unsigned LLVMStructAlignment; - std::vector Elements; - +public: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *ILE); + +private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), LLVMStructAlignment(1) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - uint64_t FieldOffsetInBytes = FieldOffset / 8; + llvm::Constant *InitExpr); - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes - && "Field offset mismatch!"); + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitExpr); - // Emit the field. - llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); - if (!C) - return false; + void AppendPadding(uint64_t NumBytes); - unsigned FieldAlignment = getAlignment(C); + void AppendTailPadding(uint64_t RecordSize); - // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + void ConvertStructToPacked(); + + bool Build(InitListExpr *ILE); - if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { - assert(!Packed && "Alignment is wrong even with a packed struct!"); + unsigned getAlignment(const llvm::Constant *C) const { + if (Packed) return 1; + return CGM.getTargetData().getABITypeAlignment(C->getType()); + } - // Convert the struct to a packed struct. - ConvertStructToPacked(); - - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + uint64_t getSizeInBytes(const llvm::Constant *C) const { + return CGM.getTargetData().getTypeAllocSize(C->getType()); + } +}; - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { - // We need to append padding. - AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); +bool ConstStructBuilder:: +AppendField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + uint64_t FieldOffsetInBytes = FieldOffset / 8; - assert(NextFieldOffsetInBytes == FieldOffsetInBytes && - "Did not add enough padding!"); + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + && "Field offset mismatch!"); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + // Emit the field. + if (!InitCst) + return false; - // Add the field. - Elements.push_back(C); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); - - if (Packed) - assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); - else - LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); + unsigned FieldAlignment = getAlignment(InitCst); - return true; - } + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); - bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - llvm::ConstantInt *CI = - cast_or_null(CGM.EmitConstantExpr(InitExpr, - Field->getType(), - CGF)); - // FIXME: Can this ever happen? - if (!CI) - return false; - - if (FieldOffset > NextFieldOffsetInBytes * 8) { - // We need to add padding. - uint64_t NumBytes = - llvm::RoundUpToAlignment(FieldOffset - - NextFieldOffsetInBytes * 8, 8) / 8; + if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + assert(!Packed && "Alignment is wrong even with a packed struct!"); - AppendPadding(NumBytes); - } + // Convert the struct to a packed struct. + ConvertStructToPacked(); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // We need to append padding. + AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); - llvm::APInt FieldValue = CI->getValue(); + assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + "Did not add enough padding!"); - // Promote the size of FieldValue if necessary - // FIXME: This should never occur, but currently it can because initializer - // constants are cast to bool, and because clang is not enforcing bitfield - // width limits. - if (FieldSize > FieldValue.getBitWidth()) - FieldValue.zext(FieldSize); + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - // Truncate the size of FieldValue to the bit field size. - if (FieldSize < FieldValue.getBitWidth()) - FieldValue.trunc(FieldSize); + // Add the field. + Elements.push_back(InitCst); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + + getSizeInBytes(InitCst); + + if (Packed) + assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + else + LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); - if (FieldOffset < NextFieldOffsetInBytes * 8) { - // Either part of the field or the entire field can go into the previous - // byte. - assert(!Elements.empty() && "Elements can't be empty!"); + return true; +} - unsigned BitsInPreviousByte = - NextFieldOffsetInBytes * 8 - FieldOffset; +bool ConstStructBuilder:: + AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + llvm::ConstantInt *CI = cast_or_null(InitCst); + // FIXME: Can this ever happen? + if (!CI) + return false; - bool FitsCompletelyInPreviousByte = - BitsInPreviousByte >= FieldValue.getBitWidth(); + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // We need to add padding. + uint64_t NumBytes = + llvm::RoundUpToAlignment(FieldOffset - + NextFieldOffsetInBytes * 8, 8) / 8; - llvm::APInt Tmp = FieldValue; + AppendPadding(NumBytes); + } - if (!FitsCompletelyInPreviousByte) { - unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); - if (CGM.getTargetData().isBigEndian()) { - Tmp = Tmp.lshr(NewFieldWidth); - Tmp.trunc(BitsInPreviousByte); + llvm::APInt FieldValue = CI->getValue(); - // We want the remaining high bits. - FieldValue.trunc(NewFieldWidth); - } else { - Tmp.trunc(BitsInPreviousByte); + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); - // We want the remaining low bits. - FieldValue = FieldValue.lshr(BitsInPreviousByte); - FieldValue.trunc(NewFieldWidth); - } - } + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); - Tmp.zext(8); - if (CGM.getTargetData().isBigEndian()) { - if (FitsCompletelyInPreviousByte) - Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); - } else { - Tmp = Tmp.shl(8 - BitsInPreviousByte); - } + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // Either part of the field or the entire field can go into the previous + // byte. + assert(!Elements.empty() && "Elements can't be empty!"); - // Or in the bits that go into the previous byte. - if (llvm::ConstantInt *Val = dyn_cast(Elements.back())) - Tmp |= Val->getValue(); - else - assert(isa(Elements.back())); + unsigned BitsInPreviousByte = + NextFieldOffsetInBytes * 8 - FieldOffset; - Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); + bool FitsCompletelyInPreviousByte = + BitsInPreviousByte >= FieldValue.getBitWidth(); - if (FitsCompletelyInPreviousByte) - return true; - } + llvm::APInt Tmp = FieldValue; - while (FieldValue.getBitWidth() > 8) { - llvm::APInt Tmp; + if (!FitsCompletelyInPreviousByte) { + unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; if (CGM.getTargetData().isBigEndian()) { - // We want the high bits. - Tmp = FieldValue; - Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); - Tmp.trunc(8); + Tmp = Tmp.lshr(NewFieldWidth); + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining high bits. + FieldValue.trunc(NewFieldWidth); } else { - // We want the low bits. - Tmp = FieldValue; - Tmp.trunc(8); + Tmp.trunc(BitsInPreviousByte); - FieldValue = FieldValue.lshr(8); + // We want the remaining low bits. + FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.trunc(NewFieldWidth); } - - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); - NextFieldOffsetInBytes++; - - FieldValue.trunc(FieldValue.getBitWidth() - 8); } - assert(FieldValue.getBitWidth() > 0 && - "Should have at least one bit left!"); - assert(FieldValue.getBitWidth() <= 8 && - "Should not have more than a byte left!"); + Tmp.zext(8); + if (CGM.getTargetData().isBigEndian()) { + if (FitsCompletelyInPreviousByte) + Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); + } else { + Tmp = Tmp.shl(8 - BitsInPreviousByte); + } - if (FieldValue.getBitWidth() < 8) { - if (CGM.getTargetData().isBigEndian()) { - unsigned BitWidth = FieldValue.getBitWidth(); + // Or in the bits that go into the previous byte. + if (llvm::ConstantInt *Val = dyn_cast(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa(Elements.back())); - FieldValue.zext(8); - FieldValue = FieldValue << (8 - BitWidth); - } else - FieldValue.zext(8); - } + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); - // Append the last element. - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), - FieldValue)); - NextFieldOffsetInBytes++; - return true; + if (FitsCompletelyInPreviousByte) + return true; } - void AppendPadding(uint64_t NumBytes) { - if (!NumBytes) - return; + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; + + if (CGM.getTargetData().isBigEndian()) { + // We want the high bits. + Tmp = FieldValue; + Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); + Tmp.trunc(8); + } else { + // We want the low bits. + Tmp = FieldValue; + Tmp.trunc(8); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + FieldValue = FieldValue.lshr(8); + } - llvm::Constant *C = llvm::UndefValue::get(Ty); - Elements.push_back(C); - assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; - NextFieldOffsetInBytes += getSizeInBytes(C); + FieldValue.trunc(FieldValue.getBitWidth() - 8); } - void AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; - AppendPadding(NumPadBytes); + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); } - void ConvertStructToPacked() { - std::vector PackedElements; - uint64_t ElementOffsetInBytes = 0; + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; +} - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - llvm::Constant *C = Elements[i]; +void ConstStructBuilder::AppendPadding(uint64_t NumBytes) { + if (!NumBytes) + return; - unsigned ElementAlign = - CGM.getTargetData().getABITypeAlignment(C->getType()); - uint64_t AlignedElementOffsetInBytes = - llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { - // We need some padding. - uint64_t NumBytes = - AlignedElementOffsetInBytes - ElementOffsetInBytes; + llvm::Constant *C = llvm::UndefValue::get(Ty); + Elements.push_back(C); + assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + NextFieldOffsetInBytes += getSizeInBytes(C); +} - llvm::Constant *Padding = llvm::UndefValue::get(Ty); - PackedElements.push_back(Padding); - ElementOffsetInBytes += getSizeInBytes(Padding); - } +void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); - PackedElements.push_back(C); - ElementOffsetInBytes += getSizeInBytes(C); - } + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - assert(ElementOffsetInBytes == NextFieldOffsetInBytes && - "Packing the struct changed its size!"); + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendPadding(NumPadBytes); +} - Elements = PackedElements; - LLVMStructAlignment = 1; - Packed = true; - } - - bool Build(InitListExpr *ILE) { - RecordDecl *RD = ILE->getType()->getAs()->getDecl(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - - unsigned FieldNo = 0; - unsigned ElementNo = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - ElementNo < ILE->getNumInits() && Field != FieldEnd; - ++Field, ++FieldNo) { - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) - continue; - - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; - - if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } else { - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } +void ConstStructBuilder::ConvertStructToPacked() { + std::vector PackedElements; + uint64_t ElementOffsetInBytes = 0; - ElementNo++; - } + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + llvm::Constant *C = Elements[i]; - uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + unsigned ElementAlign = + CGM.getTargetData().getABITypeAlignment(C->getType()); + uint64_t AlignedElementOffsetInBytes = + llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); - if (NextFieldOffsetInBytes > LayoutSizeInBytes) { - // If the struct is bigger than the size of the record type, - // we must have a flexible array member at the end. - assert(RD->hasFlexibleArrayMember() && - "Must have flexible array member if struct is bigger than type!"); - - // No tail padding is necessary. - return true; - } + if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + // We need some padding. + uint64_t NumBytes = + AlignedElementOffsetInBytes - ElementOffsetInBytes; - uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, - LLVMStructAlignment); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInBytes <= LayoutSizeInBytes && - LLVMSizeInBytes > LayoutSizeInBytes) { - assert(!Packed && "Size mismatch!"); - - ConvertStructToPacked(); - assert(NextFieldOffsetInBytes == LayoutSizeInBytes && - "Converting to packed did not help!"); + llvm::Constant *Padding = llvm::UndefValue::get(Ty); + PackedElements.push_back(Padding); + ElementOffsetInBytes += getSizeInBytes(Padding); } - // Append tail padding if necessary. - AppendTailPadding(Layout.getSize()); - - assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && - "Tail padding mismatch!"); - - return true; + PackedElements.push_back(C); + ElementOffsetInBytes += getSizeInBytes(C); } - unsigned getAlignment(const llvm::Constant *C) const { - if (Packed) - return 1; + assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + "Packing the struct changed its size!"); - return CGM.getTargetData().getABITypeAlignment(C->getType()); + Elements = PackedElements; + LLVMStructAlignment = 1; + Packed = true; +} + +bool ConstStructBuilder::Build(InitListExpr *ILE) { + RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + unsigned FieldNo = 0; + unsigned ElementNo = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isBitField() && !Field->getIdentifier()) + continue; + + // Get the initializer. A struct can include fields without initializers, + // we just use explicit null values for them. + llvm::Constant *EltInit; + if (ElementNo < ILE->getNumInits()) + EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++), + Field->getType(), CGF); + else + EltInit = CGM.EmitNullConstant(Field->getType()); + + if (!Field->isBitField()) { + // Handle non-bitfield members. + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } else { + // Otherwise we have a bitfield. + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } } - uint64_t getSizeInBytes(const llvm::Constant *C) const { - return CGM.getTargetData().getTypeAllocSize(C->getType()); + uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + + if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + // If the struct is bigger than the size of the record type, + // we must have a flexible array member at the end. + assert(RD->hasFlexibleArrayMember() && + "Must have flexible array member if struct is bigger than type!"); + + // No tail padding is necessary. + return true; } -public: - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, - InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); + uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, + LLVMStructAlignment); - if (!Builder.Build(ILE)) - return 0; + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInBytes <= LayoutSizeInBytes && + LLVMSizeInBytes > LayoutSizeInBytes) { + assert(!Packed && "Size mismatch!"); + + ConvertStructToPacked(); + assert(NextFieldOffsetInBytes <= LayoutSizeInBytes && + "Converting to packed did not help!"); + } - llvm::Constant *Result = - llvm::ConstantStruct::get(CGM.getLLVMContext(), - Builder.Elements, Builder.Packed); + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); - assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, - Builder.getAlignment(Result)) == - Builder.getSizeInBytes(Result) && "Size mismatch!"); + assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && + "Tail padding mismatch!"); - return Result; - } -}; + return true; +} + +llvm::Constant *ConstStructBuilder:: + BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + llvm::Constant *Result = + llvm::ConstantStruct::get(CGM.getLLVMContext(), + Builder.Elements, Builder.Packed); + + assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, + Builder.getAlignment(Result)) == + Builder.getSizeInBytes(Result) && "Size mismatch!"); + + return Result; +} + +//===----------------------------------------------------------------------===// +// ConstExprEmitter +//===----------------------------------------------------------------------===// + class ConstExprEmitter : public StmtVisitor { CodeGenModule &CGM; @@ -418,13 +446,18 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + Values[0] = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty = @@ -528,8 +561,6 @@ public: const MemberPointerType *DestTy = E->getType()->getAs(); - const CXXRecordDecl *BaseClass = - cast(cast(SrcTy->getClass())->getDecl()); const CXXRecordDecl *DerivedClass = cast(cast(DestTy->getClass())->getDecl()); @@ -543,7 +574,7 @@ public: // Check if we need to update the adjustment. if (llvm::Constant *Offset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) { + CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) { llvm::Constant *Values[2]; Values[0] = CS->getOperand(0); @@ -587,17 +618,15 @@ public: } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { - std::vector Elts; - const llvm::ArrayType *AType = - cast(ConvertType(ILE->getType())); unsigned NumInitElements = ILE->getNumInits(); - // FIXME: Check for wide strings - // FIXME: Check for NumInitElements exactly equal to 1?? - if (NumInitElements > 0 && + if (NumInitElements == 1 && (isa(ILE->getInit(0)) || - isa(ILE->getInit(0))) && - ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) + isa(ILE->getInit(0)))) return Visit(ILE->getInit(0)); + + std::vector Elts; + const llvm::ArrayType *AType = + cast(ConvertType(ILE->getType())); const llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d1c0f8d..9849688 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -133,6 +133,7 @@ public: CGF.getContext().typesAreCompatible( E->getArgType1(), E->getArgType2())); } + Value *VisitOffsetOfExpr(const OffsetOfExpr *E); Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); @@ -242,7 +243,7 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); - + // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); @@ -314,6 +315,10 @@ public: } BinOpInfo EmitBinOps(const BinaryOperator *E); + LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*F)(const BinOpInfo &), + Value *&BitFieldResult); + Value *EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); @@ -818,16 +823,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Visit(const_cast(E)); case CastExpr::CK_BaseToDerived: { - const CXXRecordDecl *BaseClassDecl = - E->getType()->getCXXRecordDeclForPointerType(); const CXXRecordDecl *DerivedClassDecl = DestTy->getCXXRecordDeclForPointerType(); - Value *Src = Visit(const_cast(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl, - NullCheckValue); + return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_UncheckedDerivedToBase: case CastExpr::CK_DerivedToBase: { @@ -836,15 +837,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); - const RecordType *BaseClassTy = - DestTy->getAs()->getPointeeType()->getAs(); - CXXRecordDecl *BaseClassDecl = cast(BaseClassTy->getDecl()); - - Value *Src = Visit(const_cast(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, - NullCheckValue); + return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_Dynamic: { Value *V = Visit(const_cast(E)); @@ -894,7 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + CE->getBasePath())) { if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) Src = Builder.CreateSub(Src, Adj, "adj"); else @@ -1035,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } +Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) { + Expr::EvalResult Result; + if(E->Evaluate(Result, CGF.getContext())) + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + + // FIXME: Cannot support code generation for non-constant offsetof. + unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error, + "cannot compile non-constant __builtin_offsetof"); + CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()), + DiagID) + << E->getSourceRange(); + + return llvm::Constant::getNullValue(ConvertType(E->getType())); +} + /// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * @@ -1103,22 +1114,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { return Result; } -Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, - Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { - bool Ignore = TestAndClearIgnoreResultAssign(); +LValue ScalarExprEmitter::EmitCompoundAssignLValue( + const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &), + Value *&BitFieldResult) { QualType LHSTy = E->getLHS()->getType(); - + BitFieldResult = 0; BinOpInfo OpInfo; - + if (E->getComputationResultType()->isAnyComplexType()) { // This needs to go through the complex expression emitter, but it's a tad // complicated to do that... I'm leaving it out for now. (Note that we do // actually need the imaginary part of the RHS for multiplication and // division.) CGF.ErrorUnsupported(E, "complex compound assignment"); - return llvm::UndefValue::get(CGF.ConvertType(E->getType())); + llvm::UndefValue::get(CGF.ConvertType(E->getType())); + return LValue(); } - + // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. OpInfo.RHS = Visit(E->getRHS()); @@ -1129,13 +1142,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); - + // Expand the binary operator. Value *Result = (this->*Func)(OpInfo); - + // Convert the result back to the LHS type. Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy); - + // Store the result value into the LHS lvalue. Bit-fields are handled // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the @@ -1144,11 +1157,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, if (!LHSLV.isVolatileQualified()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy, &Result); - return Result; + BitFieldResult = Result; + return LHSLV; } else CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy); } else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy); + return LHSLV; +} + +Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { + bool Ignore = TestAndClearIgnoreResultAssign(); + Value *BitFieldResult; + LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult); + if (BitFieldResult) + return BitFieldResult; + if (Ignore) return 0; return EmitLoadOfLValue(LHSLV, E->getType()); @@ -1914,3 +1939,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { return LV; } + +LValue CodeGenFunction::EmitCompoundAssignOperatorLValue( + const CompoundAssignOperator *E) { + ScalarExprEmitter Scalar(*this); + Value *BitFieldResult = 0; + switch (E->getOpcode()) { +#define COMPOUND_OP(Op) \ + case BinaryOperator::Op##Assign: \ + return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \ + BitFieldResult) + COMPOUND_OP(Mul); + COMPOUND_OP(Div); + COMPOUND_OP(Rem); + COMPOUND_OP(Add); + COMPOUND_OP(Sub); + COMPOUND_OP(Shl); + COMPOUND_OP(Shr); + COMPOUND_OP(And); + COMPOUND_OP(Xor); + COMPOUND_OP(Or); +#undef COMPOUND_OP + + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::Assign: + case BinaryOperator::Comma: + assert(false && "Not valid compound assignment operators"); + break; + } + + llvm_unreachable("Unhandled compound assignment operator"); +} diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 206d438..3359250 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -53,31 +53,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // arguments in generic code. CGObjCRuntime &Runtime = CGM.getObjCRuntime(); - const Expr *ReceiverExpr = E->getReceiver(); bool isSuperMessage = false; bool isClassMessage = false; + ObjCInterfaceDecl *OID = 0; // Find the receiver - llvm::Value *Receiver; - if (!ReceiverExpr) { - const ObjCInterfaceDecl *OID = E->getClassInfo().Decl; - - // Very special case, super send in class method. The receiver is - // self (the class object) and the send uses super semantics. - if (!OID) { - assert(E->getClassName()->isStr("super") && - "Unexpected missing class interface in message send."); - isSuperMessage = true; - Receiver = LoadObjCSelf(); - } else { - Receiver = Runtime.GetClass(Builder, OID); - } - + llvm::Value *Receiver = 0; + switch (E->getReceiverKind()) { + case ObjCMessageExpr::Instance: + Receiver = EmitScalarExpr(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: { + const ObjCInterfaceType *IFace + = E->getClassReceiver()->getAs(); + OID = IFace->getDecl(); + assert(IFace && "Invalid Objective-C class message send"); + Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; - } else if (isa(E->getReceiver())) { + break; + } + + case ObjCMessageExpr::SuperInstance: + Receiver = LoadObjCSelf(); isSuperMessage = true; + break; + + case ObjCMessageExpr::SuperClass: Receiver = LoadObjCSelf(); - } else { - Receiver = EmitScalarExpr(E->getReceiver()); + isSuperMessage = true; + isClassMessage = true; + break; } CallArgList Args; @@ -98,7 +103,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { } return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), - Receiver, isClassMessage, Args, + Receiver, Args, OID, E->getMethodDecl()); } @@ -148,19 +153,21 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + bool IsAtomic = + !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); // FIXME: This is rather murky, we create this here since they will not have // been created by Sema for us. OMD->createImplicitParams(getContext(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); - + // Determine if we should use an objc_getProperty call for // this. Non-atomic properties are directly evaluated. // atomic 'copy' and 'retain' properties are also directly // evaluated in gc-only mode. if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && - !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) && + IsAtomic && (PD->getSetterKind() == ObjCPropertyDecl::Copy || PD->getSetterKind() == ObjCPropertyDecl::Retain)) { llvm::Value *GetPropertyFn = @@ -208,7 +215,44 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); } else if (hasAggregateLLVMType(Ivar->getType())) { - EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + bool IsStrong = false; + if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType()))) + && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect + && CGM.getObjCRuntime().GetCopyStructFunction()) { + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + // objc_copyStruct (ReturnValue, &structIvar, + // sizeof (Type of Ivar), isAtomic, false); + CallArgList Args; + RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *isAtomic = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsAtomic ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(isAtomic), + getContext().BoolTy)); + llvm::Value *hasStrong = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsStrong ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(hasStrong), + getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); + } + else + EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); } else { CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); @@ -289,6 +333,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), SetPropertyFn, ReturnValueSlot(), Args); + } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) && + !Ivar->getType()->isAnyComplexType() && + IndirectObjCSetterArg(*CurFnInfo) + && CGM.getObjCRuntime().GetCopyStructFunction()) { + // objc_copyStruct (&structIvar, &Arg, + // sizeof (struct something), true, false); + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + CallArgList Args; + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); + RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; + llvm::Value *ArgAsPtrTy = + Builder.CreateBitCast(Arg, + Types.ConvertType(getContext().VoidPtrTy)); + RV = RValue::get(ArgAsPtrTy); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *True = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); + Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + llvm::Value *False = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); + Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -304,7 +383,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, if (getContext().getCanonicalType(Ivar->getType()) != getContext().getCanonicalType(ArgDecl->getType())) { ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, - false); + CXXBaseSpecifierArray(), false); BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, Ivar->getType(), Loc); EmitStmt(&Assign); @@ -318,6 +397,83 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FinishFunction(); } +void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, + bool ctor) { + llvm::SmallVector IvarInitializers; + MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface()); + StartObjCMethod(MD, IMP->getClassInterface()); + for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), + E = IMP->init_end(); B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + IvarInitializers.push_back(Member); + } + if (ctor) { + for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) { + CXXBaseOrMemberInitializer *IvarInit = IvarInitializers[I]; + FieldDecl *Field = IvarInit->getMember(); + QualType FieldType = Field->getType(); + ObjCIvarDecl *Ivar = cast(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + EmitAggExpr(IvarInit->getInit(), LV.getAddress(), + LV.isVolatileQualified(), false, true); + } + // constructor returns 'self'. + CodeGenTypes &Types = CGM.getTypes(); + QualType IdTy(CGM.getContext().getObjCIdType()); + llvm::Value *SelfAsId = + Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); + EmitReturnOfRValue(RValue::get(SelfAsId), IdTy); + } + else { + // dtor + for (size_t i = IvarInitializers.size(); i > 0; --i) { + FieldDecl *Field = IvarInitializers[i - 1]->getMember(); + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + ObjCIvarDecl *Ivar = cast(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + const RecordType *RT = FieldType->getAs(); + CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LV.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(CGM.getContext()), + Dtor_Complete, /*ForVirtualBase=*/false, + LV.getAddress()); + } + } + FinishFunction(); +} + +bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) { + CGFunctionInfo::const_arg_iterator it = FI.arg_begin(); + it++; it++; + const ABIArgInfo &AI = it->info; + // FIXME. Is this sufficient check? + return (AI.getKind() == ABIArgInfo::Indirect); +} + +bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { + if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + return false; + if (const RecordType *FDTTy = Ty.getTypePtr()->getAs()) + return FDTTy->getDecl()->hasObjectMember(); + return false; +} + llvm::Value *CodeGenFunction::LoadObjCSelf() { const ObjCMethodDecl *OMD = cast(CurFuncDecl); // See if we need to lazily forward self inside a block literal. @@ -360,7 +516,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, EmitScalarExpr(E->getBase()), - false, CallArgList()); + CallArgList()); } else { const ObjCImplicitSetterGetterRefExpr *KE = cast(Exp); @@ -376,7 +532,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, Receiver, - KE->getInterfaceDecl() != 0, CallArgList()); + CallArgList(), KE->getInterfaceDecl()); } } @@ -413,7 +569,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, EmitScalarExpr(E->getBase()), - false, Args); + Args); } else if (const ObjCImplicitSetterGetterRefExpr *E = dyn_cast(Exp)) { Selector S = E->getSetterMethod()->getSelector(); @@ -430,7 +586,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, Receiver, - E->getInterfaceDecl() != 0, Args); + Args, E->getInterfaceDecl()); } else assert (0 && "bad expression node in EmitObjCPropertySet"); } @@ -498,7 +654,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy, "limit.ptr"); @@ -623,7 +779,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); Limit = Builder.CreateLoad(LimitPtr); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index d445200..3c51b7e 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -26,6 +26,7 @@ #include "llvm/Intrinsics.h" #include "llvm/Module.h" +#include "llvm/LLVMContext.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Compiler.h" @@ -81,6 +82,8 @@ private: llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; llvm::LLVMContext &VMContext; + /// Metadata kind used to tie method lookups to message sends. + unsigned msgSendMDKind; private: llvm::Constant *GenerateIvarList( const llvm::SmallVectorImpl &IvarNames, @@ -112,7 +115,8 @@ private: llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties); + llvm::Constant *Properties, + bool isMeta=false); llvm::Constant *GenerateProtocolMethodList( const llvm::SmallVectorImpl &MethodNames, const llvm::SmallVectorImpl &MethodTypes); @@ -141,8 +145,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, @@ -170,6 +174,7 @@ public: virtual llvm::Function *ModuleInitFunction(); virtual llvm::Function *GetPropertyGetFunction(); virtual llvm::Function *GetPropertySetFunction(); + virtual llvm::Function *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -221,10 +226,6 @@ void CGObjCGNU::EmitClassRef(const std::string &className) { llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } -static std::string SymbolNameForClass(const std::string &ClassName) { - return "_OBJC_CLASS_" + ClassName; -} - static std::string SymbolNameForMethod(const std::string &ClassName, const std::string &CategoryName, const std::string &MethodName, bool isClassMethod) { @@ -238,6 +239,9 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) { + + msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); + IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); LongTy = cast( @@ -452,12 +456,15 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } - llvm::Value *cmd = GetSelector(CGF.Builder, Sel); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *cmd = GetSelector(Builder, Sel); + CallArgList ActualArgs; ActualArgs.push_back( - std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), + std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)), ASTIdTy)); ActualArgs.push_back(std::make_pair(RValue::get(cmd), CGF.getContext().getObjCSelType())); @@ -481,7 +488,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, Params, true), "objc_get_class"); } - ReceiverClass = CGF.Builder.CreateCall(classLookupFunction, + ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); } else { // Set up global aliases for the metaclass or class pointer if they do not @@ -506,36 +513,64 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } } // Cast the pointer to a simplified version of the class structure - ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass, + ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual( llvm::StructType::get(VMContext, IdTy, IdTy, NULL))); // Get the superclass pointer - ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1); + ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1); // Load the superclass pointer - ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass); + ReceiverClass = Builder.CreateLoad(ReceiverClass); // Construct the structure used to look up the IMP llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext, Receiver->getType(), IdTy, NULL); - llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy); + llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy); - CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); - CGF.Builder.CreateStore(ReceiverClass, - CGF.Builder.CreateStructGEP(ObjCSuper, 1)); + Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); + Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); // Get the IMP std::vector Params; Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy)); Params.push_back(SelectorTy); + + llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; + llvm::Value *imp; + + if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { + // The lookup function returns a slot, which can be safely cached. + llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, + IntTy, llvm::PointerType::getUnqual(impType), NULL); + + llvm::Constant *lookupFunction = + CGM.CreateRuntimeFunction(llvm::FunctionType::get( + llvm::PointerType::getUnqual(SlotTy), Params, true), + "objc_slot_lookup_super"); + + llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs, + lookupArgs+2); + slot->setOnlyReadsMemory(); + + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + } else { llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::PointerType::getUnqual(impType), Params, true), "objc_msg_lookup_super"); + imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2); + } - llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; - llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs, - lookupArgs+2); - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + return msgRet; } /// Generate code for a message send expression. @@ -544,9 +579,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { + // Strip out message sends to retain / release in GC mode if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(Receiver); @@ -555,7 +591,39 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } + CGBuilderTy &Builder = CGF.Builder; + + // If the return type is something that goes in an integer register, the + // runtime will handle 0 returns. For other cases, we fill in the 0 value + // ourselves. + // + // The language spec says the result of this kind of message send is + // undefined, but lots of people seem to have forgotten to read that + // paragraph and insist on sending messages to nil that have structure + // returns. With GCC, this generates a random return value (whatever happens + // to be on the stack / in those registers at the time) on most platforms, + // and generates a SegV on SPARC. With LLVM it corrupts the stack. + bool isPointerSizedReturn = false; + if (ResultType->isAnyPointerType() || ResultType->isIntegralType() || + ResultType->isVoidType()) + isPointerSizedReturn = true; + + llvm::BasicBlock *startBB = 0; + llvm::BasicBlock *messageBB = 0; + llvm::BasicBlock *contiueBB = 0; + + if (!isPointerSizedReturn) { + startBB = Builder.GetInsertBlock(); + messageBB = CGF.createBasicBlock("msgSend"); + contiueBB = CGF.createBasicBlock("continue"); + + llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, + llvm::Constant::getNullValue(Receiver->getType())); + Builder.CreateCondBr(isNil, contiueBB, messageBB); + CGF.EmitBlock(messageBB); + } + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) @@ -577,6 +645,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Value *imp; // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. @@ -611,9 +687,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, LookupFn->setDoesNotCapture(1); } - llvm::Value *slot = + llvm::CallInst *slot = Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self); + slot->setOnlyReadsMemory(); + slot->setMetadata(msgSendMDKind, node); + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + // The lookup function may have changed the receiver, so make sure we use // the new one. ActualArgs[0] = @@ -628,9 +708,46 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, "objc_msg_lookup"); imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); + cast(imp)->setMetadata(msgSendMDKind, node); } - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + + if (!isPointerSizedReturn) { + CGF.EmitBlock(contiueBB); + if (msgRet.isScalar()) { + llvm::Value *v = msgRet.getScalarVal(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + phi->addIncoming(v, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); + msgRet = RValue::get(phi); + } else if (msgRet.isAggregate()) { + llvm::Value *v = msgRet.getAggregateAddr(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + const llvm::PointerType *RetTy = cast(v->getType()); + llvm::AllocaInst *NullVal = + CGF.CreateTempAlloca(RetTy->getElementType(), "null"); + CGF.InitTempAlloca(NullVal, + llvm::Constant::getNullValue(RetTy->getElementType())); + phi->addIncoming(v, messageBB); + phi->addIncoming(NullVal, startBB); + msgRet = RValue::getAggregate(phi); + } else /* isComplex() */ { + std::pair v = msgRet.getComplexVal(); + llvm::PHINode *phi = Builder.CreatePHI(v.first->getType()); + phi->addIncoming(v.first, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), + startBB); + llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType()); + phi2->addIncoming(v.second, messageBB); + phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), + startBB); + msgRet = RValue::getComplex(phi, phi2); + } + } + return msgRet; } /// Generates a MethodList. Used in construction of a objc_class and @@ -749,7 +866,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties) { + llvm::Constant *Properties, + bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. @@ -799,8 +917,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. - return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name), - llvm::GlobalValue::ExternalLinkage); + return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_": + "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage); } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( @@ -1289,16 +1407,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { instanceSize = 0 - (instanceSize - superInstanceSize); } - for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(), - endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) { + + // Collect declared and synthesized ivars. + llvm::SmallVector OIvars; + CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars); + + for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { + ObjCIvarDecl *IVD = OIvars[i]; // Store the name - IvarNames.push_back(MakeConstantString((*iter)->getNameAsString())); + IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; - Context.getObjCEncodingForType((*iter)->getType(), TypeStr); + Context.getObjCEncodingForType(IVD->getType(), TypeStr); IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset - uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { Offset = BaseOffset - superInstanceSize; @@ -1309,7 +1432,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(IntTy, BaseOffset), "__objc_ivar_offset_value_" + ClassName +"." + - (*iter)->getNameAsString())); + IVD->getNameAsString())); } llvm::Constant *IvarOffsetArrayInit = llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy, @@ -1411,7 +1534,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr); + empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true); // Generate the class structure llvm::Constant *ClassStruct = @@ -1658,10 +1781,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(BoolTy); - // void objc_getProperty (id, SEL, ptrdiff_t, bool) + // void objc_getProperty (id, SEL, int, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Params, false); return cast(CGM.CreateRuntimeFunction(FTy, @@ -1674,18 +1796,22 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(IdTy); Params.push_back(BoolTy); Params.push_back(BoolTy); - // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) + // void objc_setProperty (id, SEL, int, id, bool, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); return cast(CGM.CreateRuntimeFunction(FTy, "objc_setProperty")); } +// FIXME. Implement this. +llvm::Function *CGObjCGNU::GetCopyStructFunction() { + return 0; +} + llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -1764,7 +1890,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow"); llvm::SmallVector ESelArgs; - llvm::SmallVector, 8> Handlers; + llvm::SmallVector, 8> Handlers; ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); @@ -1772,12 +1898,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, bool HasCatchAll = false; // Only @try blocks are allowed @catch blocks, but both can have @finally if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { + if (cast(S).getNumCatchStmts()) { + const ObjCAtTryStmt &AtTry = cast(S); CGF.setInvokeDest(CatchInCatch); - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); @@ -1816,7 +1943,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.begin(), ESelArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -2046,7 +2173,14 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( // when linked against code which isn't (most of the time). llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); if (!IvarOffsetPointer) { - uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + uint64_t Offset; + if (ObjCImplementationDecl *OID = + CGM.getContext().getObjCImplementation( + const_cast(ID))) + Offset = ComputeIvarBaseOffset(CGM, OID, Ivar); + else + Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar"); // Don't emit the guess in non-PIC code because the linker will not be able diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index ac8fa05..77eabbf 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -124,9 +124,19 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // layout object. However, this is blocked on other cleanups to the // Objective-C code, so for now we just live with allocating a bunch of these // objects. - unsigned FieldNo = 0; // This value is unused. + + // We always construct a single, possibly unaligned, access for this case. + CGBitFieldInfo::AccessInfo AI; + AI.FieldIndex = 0; + AI.FieldByteOffset = 0; + AI.FieldBitStart = BitOffset; + AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy); + AI.AccessAlignment = 0; + AI.TargetBitOffset = 0; + AI.TargetBitWidth = BitFieldSize; + CGBitFieldInfo *Info = - new (CGF.CGM.getContext()) CGBitFieldInfo(FieldNo, BitOffset, BitFieldSize, + new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI, IvarTy->isSignedIntegerType()); // FIXME: We need to set a very conservative alignment on this, or make sure @@ -329,6 +339,24 @@ public: return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } + + llvm::Constant *getCopyStructFn() { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); + // void objc_copyStruct (void *, const void *, size_t, bool, bool) + llvm::SmallVector Params; + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.BoolTy); + Params.push_back(Ctx.BoolTy); + const llvm::FunctionType *FTy = + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + FunctionType::ExtInfo()), + false); + return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct"); + } + llvm::Constant *getEnumerationMutationFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -954,6 +982,10 @@ protected: const ObjCMethodDecl *OMD, const ObjCCommonTypesHelper &ObjCTypes); + /// EmitImageInfo - Emit the image info marker used to encode some module + /// level information. + void EmitImageInfo(); + public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } @@ -980,9 +1012,6 @@ public: class CGObjCMac : public CGObjCCommonMac { private: ObjCTypesHelper ObjCTypes; - /// EmitImageInfo - Emit the image info marker used to encode some module - /// level information. - void EmitImageInfo(); /// EmitModuleInfo - Another marker encoding module level /// information. @@ -1100,8 +1129,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1134,6 +1163,7 @@ public: virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); + virtual llvm::Constant *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -1327,8 +1357,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1366,6 +1396,11 @@ public: virtual llvm::Constant *GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } + + virtual llvm::Constant *GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); + } + virtual llvm::Constant *EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -1459,9 +1494,20 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl }; */ +/// or Generate a constant NSString object. +/* + struct __builtin_NSString { + const int *isa; // point to __NSConstantStringClassReference + const char *str; + unsigned int length; + }; +*/ + llvm::Constant *CGObjCCommonMac::GenerateConstantString( const StringLiteral *SL) { - return CGM.GetAddrOfConstantCFString(SL); + return (CGM.getLangOptions().NoConstantCFStrings == 0 ? + CGM.GetAddrOfConstantCFString(SL) : + CGM.GetAddrOfConstantNSString(SL)); } /// Generates a message send where the super is the receiver. This is @@ -1531,8 +1577,8 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -1696,7 +1742,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { Init, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -1718,7 +1763,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { 0, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -2039,6 +2083,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; + if (ID->getNumIvarInitializers()) + Flags |= eClassFlags_HasCXXStructors; unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8; @@ -2430,6 +2476,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } +llvm::Constant *CGObjCMac::GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); +} + llvm::Constant *CGObjCMac::EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -2597,8 +2647,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); - } else if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { + } else if (cast(S).getNumCatchStmts()) { + const ObjCAtTryStmt* AtTryStmt = cast(&S); + // Enter a new exception try block (in case a @catch block throws // an exception). CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData); @@ -2617,10 +2668,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // matched and avoid generating code for falling off the end if // so. bool AllMatched = false; - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { + for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I); llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch"); - const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl(); + const VarDecl *CatchParam = CatchStmt->getCatchParamDecl(); const ObjCObjectPointerType *OPT = 0; // catch(...) always matches. @@ -2911,18 +2963,17 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, /// unsigned flags; /// }; enum ImageInfoFlags { - eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what - // this implies. + eImageInfo_FixAndContinue = (1 << 0), eImageInfo_GarbageCollected = (1 << 1), eImageInfo_GCOnly = (1 << 2), eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set. - // A flag indicating that the module has no instances of an - // @synthesize of a superclass variable. + // A flag indicating that the module has no instances of a @synthesize of a + // superclass variable. eImageInfo_CorrectedSynthesize = (1 << 4) }; -void CGObjCMac::EmitImageInfo() { +void CGObjCCommonMac::EmitImageInfo() { unsigned version = 0; // Version is unused? unsigned flags = 0; @@ -3132,19 +3183,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; if (RD) { - const CGRecordLayout &RL = - CGM.getTypes().getCGRecordLayout(Field->getParent()); - if (Field->isBitField()) { - const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - const llvm::Type *Ty = - CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); - uint64_t TypeSize = - CGM.getTypes().getTargetData().getTypeAllocSize(Ty); - FieldOffset = Info.FieldNo * TypeSize; - } else - FieldOffset = - Layout->getElementOffset(RL.getLLVMFieldNo(Field)); + // Note that 'i' here is actually the field index inside RD of Field, + // although this dependency is hidden. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + FieldOffset = RL.getFieldOffset(i) / 8; } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast(Field)); @@ -3536,7 +3578,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = dyn_cast(D->getDeclContext())) - OS << '(' << CID->getNameAsString() << ')'; + OS << '(' << CID << ')'; OS << ' ' << D->getSelector().getAsString() << ']'; } @@ -3574,14 +3616,14 @@ void CGObjCMac::FinishModule() { Asm += '\n'; llvm::raw_svector_ostream OS(Asm); - for (llvm::SetVector::iterator I = LazySymbols.begin(), - e = LazySymbols.end(); I != e; ++I) - OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; for (llvm::SetVector::iterator I = DefinedSymbols.begin(), e = DefinedSymbols.end(); I != e; ++I) OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n" << "\t.globl .objc_class_name_" << (*I)->getName() << "\n"; - + for (llvm::SetVector::iterator I = LazySymbols.begin(), + e = LazySymbols.end(); I != e; ++I) + OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; + CGM.getModule().setModuleInlineAsm(OS.str()); } } @@ -3627,7 +3669,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // id self; // Class cls; // } - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4088,7 +4131,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // }; // First the clang type for struct _message_ref_t - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4162,7 +4206,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(const llvm::GlobalValue::InternalLinkage, Init, SymbolName); - GV->setAlignment(8); + GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(SectionName); CGM.AddUsedGlobal(GV); } @@ -4203,28 +4247,7 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$", "__DATA, __objc_nlcatlist, regular, no_dead_strip"); - // static int L_OBJC_IMAGE_INFO[2] = { 0, flags }; - // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0 - std::vector Values(2); - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0); - unsigned int flags = 0; - // FIXME: Fix and continue? - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) - flags |= eImageInfo_GarbageCollected; - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) - flags |= eImageInfo_GCOnly; - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); - llvm::Constant* Init = llvm::ConstantArray::get( - llvm::ArrayType::get(ObjCTypes.IntTy, 2), - Values); - llvm::GlobalVariable *IMGV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::InternalLinkage, - Init, - "\01L_OBJC_IMAGE_INFO"); - IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip"); - IMGV->setConstant(true); - CGM.AddUsedGlobal(IMGV); + EmitImageInfo(); } /// LegacyDispatchedSelector - Returns true if SEL is not in the list of @@ -4233,9 +4256,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { /// message dispatch call for all the rest. /// bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { - if (CGM.getCodeGenOpts().ObjCLegacyDispatch) + switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { + default: + assert(0 && "Invalid dispatch method!"); + case CodeGenOptions::Legacy: return true; + case CodeGenOptions::NonLegacy: + return false; + case CodeGenOptions::Mixed: + break; + } + // If so, see whether this selector is in the white-list of things which must + // use the new dispatch convention. We lazily build a dense set for this. if (NonLegacyDispatchMethods.empty()) { NonLegacyDispatchMethods.insert(GetNullarySelector("alloc")); NonLegacyDispatchMethods.insert(GetNullarySelector("class")); @@ -4265,6 +4298,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { NonLegacyDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); } + return (NonLegacyDispatchMethods.count(Sel) == 0); } @@ -4369,7 +4403,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); CLASS_RO_GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); CLASS_RO_GV->setSection("__DATA, __objc_const"); return CLASS_RO_GV; @@ -4405,7 +4439,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( GV->setInitializer(Init); GV->setSection("__DATA, __objc_data"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy)); if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return GV; @@ -4467,6 +4501,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (!ID->getClassInterface()->getSuperClass()) { // class is root flags |= CLS_ROOT; @@ -4501,6 +4537,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { flags = CLS; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface())) flags |= CLS_EXCEPTION; @@ -4655,7 +4693,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Init, ExtCatName); GCATV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy)); GCATV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); @@ -4715,7 +4753,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, Init, Name); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(Section); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, @@ -4750,7 +4788,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, Offset)); IvarOffsetGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy)); // FIXME: This matches gcc, but shouldn't the visibility be set on the use as // well (i.e., in ObjCIvarOffsetVariable). @@ -4837,7 +4875,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( Init, Prefix + OID->getName()); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GV); @@ -4956,7 +4994,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Init, "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -4969,7 +5007,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Entry, "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); @@ -5025,7 +5063,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, Name); GV->setSection("__DATA, __objc_const"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); @@ -5184,8 +5222,8 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return LegacyDispatchedSelector(Sel) ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -5222,7 +5260,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_REFERENCES_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5245,7 +5283,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5271,7 +5309,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, MetaClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); @@ -5532,45 +5570,44 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr()); // Construct the lists of (type, catch body) to handle. - llvm::SmallVector, 8> Handlers; + llvm::SmallVector, 8> Handlers; bool HasCatchAll = false; if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast(S).getCatchStmts()) { - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - - // catch(...) always matches. - if (!CatchDecl) { - // Use i8* null here to signal this is a catch all, not a cleanup. - llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); - SelectorArgs.push_back(Null); - HasCatchAll = true; - break; - } + const ObjCAtTryStmt &AtTry = cast(S); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - if (CatchDecl->getType()->isObjCIdType() || - CatchDecl->getType()->isObjCQualifiedIdType()) { - llvm::Value *IDEHType = - CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); - if (!IDEHType) - IDEHType = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, "OBJC_EHTYPE_id"); - SelectorArgs.push_back(IDEHType); - } else { - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *PT = - CatchDecl->getType()->getAs(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = PT->getInterfaceType(); - assert(IT && "Invalid @catch type."); - llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); - SelectorArgs.push_back(EHType); - } + // catch(...) always matches. + if (!CatchDecl) { + // Use i8* null here to signal this is a catch all, not a cleanup. + llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + SelectorArgs.push_back(Null); + HasCatchAll = true; + break; + } + + if (CatchDecl->getType()->isObjCIdType() || + CatchDecl->getType()->isObjCQualifiedIdType()) { + llvm::Value *IDEHType = + CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, "OBJC_EHTYPE_id"); + SelectorArgs.push_back(IDEHType); + } else { + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *PT = + CatchDecl->getType()->getAs(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); + SelectorArgs.push_back(EHType); } } } @@ -5589,7 +5626,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -5612,14 +5649,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (CatchBody) { llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end"); - llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); // Cleanups must call objc_end_catch. - // - // FIXME: It seems incorrect for objc_begin_catch to be inside this - // context, but this matches gcc. CGF.PushCleanupBlock(MatchEnd); - CGF.setInvokeDest(MatchHandler); llvm::Value *ExcObject = CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc); @@ -5636,25 +5668,37 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam)); } + // Exceptions inside the catch block must be rethrown. We set a special + // purpose invoke destination for this which just collects the thrown + // exception and overwrites the object in RethrowPtr, branches through the + // match.end to make sure we call objc_end_catch, before branching to the + // rethrow handler. + llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); + CGF.setInvokeDest(MatchHandler); CGF.ObjCEHValueStack.push_back(ExcObject); CGF.EmitStmt(CatchBody); CGF.ObjCEHValueStack.pop_back(); + CGF.setInvokeDest(0); CGF.EmitBranchThroughCleanup(FinallyEnd); - CGF.EmitBlock(MatchHandler); - - llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); - // We are required to emit this call to satisfy LLVM, even - // though we don't use the result. - llvm::SmallVector Args; - Args.push_back(Exc); - Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); - CGF.Builder.CreateStore(Exc, RethrowPtr); - CGF.EmitBranchThroughCleanup(FinallyRethrow); + // Don't emit the extra match handler if there we no unprotected calls in + // the catch block. + if (MatchHandler->use_empty()) { + delete MatchHandler; + } else { + CGF.EmitBlock(MatchHandler); + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); + CGF.Builder.CreateStore(Exc, RethrowPtr); + CGF.EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock(); @@ -5666,8 +5710,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.createBasicBlock("match.end.handler"); llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(), - Cont, MatchEndHandler, - Args.begin(), Args.begin()); + Cont, MatchEndHandler); CGF.EmitBlock(Cont); if (Info.SwitchBlock) @@ -5676,15 +5719,14 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Info.EndBlock); CGF.EmitBlock(MatchEndHandler); - Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); CGF.Builder.CreateStore(Exc, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); @@ -5723,9 +5765,19 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Branch around the rethrow code. CGF.EmitBranch(FinallyEnd); + // Generate the rethrow code, taking care to use an invoke if we are in a + // nested exception scope. CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), - CGF.Builder.CreateLoad(RethrowPtr)); + if (PrevLandingPad) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(ObjCTypes.getUnwindResumeOrRethrowFn(), + Cont, PrevLandingPad, + CGF.Builder.CreateLoad(RethrowPtr)); + CGF.EmitBlock(Cont); + } else { + CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), + CGF.Builder.CreateLoad(RethrowPtr)); + } CGF.Builder.CreateUnreachable(); CGF.EmitBlock(FinallyEnd); @@ -5816,7 +5868,8 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - Entry->setAlignment(8); + Entry->setAlignment(CGM.getTargetData().getABITypeAlignment( + ObjCTypes.EHTypeTy)); if (ForDefinition) { Entry->setSection("__DATA,__objc_const"); diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index e478394..654ad0a 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -122,8 +122,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class = 0, const ObjCMethodDecl *Method = 0) = 0; /// Generate an Objective-C message send operation to the super @@ -167,6 +167,9 @@ public: /// Return the runtime function for setting properties. virtual llvm::Constant *GetPropertySetFunction() = 0; + // API for atomic copying of qualified aggregates in setter/getter. + virtual llvm::Constant *GetCopyStructFunction() = 0; + /// GetClass - Return a reference to the class for the given /// interface decl. virtual llvm::Value *GetClass(CGBuilderTy &Builder, diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 1caec97..aec1c45 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -31,8 +31,8 @@ class RTTIBuilder { /// descriptor of the given type. llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); - /// BuildVtablePointer - Build the vtable pointer for the given type. - void BuildVtablePointer(const Type *Ty); + /// BuildVTablePointer - Build the vtable pointer for the given type. + void BuildVTablePointer(const Type *Ty); /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. @@ -148,6 +148,9 @@ public: }; /// BuildTypeInfo - Build the RTTI type info struct for the given type. + /// + /// \param Force - true to force the creation of this RTTI value + /// \param ForEH - true if this is for exception handling llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); }; } @@ -242,9 +245,10 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { } /// ShouldUseExternalRTTIDescriptor - Returns whether the type information for -/// the given type exists somewhere else, and that we should not emit the typ +/// the given type exists somewhere else, and that we should not emit the type /// information in this translation unit. -bool ShouldUseExternalRTTIDescriptor(QualType Ty) { +static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, + QualType Ty) { // Type info for builtin types is defined in the standard library. if (const BuiltinType *BuiltinTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(BuiltinTy); @@ -254,6 +258,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) { if (const PointerType *PointerTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(PointerTy); + // If RTTI is disabled, don't consider key functions. + if (!Context.getLangOptions().RTTI) return false; + if (const RecordType *RecordTy = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(RecordTy->getDecl()); if (!RD->hasDefinition()) @@ -337,7 +344,7 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { if (const RecordType *Record = dyn_cast(Ty)) { const CXXRecordDecl *RD = cast(Record->getDecl()); if (RD->isDynamicClass()) - return CodeGenModule::getVtableLinkage(RD); + return CodeGenModule::getVTableLinkage(RD); } return llvm::GlobalValue::WeakODRLinkage; @@ -375,8 +382,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { return true; } -void RTTIBuilder::BuildVtablePointer(const Type *Ty) { - const char *VtableName; +void RTTIBuilder::BuildVTablePointer(const Type *Ty) { + const char *VTableName; switch (Ty->getTypeClass()) { default: assert(0 && "Unhandled type!"); @@ -386,24 +393,24 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Vector: case Type::ExtVector: // abi::__fundamental_type_info. - VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; + VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; break; case Type::ConstantArray: case Type::IncompleteArray: // abi::__array_type_info. - VtableName = "_ZTVN10__cxxabiv117__array_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; break; case Type::FunctionNoProto: case Type::FunctionProto: // abi::__function_type_info. - VtableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; break; case Type::Enum: // abi::__enum_type_info. - VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; + VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; break; case Type::Record: { @@ -412,13 +419,13 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { if (!RD->hasDefinition() || !RD->getNumBases()) { // abi::__class_type_info. - VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__class_type_infoE"; } else if (CanUseSingleInheritance(RD)) { // abi::__si_class_type_info. - VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; } else { // abi::__vmi_class_type_info. - VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; } break; @@ -426,30 +433,31 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Pointer: // abi::__pointer_type_info. - VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; + VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; break; case Type::MemberPointer: // abi::__pointer_to_member_type_info. - VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; + VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; break; } - llvm::Constant *Vtable = - CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy); + llvm::Constant *VTable = + CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy); const llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); // The vtable address point is 2. llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1); - Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy); + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1); + VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy); - Fields.push_back(Vtable); + Fields.push_back(VTable); } -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, + bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); @@ -463,13 +471,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); // Check if there is already an external RTTI descriptor for this type. - if (!Force && ShouldUseExternalRTTIDescriptor(Ty)) + if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty)) return GetAddrOfExternalRTTIDescriptor(Ty); llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); // Add the vtable pointer. - BuildVtablePointer(cast(Ty)); + BuildVTablePointer(cast(Ty)); // And the name. Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage)); @@ -782,42 +790,17 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); } -llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) { - if (!getContext().getLangOptions().RTTI) { +llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, + bool ForEH) { + // Return a bogus pointer if RTTI is disabled, unless it's for EH. + // FIXME: should we even be calling this method if RTTI is disabled + // and it's not for EH? + if (!ForEH && !getContext().getLangOptions().RTTI) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); return llvm::Constant::getNullValue(Int8PtrTy); } - - return RTTIBuilder(*this).BuildTypeInfo(Ty); -} -// Try to find the magic class __cxxabiv1::__fundamental_type_info. If -// exists and has a destructor, we will emit the typeinfo for the fundamental -// types. This is the same behaviour as GCC. -static CXXRecordDecl *FindMagicClass(ASTContext &AC) { - const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1"); - DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII); - TranslationUnitDecl *TUD = AC.getTranslationUnitDecl(); - DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN); - if (NamespaceLookup.first == NamespaceLookup.second) - return NULL; - const NamespaceDecl *Namespace = - dyn_cast(*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(*ClassLookup.first); - - if (Class->hasDefinition() && Class->isDynamicClass() && - Class->getDestructor(AC)) - return Class; - - return NULL; + return RTTIBuilder(*this).BuildTypeInfo(Ty); } void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { @@ -829,12 +812,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { } void CodeGenModule::EmitFundamentalRTTIDescriptors() { - CXXRecordDecl *RD = FindMagicClass(getContext()); - if (!RD) - return; - - getVTables().GenerateClassData(getVtableLinkage(RD), RD); - QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty, Context.Char16Ty, Context.UnsignedLongLongTy, Context.LongLongTy, Context.WCharTy, diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index fd1775e..9f966fb 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -13,22 +13,137 @@ #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" namespace llvm { + class raw_ostream; class Type; } namespace clang { namespace CodeGen { +/// \brief Helper object for describing how to generate the code for access to a +/// bit-field. +/// +/// This structure is intended to describe the "policy" of how the bit-field +/// should be accessed, which may be target, language, or ABI dependent. class CGBitFieldInfo { public: - CGBitFieldInfo(unsigned FieldNo, unsigned Start, unsigned Size, - bool IsSigned) - : FieldNo(FieldNo), Start(Start), Size(Size), IsSigned(IsSigned) {} + /// Descriptor for a single component of a bit-field access. The entire + /// bit-field is constituted of a bitwise OR of all of the individual + /// components. + /// + /// Each component describes an accessed value, which is how the component + /// should be transferred to/from memory, and a target placement, which is how + /// that component fits into the constituted bit-field. The pseudo-IR for a + /// load is: + /// + /// %0 = gep %base, 0, FieldIndex + /// %1 = gep (i8*) %0, FieldByteOffset + /// %2 = (i(AccessWidth) *) %1 + /// %3 = load %2, align AccessAlignment + /// %4 = shr %3, FieldBitStart + /// + /// and the composed bit-field is formed as the boolean OR of all accesses, + /// masked to TargetBitWidth bits and shifted to TargetBitOffset. + struct AccessInfo { + /// Offset of the field to load in the LLVM structure, if any. + unsigned FieldIndex; + + /// Byte offset from the field address, if any. This should generally be + /// unused as the cleanest IR comes from having a well-constructed LLVM type + /// with proper GEP instructions, but sometimes its use is required, for + /// example if an access is intended to straddle an LLVM field boundary. + unsigned FieldByteOffset; + + /// Bit offset in the accessed value to use. The width is implied by \see + /// TargetBitWidth. + unsigned FieldBitStart; + + /// Bit width of the memory access to perform. + unsigned AccessWidth; + + /// The alignment of the memory access, or 0 if the default alignment should + /// be used. + // + // FIXME: Remove use of 0 to encode default, instead have IRgen do the right + // thing when it generates the code, if avoiding align directives is + // desired. + unsigned AccessAlignment; + + /// Offset for the target value. + unsigned TargetBitOffset; + + /// Number of bits in the access that are destined for the bit-field. + unsigned TargetBitWidth; + }; - unsigned FieldNo; - unsigned Start; +private: + /// The components to use to access the bit-field. We may need up to three + /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte + /// accesses). + // + // FIXME: De-hardcode this, just allocate following the struct. + AccessInfo Components[3]; + + /// The total size of the bit-field, in bits. unsigned Size; + + /// The number of access components to use. + unsigned NumComponents; + + /// Whether the bit-field is signed. bool IsSigned : 1; + +public: + CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components, + bool IsSigned) : Size(Size), NumComponents(NumComponents), + IsSigned(IsSigned) { + assert(NumComponents <= 3 && "invalid number of components!"); + for (unsigned i = 0; i != NumComponents; ++i) + Components[i] = _Components[i]; + + // Check some invariants. + unsigned AccessedSize = 0; + for (unsigned i = 0, e = getNumComponents(); i != e; ++i) { + const AccessInfo &AI = getComponent(i); + AccessedSize += AI.TargetBitWidth; + + // We shouldn't try to load 0 bits. + assert(AI.TargetBitWidth > 0); + + // We can't load more bits than we accessed. + assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth); + + // We shouldn't put any bits outside the result size. + assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size); + } + + // Check that the total number of target bits matches the total bit-field + // size. + assert(AccessedSize == Size && "Total size does not match accessed size!"); + } + +public: + /// \brief Check whether this bit-field access is (i.e., should be sign + /// extended on loads). + bool isSigned() const { return IsSigned; } + + /// \brief Get the size of the bit-field, in bits. + unsigned getSize() const { return Size; } + + /// @name Component Access + /// @{ + + unsigned getNumComponents() const { return NumComponents; } + + const AccessInfo &getComponent(unsigned Index) const { + assert(Index < getNumComponents() && "Invalid access!"); + return Components[Index]; + } + + /// @} + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; /// CGRecordLayout - This class handles struct and union layout info while @@ -71,15 +186,15 @@ public: return ContainsPointerToDataMember; } - /// \brief Return the BitFieldInfo that corresponds to the field FD. + /// \brief Return llvm::StructType element number that corresponds to the + /// field FD. unsigned getLLVMFieldNo(const FieldDecl *FD) const { assert(!FD->isBitField() && "Invalid call for bit-field decl!"); assert(FieldInfo.count(FD) && "Invalid field for record!"); return FieldInfo.lookup(FD); } - /// \brief Return llvm::StructType element number that corresponds to the - /// field FD. + /// \brief Return the BitFieldInfo that corresponds to the field FD. const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const { assert(FD->isBitField() && "Invalid call for non bit-field decl!"); llvm::DenseMap::const_iterator @@ -87,6 +202,9 @@ public: assert(it != BitFields.end() && "Unable to find bitfield info"); return it->second; } + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 4b9ec66..6302cf8 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -18,8 +18,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "CodeGenTypes.h" -#include "llvm/Type.h" #include "llvm/DerivedTypes.h" +#include "llvm/Type.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -67,6 +69,11 @@ private: /// NextFieldOffsetInBytes - Holds the next field offset in bytes. uint64_t NextFieldOffsetInBytes; + /// LayoutUnionField - Will layout a field in an union and return the type + /// that the field will have. + const llvm::Type *LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout); + /// LayoutUnion - Will layout a union RecordDecl. void LayoutUnion(const RecordDecl *D); @@ -87,10 +94,6 @@ private: /// AppendField - Appends a field with the given offset and type. void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total struct - /// size matches the alignment of the passed in type. - void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total /// struct size is a multiple of the field alignment. void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); @@ -103,7 +106,6 @@ private: void AppendTailPadding(uint64_t RecordSize); unsigned getTypeAlignment(const llvm::Type *Ty) const; - uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; /// CheckForPointerToDataMember - Check if the given type contains a pointer /// to data member. @@ -145,6 +147,104 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutFields(D); } +static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, + const FieldDecl *FD, + uint64_t FieldOffset, + uint64_t FieldSize) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); + uint64_t ContainingTypeSizeInBits = RL.getSize(); + unsigned ContainingTypeAlign = RL.getAlignment(); + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType()); + uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty); + uint64_t TypeSizeInBits = TypeSizeInBytes * 8; + + bool IsSigned = FD->getType()->isSignedIntegerType(); + + if (FieldSize > TypeSizeInBits) { + // We have a wide bit-field. The extra bits are only used for padding, so + // if we have a bitfield of type T, with size N: + // + // T t : N; + // + // We can just assume that it's: + // + // T t : sizeof(T); + // + FieldSize = TypeSizeInBits; + } + + // Compute the access components. The policy we use is to start by attempting + // to access using the width of the bit-field type itself and to always access + // at aligned indices of that type. If such an access would fail because it + // extends past the bound of the type, then we reduce size to the next smaller + // power of two and retry. The current algorithm assumes pow2 sized types, + // although this is easy to fix. + // + // FIXME: This algorithm is wrong on big-endian systems, I think. + assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!"); + CGBitFieldInfo::AccessInfo Components[3]; + unsigned NumComponents = 0; + unsigned AccessedTargetBits = 0; // The tumber of target bits accessed. + unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt. + + // Round down from the field offset to find the first access position that is + // at an aligned offset of the initial access type. + uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth); + + // Adjust initial access size to fit within record. + while (AccessWidth > 8 && + AccessStart + AccessWidth > ContainingTypeSizeInBits) { + AccessWidth >>= 1; + AccessStart = FieldOffset - (FieldOffset % AccessWidth); + } + + while (AccessedTargetBits < FieldSize) { + // Check that we can access using a type of this size, without reading off + // the end of the structure. This can occur with packed structures and + // -fno-bitfield-type-align, for example. + if (AccessStart + AccessWidth > ContainingTypeSizeInBits) { + // If so, reduce access size to the next smaller power-of-two and retry. + AccessWidth >>= 1; + assert(AccessWidth >= 8 && "Cannot access under byte size!"); + continue; + } + + // Otherwise, add an access component. + + // First, compute the bits inside this access which are part of the + // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the + // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits + // in the target that we are reading. + assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!"); + assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!"); + uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset); + uint64_t AccessBitsInFieldSize = + std::min(AccessWidth + AccessStart, + FieldOffset + FieldSize) - AccessBitsInFieldStart; + + assert(NumComponents < 3 && "Unexpected number of components!"); + CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++]; + AI.FieldIndex = 0; + // FIXME: We still follow the old access pattern of only using the field + // byte offset. We should switch this once we fix the struct layout to be + // pretty. + AI.FieldByteOffset = AccessStart / 8; + AI.FieldBitStart = AccessBitsInFieldStart - AccessStart; + AI.AccessWidth = AccessWidth; + AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8; + AI.TargetBitOffset = AccessedTargetBits; + AI.TargetBitWidth = AccessBitsInFieldSize; + + AccessStart += AccessWidth; + AccessedTargetBits += AI.TargetBitWidth; + } + + assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!"); + return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned); +} + void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, uint64_t FieldOffset) { uint64_t FieldSize = @@ -175,14 +275,9 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, assert(NumBytesToAppend && "No bytes to append!"); } - const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); - uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8; - - bool IsSigned = D->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - D, CGBitFieldInfo(FieldOffset / TypeSizeInBits, - FieldOffset % TypeSizeInBits, - FieldSize, IsSigned))); + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize))); AppendBytes(NumBytesToAppend); @@ -254,6 +349,35 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, return true; } +const llvm::Type * +CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout) { + if (Field->isBitField()) { + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + // Ignore zero sized bit fields. + if (FieldSize == 0) + return 0; + + const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext()); + unsigned NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize, 8) / 8; + + if (NumBytesToAppend > 1) + FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend); + + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize))); + return FieldTy; + } + + // This is a regular union field. + LLVMFields.push_back(LLVMFieldInfo(Field, 0)); + return Types.ConvertTypeForMemRecursive(Field->getType()); +} + void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!"); @@ -270,28 +394,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { assert(Layout.getFieldOffset(FieldNo) == 0 && "Union field offset did not start at the beginning of record!"); + const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout); - if (Field->isBitField()) { - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); - - // Ignore zero sized bit fields. - if (FieldSize == 0) - continue; - - // Add the bit field info. - bool IsSigned = Field->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - *Field, CGBitFieldInfo(0, 0, FieldSize, - IsSigned))); - } else { - LLVMFields.push_back(LLVMFieldInfo(*Field, 0)); - } + if (!FieldTy) + continue; HasOnlyZeroSizedBitFields = false; - const llvm::Type *FieldTy = - Types.ConvertTypeForMemRecursive(Field->getType()); unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy); @@ -334,7 +443,7 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, llvm::Type::getInt8PtrTy(Types.getLLVMContext()); assert(NextFieldOffsetInBytes == 0 && - "Vtable pointer must come first!"); + "VTable pointer must come first!"); AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); } } @@ -388,7 +497,7 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(FieldTy)); - uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy); + uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy); FieldTypes.push_back(FieldTy); @@ -396,12 +505,6 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, BitsAvailableInLastField = 0; } -void -CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, - const llvm::Type *FieldTy) { - AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy)); -} - void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment) { assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && @@ -439,10 +542,6 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { return Types.getTargetData().getABITypeAlignment(Ty); } -uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { - return Types.getTargetData().getTypeAllocSize(Ty); -} - void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { // This record already contains a member pointer. if (ContainsPointerToDataMember) @@ -481,9 +580,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(), Builder.FieldTypes, Builder.Packed); - assert(getContext().getASTRecordLayout(D).getSize() / 8 == - getTargetData().getTypeAllocSize(Ty) && - "Type size mismatch!"); CGRecordLayout *RL = new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); @@ -496,5 +592,121 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) RL->BitFields.insert(Builder.LLVMBitFields[i]); + // Dump the layout, if requested. + if (getContext().getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping IRgen Record Layout\n"; + llvm::errs() << "Record: "; + D->dump(); + llvm::errs() << "\nLayout: "; + RL->dump(); + } + +#ifndef NDEBUG + // Verify that the computed LLVM struct size matches the AST layout size. + uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize(); + assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && + "Type size mismatch!"); + + // Verify that the LLVM and AST field offsets agree. + const llvm::StructType *ST = + dyn_cast(RL->getLLVMType()); + const llvm::StructLayout *SL = getTargetData().getStructLayout(ST); + + const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); + RecordDecl::field_iterator it = D->field_begin(); + for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { + const FieldDecl *FD = *it; + + // For non-bit-fields, just check that the LLVM struct offset matches the + // AST offset. + if (!FD->isBitField()) { + unsigned FieldNo = RL->getLLVMFieldNo(FD); + assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && + "Invalid field offset!"); + continue; + } + + // Ignore unnamed bit-fields. + if (!FD->getDeclName()) + continue; + + const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); + + // Verify that every component access is within the structure. + uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex); + uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8; + assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits && + "Invalid bit-field access (out of range)!"); + } + } +#endif + return RL; } + +void CGRecordLayout::print(llvm::raw_ostream &OS) const { + OS << " > BFIs; + for (llvm::DenseMap::const_iterator + it = BitFields.begin(), ie = BitFields.end(); + it != ie; ++it) { + const RecordDecl *RD = it->first->getParent(); + unsigned Index = 0; + for (RecordDecl::field_iterator + it2 = RD->field_begin(); *it2 != it->first; ++it2) + ++Index; + BFIs.push_back(std::make_pair(Index, &it->second)); + } + llvm::array_pod_sort(BFIs.begin(), BFIs.end()); + for (unsigned i = 0, e = BFIs.size(); i != e; ++i) { + OS.indent(4); + BFIs[i].second->print(OS); + OS << "\n"; + } + + OS << "]>\n"; +} + +void CGRecordLayout::dump() const { + print(llvm::errs()); +} + +void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { + OS << "\n"; + } + OS.indent(4); + } + OS << "]>"; +} + +void CGBitFieldInfo::dump() const { + print(llvm::errs()); +} diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index ae2f791..a914c80d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -160,7 +160,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EmitStmt(*I); if (DI) { - DI->setLocation(S.getLBracLoc()); + DI->setLocation(S.getRBracLoc()); DI->EmitRegionEnd(CurFn, Builder); } @@ -205,6 +205,8 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { } void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + // Fall out of the current block (if necessary). EmitBranch(BB); @@ -225,7 +227,12 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { } } - CurFn->getBasicBlockList().push_back(BB); + // Place the block after the current block, if possible, or else at + // the end of the function. + if (CurBB && CurBB->getParent()) + CurFn->getBasicBlockList().insertAfter(CurBB, BB); + else + CurFn->getBasicBlockList().push_back(BB); Builder.SetInsertPoint(BB); } @@ -974,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { unsigned InputNo; for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) { TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo]; - if (Input.hasTiedOperand() && - Input.getTiedOperand() == i) + if (Input.hasTiedOperand() && Input.getTiedOperand() == i) break; } assert(InputNo != S.getNumInputs() && "Didn't find matching input!"); QualType InputTy = S.getInputExpr(InputNo)->getType(); - QualType OutputTy = OutExpr->getType(); + QualType OutputType = OutExpr->getType(); uint64_t InputSize = getContext().getTypeSize(InputTy); - if (getContext().getTypeSize(OutputTy) < InputSize) { - // Form the asm to return the value as a larger integer type. - ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize); + if (getContext().getTypeSize(OutputType) < InputSize) { + // Form the asm to return the value as a larger integer or fp type. + ResultRegTypes.back() = ConvertType(InputTy); } } } else { @@ -1036,17 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // that is usually cheaper, but LLVM IR should really get an anyext someday. if (Info.hasTiedOperand()) { unsigned Output = Info.getTiedOperand(); - QualType OutputTy = S.getOutputExpr(Output)->getType(); + QualType OutputType = S.getOutputExpr(Output)->getType(); QualType InputTy = InputExpr->getType(); - if (getContext().getTypeSize(OutputTy) > + if (getContext().getTypeSize(OutputType) > getContext().getTypeSize(InputTy)) { // Use ptrtoint as appropriate so that we can do our extension. if (isa(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, - llvm::IntegerType::get(VMContext, LLVMPointerWidth)); - unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy); - Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize)); + llvm::IntegerType::get(VMContext, LLVMPointerWidth)); + const llvm::Type *OutputTy = ConvertType(OutputType); + if (isa(OutputTy)) + Arg = Builder.CreateZExt(Arg, OutputTy); + else + Arg = Builder.CreateFPExt(Arg, OutputTy); } } @@ -1102,6 +1111,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end()); Result->addAttribute(~0, llvm::Attribute::NoUnwind); + // Slap the source location of the inline asm into a !srcloc metadata on the + // call. + unsigned LocID = S.getAsmString()->getLocStart().getRawEncoding(); + llvm::Value *LocIDC = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LocID); + Result->setMetadata("srcloc", llvm::MDNode::get(VMContext, &LocIDC, 1)); // Extract all of the register value results from the asm. std::vector RegResults; @@ -1121,14 +1136,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { const llvm::Type *TruncTy = ResultTruncRegTypes[i]; - // Truncate the integer result to the right size, note that - // ResultTruncRegTypes can be a pointer. - uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); - Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize)); - - if (Tmp->getType() != TruncTy) { - assert(isa(TruncTy)); + + // Truncate the integer result to the right size, note that TruncTy can be + // a pointer. + if (TruncTy->isFloatingPointTy()) + Tmp = Builder.CreateFPTrunc(Tmp, TruncTy); + else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) { + uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); + Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)ResSize)); Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); + } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) { + uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType()); + Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)TmpSize)); + Tmp = Builder.CreateTrunc(Tmp, TruncTy); + } else if (TruncTy->isIntegerTy()) { + Tmp = Builder.CreateTrunc(Tmp, TruncTy); } } diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index 6d38ab9..a8f0467 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, "Pushed the same temporary twice; AST is likely wrong"); llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - llvm::Value *CondPtr = 0; + llvm::AllocaInst *CondPtr = 0; // Check if temporaries need to be conditional. If so, we'll create a // condition boolean, initialize it to 0 and @@ -32,10 +32,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, // Initialize it to false. This initialization takes place right after // the alloca insert point. - llvm::StoreInst *SI = - new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr); - llvm::BasicBlock *Block = AllocaInsertPt->getParent(); - Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); + InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); // Now set it to true. Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); @@ -64,7 +61,8 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, + Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. @@ -107,7 +105,7 @@ void CodeGenFunction::PopCXXTemporary() { } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 91d9f76..15e5648 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -43,7 +43,7 @@ class VTTBuilder { /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived /// class. - llvm::DenseMap SubVTTIndicies; + llvm::DenseMap SubVTTIndicies; /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of /// all subobjects of the most derived class. @@ -116,8 +116,7 @@ public: } /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. - const llvm::DenseMap & - getSubVTTIndicies() const { + const llvm::DenseMap &getSubVTTIndicies() const { return SubVTTIndicies; } @@ -179,13 +178,14 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, // The vtable is a construction vtable, look in the construction vtable // address points. AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); } else { // Just get the address point for the regular vtable. AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + assert(AddressPoint != 0 && "Did not find vtable address point!"); } if (!AddressPoint) AddressPoint = 0; - assert(AddressPoint != 0 && "Did not find an address point!"); llvm::Value *Idxs[] = { llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), @@ -340,7 +340,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { if (!IsPrimaryVTT) { // Remember the sub-VTT index. - SubVTTIndicies[RD] = VTTComponents.size(); + SubVTTIndicies[Base] = VTTComponents.size(); } AddressPointsMapTy AddressPoints; @@ -434,25 +434,25 @@ bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { } uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { - ClassPairTy ClassPair(RD, Base); + BaseSubobject Base) { + BaseSubobjectPairTy ClassSubobjectPair(RD, Base); - SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair); + SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair); if (I != SubVTTIndicies.end()) return I->second; VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); - for (llvm::DenseMap::const_iterator I = + for (llvm::DenseMap::const_iterator I = Builder.getSubVTTIndicies().begin(), E = Builder.getSubVTTIndicies().end(); I != E; ++I) { // Insert all indices. - ClassPairTy ClassPair(RD, I->first); + BaseSubobjectPairTy ClassSubobjectPair(RD, I->first); - SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second)); } - I = SubVTTIndicies.find(ClassPair); + I = SubVTTIndicies.find(ClassSubobjectPair); assert(I != SubVTTIndicies.end() && "Did not find index!"); return I->second; diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp new file mode 100644 index 0000000..159753a --- /dev/null +++ b/lib/CodeGen/CGVTables.cpp @@ -0,0 +1,3167 @@ +//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "CodeGenFunction.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include +#include + +using namespace clang; +using namespace CodeGen; + +namespace { + +/// BaseOffset - Represents an offset from a derived class to a direct or +/// indirect base class. +struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// (Or the offset from the virtual base class to the base class, if the + /// path from the derived class to the base class involves a virtual base + /// class. + int64_t NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } +}; + +/// FinalOverriders - Contains the final overrider member functions for all +/// member functions in the base subobjects of a class. +class FinalOverriders { +public: + /// OverriderInfo - Information about a final overrider. + struct OverriderInfo { + /// Method - The method decl of the overrider. + const CXXMethodDecl *Method; + + /// Offset - the base offset of the overrider in the layout class. + uint64_t Offset; + + OverriderInfo() : Method(0), Offset(0) { } + }; + +private: + /// MostDerivedClass - The most derived class for which the final overriders + /// are stored. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building final overriders for a + /// construction vtable, this holds the offset from the layout class to the + /// most derived class. + const uint64_t MostDerivedClassOffset; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if the final overriders are for a + /// construction vtable. + const CXXRecordDecl *LayoutClass; + + ASTContext &Context; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + /// BaseSubobjectMethodPairTy - Uniquely identifies a member function + /// in a base subobject. + typedef std::pair + BaseSubobjectMethodPairTy; + + typedef llvm::DenseMap OverridersMapTy; + + /// OverridersMap - The final overriders for all virtual member functions of + /// all the base subobjects of the most derived class. + OverridersMapTy OverridersMap; + + /// VisitedVirtualBases - A set of all the visited virtual bases, used to + /// avoid visiting virtual bases more than once. + llvm::SmallPtrSet VisitedVirtualBases; + + typedef llvm::DenseMap + AdjustmentOffsetsMapTy; + + /// ReturnAdjustments - Holds return adjustments for all the overriders that + /// need to perform return value adjustments. + AdjustmentOffsetsMapTy ReturnAdjustments; + + // FIXME: We might be able to get away with making this a SmallSet. + typedef llvm::SmallSetVector OffsetSetVectorTy; + + /// SubobjectOffsetsMapTy - This map is used for keeping track of all the + /// base subobject offsets that a single class declaration might refer to. + /// + /// For example, in: + /// + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// when we determine that C::f() overrides A::f(), we need to update the + /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map + /// will have the subobject offsets for both A copies. + typedef llvm::DenseMap + SubobjectOffsetsMapTy; + + /// ComputeFinalOverriders - Compute the final overriders for a given base + /// subobject (and all its direct and indirect bases). + void ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets); + + /// AddOverriders - Add the final overriders for this base subobject to the + /// map of final overriders. + void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets); + + /// PropagateOverrider - Propagate the NewMD overrider to all the functions + /// that OldMD overrides. For example, if we have: + /// + /// struct A { virtual void f(); }; + /// struct B : A { virtual void f(); }; + /// struct C : B { virtual void f(); }; + /// + /// and we want to override B::f with C::f, we also need to override A::f with + /// C::f. + void PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + uint64_t OverriderOffsetInLayoutClass, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets); + + static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets); + +public: + FinalOverriders(const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass); + + /// getOverrider - Get the final overrider for the given method declaration in + /// the given base subobject. + OverriderInfo getOverrider(BaseSubobject Base, + const CXXMethodDecl *MD) const { + assert(OverridersMap.count(std::make_pair(Base, MD)) && + "Did not find overrider!"); + + return OverridersMap.lookup(std::make_pair(Base, MD)); + } + + /// getReturnAdjustmentOffset - Get the return adjustment offset for the + /// method decl in the given base subobject. Returns an empty base offset if + /// no adjustment is needed. + BaseOffset getReturnAdjustmentOffset(BaseSubobject Base, + const CXXMethodDecl *MD) const { + return ReturnAdjustments.lookup(std::make_pair(Base, MD)); + } + + /// dump - dump the final overriders. + void dump() { + assert(VisitedVirtualBases.empty() && + "Visited virtual bases aren't empty!"); + dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); + VisitedVirtualBases.clear(); + } + + /// dump - dump the final overriders for a base subobject, and all its direct + /// and indirect base subobjects. + void dump(llvm::raw_ostream &Out, BaseSubobject Base); +}; + +#define DUMP_OVERRIDERS 0 + +FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, + const CXXRecordDecl *LayoutClass) + : MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), + MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { + + // Compute the final overriders. + SubobjectOffsetsMapTy Offsets; + ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), + /*BaseSubobjectIsVisitedVBase=*/false, + MostDerivedClassOffset, Offsets); + VisitedVirtualBases.clear(); + +#if DUMP_OVERRIDERS + // And dump them (for now). + dump(); + + // Also dump the base offsets (for now). + for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(), + E = Offsets.end(); I != E; ++I) { + const OffsetSetVectorTy& OffsetSetVector = I->second; + + llvm::errs() << "Base offsets for "; + llvm::errs() << I->first->getQualifiedNameAsString() << '\n'; + + for (unsigned I = 0, E = OffsetSetVector.size(); I != E; ++I) + llvm::errs() << " " << I << " - " << OffsetSetVector[I] / 8 << '\n'; + } +#endif +} + +void FinalOverriders::AddOverriders(BaseSubobject Base, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // First, propagate the overrider. + PropagateOverrider(MD, Base, OffsetInLayoutClass, MD, Offsets); + + // Add the overrider as the final overrider of itself. + OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; + assert(!Overrider.Method && "Overrider should not exist yet!"); + + Overrider.Offset = OffsetInLayoutClass; + Overrider.Method = MD; + } +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { + int64_t NonVirtualOffset = 0; + + unsigned NonVirtualStart = 0; + const CXXRecordDecl *VirtualBase = 0; + + // First, look for the virtual base class. + for (unsigned I = 0, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + if (Element.Base->isVirtual()) { + // FIXME: Can we break when we find the first virtual base? + // (If we can't, can't we just iterate over the path in reverse order?) + NonVirtualStart = I + 1; + QualType VBaseType = Element.Base->getType(); + VirtualBase = + cast(VBaseType->getAs()->getDecl()); + } + } + + // Now compute the non-virtual offset. + for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { + const CXXBasePathElement &Element = Path[I]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs(); + const CXXRecordDecl *Base = cast(BaseType->getDecl()); + + NonVirtualOffset += Layout.getBaseClassOffset(Base); + } + + // FIXME: This should probably use CharUnits or something. Maybe we should + // even change the base offsets in ASTRecordLayout to be specified in + // CharUnits. + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); + +} + +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + + if (!const_cast(DerivedRD)-> + isDerivedFrom(const_cast(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return BaseOffset(); + } + + return ComputeBaseOffset(Context, DerivedRD, Paths.front()); +} + +static BaseOffset +ComputeReturnAdjustmentBaseOffset(ASTContext &Context, + const CXXMethodDecl *DerivedMD, + const CXXMethodDecl *BaseMD) { + const FunctionType *BaseFT = BaseMD->getType()->getAs(); + const FunctionType *DerivedFT = DerivedMD->getType()->getAs(); + + // Canonicalize the return types. + CanQualType CanDerivedReturnType = + Context.getCanonicalType(DerivedFT->getResultType()); + CanQualType CanBaseReturnType = + Context.getCanonicalType(BaseFT->getResultType()); + + assert(CanDerivedReturnType->getTypeClass() == + CanBaseReturnType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedReturnType == CanBaseReturnType) { + // No adjustment needed. + return BaseOffset(); + } + + if (isa(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs()->getPointeeType(); + } else if (isa(CanDerivedReturnType)) { + CanDerivedReturnType = + CanDerivedReturnType->getAs()->getPointeeType(); + CanBaseReturnType = + CanBaseReturnType->getAs()->getPointeeType(); + } else { + assert(false && "Unexpected return type!"); + } + + // We need to compare unqualified types here; consider + // const T *Base::foo(); + // T *Derived::foo(); + if (CanDerivedReturnType.getUnqualifiedType() == + CanBaseReturnType.getUnqualifiedType()) { + // No adjustment needed. + return BaseOffset(); + } + + const CXXRecordDecl *DerivedRD = + cast(cast(CanDerivedReturnType)->getDecl()); + + const CXXRecordDecl *BaseRD = + cast(cast(CanBaseReturnType)->getDecl()); + + return ComputeBaseOffset(Context, BaseRD, DerivedRD); +} + +void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, + BaseSubobject NewBase, + uint64_t OverriderOffsetInLayoutClass, + const CXXMethodDecl *NewMD, + SubobjectOffsetsMapTy &Offsets) { + for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(), + E = OldMD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + + // We want to override OverriddenMD in all subobjects, for example: + // + /// struct A { virtual void f(); }; + /// struct B1 : A { }; + /// struct B2 : A { }; + /// struct C : B1, B2 { virtual void f(); }; + /// + /// When overriding A::f with C::f we need to do so in both A subobjects. + const OffsetSetVectorTy &OffsetVector = Offsets[OverriddenRD]; + + // Go through all the subobjects. + for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { + uint64_t Offset = OffsetVector[I]; + + BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset); + BaseSubobjectMethodPairTy SubobjectAndMethod = + std::make_pair(OverriddenSubobject, OverriddenMD); + + OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod]; + + assert(Overrider.Method && "Did not find existing overrider!"); + + // Check if we need return adjustments or base adjustments. + // (We don't want to do this for pure virtual member functions). + if (!NewMD->isPure()) { + // Get the return adjustment base offset. + BaseOffset ReturnBaseOffset = + ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD); + + if (!ReturnBaseOffset.isEmpty()) { + // Store the return adjustment base offset. + ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; + } + } + + // Set the new overrider. + Overrider.Offset = OverriderOffsetInLayoutClass; + Overrider.Method = NewMD; + + // And propagate it further. + PropagateOverrider(OverriddenMD, NewBase, OverriderOffsetInLayoutClass, + NewMD, Offsets); + } + } +} + +void +FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, + SubobjectOffsetsMapTy &Offsets) { + // Iterate over the new offsets. + for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), + E = NewOffsets.end(); I != E; ++I) { + const CXXRecordDecl *NewRD = I->first; + const OffsetSetVectorTy& NewOffsetVector = I->second; + + OffsetSetVectorTy &OffsetVector = Offsets[NewRD]; + + // Merge the new offsets set vector into the old. + OffsetVector.insert(NewOffsetVector.begin(), NewOffsetVector.end()); + } +} + +void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, + uint64_t OffsetInLayoutClass, + SubobjectOffsetsMapTy &Offsets) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + SubobjectOffsetsMapTy NewOffsets; + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; + uint64_t BaseOffset; + uint64_t BaseOffsetInLayoutClass; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) + IsVisitedVirtualBase = true; + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); + BaseOffsetInLayoutClass = Layout.getBaseClassOffset(BaseDecl) + + OffsetInLayoutClass; + } + + // Compute the final overriders for this base. + // We always want to compute the final overriders, even if the base is a + // visited virtual base. Consider: + // + // struct A { + // virtual void f(); + // virtual void g(); + // }; + // + // struct B : virtual A { + // void f(); + // }; + // + // struct C : virtual A { + // void g (); + // }; + // + // struct D : B, C { }; + // + // Here, we still want to compute the overriders for A as a base of C, + // because otherwise we'll miss that C::g overrides A::f. + ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), + IsVisitedVirtualBase, BaseOffsetInLayoutClass, + NewOffsets); + } + + /// Now add the overriders for this particular subobject. + /// (We don't want to do this more than once for a virtual base). + if (!BaseSubobjectIsVisitedVBase) + AddOverriders(Base, OffsetInLayoutClass, NewOffsets); + + // And merge the newly discovered subobject offsets. + MergeSubobjectOffsets(NewOffsets, Offsets); + + /// Finally, add the offset for our own subobject. + Offsets[RD].insert(Base.getBaseOffset()); +} + +void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have any virtual member functions. + if (!BaseDecl->isPolymorphic()) + continue; + + uint64_t BaseOffset; + if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) { + // We've visited this base before. + continue; + } + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + + Base.getBaseOffset(); + } + + dump(Out, BaseSubobject(BaseDecl, BaseOffset)); + } + + Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; + Out << Base.getBaseOffset() / 8 << ")\n"; + + // Now dump the overriders for this base subobject. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + OverriderInfo Overrider = getOverrider(Base, MD); + + Out << " " << MD->getQualifiedNameAsString() << " - ("; + Out << Overrider.Method->getQualifiedNameAsString(); + Out << ", " << ", " << Overrider.Offset / 8 << ')'; + + AdjustmentOffsetsMapTy::const_iterator AI = + ReturnAdjustments.find(std::make_pair(Base, MD)); + if (AI != ReturnAdjustments.end()) { + const BaseOffset &Offset = AI->second; + + Out << " [ret-adj: "; + if (Offset.VirtualBase) + Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; + + Out << Offset.NonVirtualOffset << " nv]"; + } + + Out << "\n"; + } +} + +/// VTableComponent - Represents a single component in a vtable. +class VTableComponent { +public: + enum Kind { + CK_VCallOffset, + CK_VBaseOffset, + CK_OffsetToTop, + CK_RTTI, + CK_FunctionPointer, + + /// CK_CompleteDtorPointer - A pointer to the complete destructor. + CK_CompleteDtorPointer, + + /// CK_DeletingDtorPointer - A pointer to the deleting destructor. + CK_DeletingDtorPointer, + + /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer + /// will end up never being called. Such vtable function pointers are + /// represented as a CK_UnusedFunctionPointer. + CK_UnusedFunctionPointer + }; + + static VTableComponent MakeVCallOffset(int64_t Offset) { + return VTableComponent(CK_VCallOffset, Offset); + } + + static VTableComponent MakeVBaseOffset(int64_t Offset) { + return VTableComponent(CK_VBaseOffset, Offset); + } + + static VTableComponent MakeOffsetToTop(int64_t Offset) { + return VTableComponent(CK_OffsetToTop, Offset); + } + + static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VTableComponent(CK_RTTI, reinterpret_cast(RD)); + } + + static VTableComponent MakeFunction(const CXXMethodDecl *MD) { + assert(!isa(MD) && + "Don't use MakeFunction with destructors!"); + + return VTableComponent(CK_FunctionPointer, + reinterpret_cast(MD)); + } + + static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_CompleteDtorPointer, + reinterpret_cast(DD)); + } + + static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_DeletingDtorPointer, + reinterpret_cast(DD)); + } + + static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + assert(!isa(MD) && + "Don't use MakeUnusedFunction with destructors!"); + return VTableComponent(CK_UnusedFunctionPointer, + reinterpret_cast(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); + } + + int64_t getVCallOffset() const { + assert(getKind() == CK_VCallOffset && "Invalid component kind!"); + + return getOffset(); + } + + int64_t getVBaseOffset() const { + assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); + + return getOffset(); + } + + int64_t getOffsetToTop() const { + assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); + + return getOffset(); + } + + const CXXRecordDecl *getRTTIDecl() const { + assert(getKind() == CK_RTTI && "Invalid component kind!"); + + return reinterpret_cast(getPointer()); + } + + const CXXMethodDecl *getFunctionDecl() const { + assert(getKind() == CK_FunctionPointer); + + return reinterpret_cast(getPointer()); + } + + const CXXDestructorDecl *getDestructorDecl() const { + assert((getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); + + return reinterpret_cast(getPointer()); + } + + const CXXMethodDecl *getUnusedFunctionDecl() const { + assert(getKind() == CK_UnusedFunctionPointer); + + return reinterpret_cast(getPointer()); + } + +private: + VTableComponent(Kind ComponentKind, int64_t Offset) { + assert((ComponentKind == CK_VCallOffset || + ComponentKind == CK_VBaseOffset || + ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); + assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); + + Value = ((Offset << 3) | ComponentKind); + } + + VTableComponent(Kind ComponentKind, uintptr_t Ptr) { + assert((ComponentKind == CK_RTTI || + ComponentKind == CK_FunctionPointer || + ComponentKind == CK_CompleteDtorPointer || + ComponentKind == CK_DeletingDtorPointer || + ComponentKind == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); + + Value = Ptr | ComponentKind; + } + + int64_t getOffset() const { + assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || + getKind() == CK_OffsetToTop) && "Invalid component kind!"); + + return Value >> 3; + } + + uintptr_t getPointer() const { + assert((getKind() == CK_RTTI || + getKind() == CK_FunctionPointer || + getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer || + getKind() == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + return static_cast(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. + /// (The reason that we're not simply using a PointerIntPair here is that we + /// need the offsets to be 64-bit, even when on a 32-bit machine). + int64_t Value; +}; + +/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. +struct VCallOffsetMap { + + typedef std::pair MethodAndOffsetPairTy; + + /// Offsets - Keeps track of methods and their offsets. + // FIXME: This should be a real map and not a vector. + llvm::SmallVector Offsets; + + /// MethodsCanShareVCallOffset - Returns whether two virtual member functions + /// can share the same vcall offset. + static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS); + +public: + /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the + /// add was successful, or false if there was already a member function with + /// the same signature in the map. + bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); + + /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the + /// vtable address point) for the given virtual member function. + int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); + + // empty - Return whether the offset map is empty or not. + bool empty() const { return Offsets.empty(); } +}; + +static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + ASTContext &C = LHS->getASTContext(); // TODO: thread this down + CanQual + LT = C.getCanonicalType(LHS->getType()).getAs(), + RT = C.getCanonicalType(RHS->getType()).getAs(); + + // Fast-path matches in the canonical types. + if (LT == RT) return true; + + // Force the signatures to match. We can't rely on the overrides + // list here because there isn't necessarily an inheritance + // relationship between the two methods. + if (LT.getQualifiers() != RT.getQualifiers() || + LT->getNumArgs() != RT->getNumArgs()) + return false; + for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) + if (LT->getArgType(I) != RT->getArgType(I)) + return false; + return true; +} + +bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + assert(LHS->isVirtual() && "LHS must be virtual!"); + assert(RHS->isVirtual() && "LHS must be virtual!"); + + // A destructor can share a vcall offset with another destructor. + if (isa(LHS)) + return isa(RHS); + + // FIXME: We need to check more things here. + + // The methods must have the same name. + DeclarationName LHSName = LHS->getDeclName(); + DeclarationName RHSName = RHS->getDeclName(); + if (LHSName != RHSName) + return false; + + // And the same signatures. + return HasSameVirtualSignature(LHS, RHS); +} + +bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, + int64_t OffsetOffset) { + // Check if we can reuse an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return false; + } + + // Add the offset. + Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); + return true; +} + +int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { + // Look for an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return Offsets[I].second; + } + + assert(false && "Should always find a vcall offset offset!"); + return 0; +} + +/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. +class VCallAndVBaseOffsetBuilder { +public: + typedef llvm::DenseMap + VBaseOffsetOffsetsMapTy; + +private: + /// MostDerivedClass - The most derived class for which we're building vcall + /// and vbase offsets. + const CXXRecordDecl *MostDerivedClass; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// Components - vcall and vbase offset components + typedef llvm::SmallVector VTableComponentVectorTy; + VTableComponentVectorTy Components; + + /// VisitedVirtualBases - Visited virtual bases. + llvm::SmallPtrSet VisitedVirtualBases; + + /// VCallOffsets - Keeps track of vcall offsets. + VCallOffsetMap VCallOffsets; + + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, + /// relative to the address point. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// FinalOverriders - The final overriders of the most derived class. + /// (Can be null when we're not building a vtable of the most derived class). + const FinalOverriders *Overriders; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given base subobject. + void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset); + + /// AddVCallOffsets - Add vcall offsets for the given base subobject. + void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); + + /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in + /// bytes, relative to the vtable address point. + int64_t getCurrentOffsetOffset() const; + +public: + VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *LayoutClass, + const FinalOverriders *Overriders, + BaseSubobject Base, bool BaseIsVirtual, + uint64_t OffsetInLayoutClass) + : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { + + // Add vcall and vbase offsets. + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); + } + + /// Methods for iterating over the components. + typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; + const_iterator components_begin() const { return Components.rbegin(); } + const_iterator components_end() const { return Components.rend(); } + + const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } +}; + +void +VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t RealBaseOffset) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); + } + + AddVBaseOffsets(Base.getBase(), RealBaseOffset); + + // We only want to add vcall offsets for virtual bases. + if (BaseIsVirtual) + AddVCallOffsets(Base, RealBaseOffset); +} + +int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { + // OffsetIndex is the index of this vcall or vbase offset, relative to the + // vtable address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + return OffsetOffset; +} + +void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, + uint64_t VBaseOffset) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Handle the primary base first. + // We only want to add vcall offsets if the base is non-virtual; a virtual + // primary base will have its vcall and vbase offsets emitted already. + if (PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) { + // Get the base offset of the primary base. + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), + VBaseOffset); + } + + // Add the vcall offsets. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + int64_t OffsetOffset = getCurrentOffsetOffset(); + + // Don't add a vcall offset if we already have one for this member function + // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; + + int64_t Offset = 0; + + if (Overriders) { + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders->getOverrider(Base, MD); + + /// The vcall offset is the offset from the virtual base to the object + /// where the function was overridden. + // FIXME: We should not use / 8 here. + Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; + } + + Components.push_back(VTableComponent::MakeVCallOffset(Offset)); + } + + // And iterate over all non-virtual bases (ignoring the primary base). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + if (BaseDecl == PrimaryBase) + continue; + + // Get the base offset of this base. + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); + } +} + +void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass) { + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Add vbase offsets. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + // FIXME: We shouldn't use / 8 here. + int64_t Offset = + (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - + OffsetInLayoutClass) / 8; + + // Add the vbase offset offset. + assert(!VBaseOffsetOffsets.count(BaseDecl) && + "vbase offset offset already exists!"); + + int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); + VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); + + Components.push_back(VTableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); + } +} + +/// VTableBuilder - Class for building vtable layout information. +class VTableBuilder { +public: + /// PrimaryBasesSetVectorTy - A set vector of direct and indirect + /// primary bases. + typedef llvm::SmallSetVector + PrimaryBasesSetVectorTy; + + typedef llvm::DenseMap + VBaseOffsetOffsetsMapTy; + + typedef llvm::DenseMap + AddressPointsMapTy; + +private: + /// VTables - Global vtable information. + CodeGenVTables &VTables; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + /// MostDerivedClassOffset - If we're building a construction vtable, this + /// holds the offset from the layout class to the most derived class. + const uint64_t MostDerivedClassOffset; + + /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual + /// base. (This only makes sense when building a construction vtable). + bool MostDerivedClassIsVirtual; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// FinalOverriders - The final overriders of the most derived class. + const FinalOverriders Overriders; + + /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual + /// bases in this vtable. + llvm::DenseMap VCallOffsetsForVBases; + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for + /// the most derived class. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + + /// Components - The components of the vtable being built. + llvm::SmallVector Components; + + /// AddressPoints - Address points for the vtable being built. + AddressPointsMapTy AddressPoints; + + /// MethodInfo - Contains information about a method in a vtable. + /// (Used for computing 'this' pointer adjustment thunks. + struct MethodInfo { + /// BaseOffset - The base offset of this method. + const uint64_t BaseOffset; + + /// BaseOffsetInLayoutClass - The base offset in the layout class of this + /// method. + const uint64_t BaseOffsetInLayoutClass; + + /// VTableIndex - The index in the vtable that this method has. + /// (For destructors, this is the index of the complete destructor). + const uint64_t VTableIndex; + + MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, + uint64_t VTableIndex) + : BaseOffset(BaseOffset), + BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), + VTableIndex(VTableIndex) { } + + MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { } + }; + + typedef llvm::DenseMap MethodInfoMapTy; + + /// MethodInfoMap - The information for all methods in the vtable we're + /// currently building. + MethodInfoMapTy MethodInfoMap; + + typedef llvm::DenseMap VTableThunksMapTy; + + /// VTableThunks - The thunks by vtable index in the vtable currently being + /// built. + VTableThunksMapTy VTableThunks; + + typedef llvm::SmallVector ThunkInfoVectorTy; + typedef llvm::DenseMap ThunksMapTy; + + /// 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, const ThunkInfo &Thunk); + + /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the + /// part of the vtable we're currently building. + void ComputeThisAdjustments(); + + typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; + + /// PrimaryVirtualBases - All known virtual bases who are a primary base of + /// some other base. + VisitedVirtualBasesSetTy PrimaryVirtualBases; + + /// ComputeReturnAdjustment - Compute the return adjustment given a return + /// adjustment base offset. + ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); + + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const; + + /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the + /// given virtual member function, its offset in the layout class and its + /// final overrider. + ThisAdjustment + ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider); + + /// AddMethod - Add a single virtual member function to the vtable + /// components vector. + void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); + + /// IsOverriderUsed - Returns whether the overrider will ever be used in this + /// part of the vtable. + /// + /// Itanium C++ ABI 2.5.2: + /// + /// struct A { virtual void f(); }; + /// struct B : virtual public A { int i; }; + /// struct C : virtual public A { int j; }; + /// struct D : public B, public C {}; + /// + /// When B and C are declared, A is a primary base in each case, so although + /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this + /// adjustment is required and no thunk is generated. However, inside D + /// objects, A is no longer a primary base of C, so if we allowed calls to + /// C::f() to use the copy of A's vtable in the C subobject, we would need + /// to adjust this from C* to B::A*, which would require a third-party + /// thunk. Since we require that a call to C::f() first convert to A*, + /// C-in-D's copy of A's vtable is never referenced, so this is not + /// necessary. + bool IsOverriderUsed(const CXXMethodDecl *Overrider, + uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass) const; + + + /// AddMethods - Add the methods of this base subobject and all its + /// primary bases to the vtable components vector. + void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases); + + // LayoutVTable - Layout the vtable for the given base class, including its + // secondary vtables and any vtables for virtual bases. + void LayoutVTable(); + + /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the + /// given base subobject, as well as all its secondary vtables. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual + /// in the layout class. + void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + uint64_t OffsetInLayoutClass); + + /// LayoutSecondaryVTables - Layout the secondary vtables for the given base + /// subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, + uint64_t OffsetInLayoutClass); + + /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this + /// class hierarchy. + void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the + /// given base (excluding any primary bases). + void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// isBuildingConstructionVTable - Return whether this vtable builder is + /// building a construction vtable. + bool isBuildingConstructorVTable() const { + return MostDerivedClass != LayoutClass; + } + +public: + VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass) + : VTables(VTables), MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), + MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), + LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), + Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + + 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(Components.begin()); + } + + const uint64_t *vtable_components_data_end() const { + return reinterpret_cast(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, const ThunkInfo &Thunk) { + assert(!isBuildingConstructorVTable() && + "Can't add thunks for construction vtable"); + + llvm::SmallVector &ThunksVector = Thunks[MD]; + + // Check if we have this thunk already. + if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != + ThunksVector.end()) + return; + + ThunksVector.push_back(Thunk); +} + +typedef llvm::SmallPtrSet OverriddenMethodsSetTy; + +/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all +/// the overridden methods that the function decl overrides. +static void +ComputeAllOverriddenMethods(const CXXMethodDecl *MD, + OverriddenMethodsSetTy& OverriddenMethods) { + assert(MD->isVirtual() && "Method is not virtual!"); + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + OverriddenMethods.insert(OverriddenMD); + + ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); + } +} + +void VTableBuilder::ComputeThisAdjustments() { + // Now go through the method info map and see if any of the methods need + // 'this' pointer adjustments. + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MethodInfo = I->second; + + // Ignore adjustments for unused function pointers. + uint64_t VTableIndex = MethodInfo.VTableIndex; + if (Components[VTableIndex].getKind() == + VTableComponent::CK_UnusedFunctionPointer) + continue; + + // Get the final overrider for this method. + FinalOverriders::OverriderInfo Overrider = + 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); + + if (ThisAdjustment.isEmpty()) + continue; + + // Add it. + VTableThunks[VTableIndex].This = ThisAdjustment; + + if (isa(MD)) { + // Add an adjustment for the deleting destructor as well. + VTableThunks[VTableIndex + 1].This = ThisAdjustment; + } + } + + /// 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); + } +} + +ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { + ReturnAdjustment Adjustment; + + if (!Offset.isEmpty()) { + if (Offset.VirtualBase) { + // Get the virtual base offset offset. + if (Offset.DerivedClass == MostDerivedClass) { + // We can get the offset offset directly from our map. + Adjustment.VBaseOffsetOffset = + VBaseOffsetOffsets.lookup(Offset.VirtualBase); + } else { + Adjustment.VBaseOffsetOffset = + VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, + Offset.VirtualBase); + } + } + + Adjustment.NonVirtual = Offset.NonVirtualOffset; + } + + return Adjustment; +} + +BaseOffset +VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const { + const CXXRecordDecl *BaseRD = Base.getBase(); + const CXXRecordDecl *DerivedRD = Derived.getBase(); + + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + + if (!const_cast(DerivedRD)-> + isDerivedFrom(const_cast(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return BaseOffset(); + } + + // We have to go through all the paths, and see which one leads us to the + // right base subobject. + for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); + + // FIXME: Should not use * 8 here. + uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; + + if (Offset.VirtualBase) { + // If we have a virtual base class, the non-virtual offset is relative + // to the virtual base class offset. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + /// Get the virtual base offset, relative to the most derived class + /// layout. + OffsetToBaseSubobject += + LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); + } else { + // Otherwise, the non-virtual offset is relative to the derived class + // offset. + OffsetToBaseSubobject += Derived.getBaseOffset(); + } + + // Check if this path gives us the right base subobject. + if (OffsetToBaseSubobject == Base.getBaseOffset()) { + // Since we're going from the base class _to_ the derived class, we'll + // invert the non-virtual offset here. + Offset.NonVirtualOffset = -Offset.NonVirtualOffset; + return Offset; + } + } + + return BaseOffset(); +} + +ThisAdjustment +VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) { + // Ignore adjustments for pure virtual member functions. + if (Overrider.Method->isPure()) + return ThisAdjustment(); + + BaseSubobject OverriddenBaseSubobject(MD->getParent(), + BaseOffsetInLayoutClass); + + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.Offset); + + // Compute the adjustment offset. + BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, + OverriderBaseSubobject); + if (Offset.isEmpty()) + return ThisAdjustment(); + + ThisAdjustment Adjustment; + + if (Offset.VirtualBase) { + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, + /*FinalOverriders=*/0, + BaseSubobject(Offset.VirtualBase, 0), + /*BaseIsVirtual=*/true, + /*OffsetInLayoutClass=*/0); + + VCallOffsets = Builder.getVCallOffsets(); + } + + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); + } + + // Set the non-virtual part of the adjustment. + Adjustment.NonVirtual = Offset.NonVirtualOffset; + + return Adjustment; +} + +void +VTableBuilder::AddMethod(const CXXMethodDecl *MD, + ReturnAdjustment ReturnAdjustment) { + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + assert(ReturnAdjustment.isEmpty() && + "Destructor can't have return adjustment!"); + + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + } else { + // Add the return adjustment if necessary. + if (!ReturnAdjustment.isEmpty()) + VTableThunks[Components.size()].Return = ReturnAdjustment; + + // Add the function. + Components.push_back(VTableComponent::MakeFunction(MD)); + } +} + +/// OverridesIndirectMethodInBase - Return whether the given member function +/// overrides any methods in the set of given bases. +/// Unlike OverridesMethodInBase, this checks "overriders of overriders". +/// For example, if we have: +/// +/// struct A { virtual void f(); } +/// struct B : A { virtual void f(); } +/// struct C : B { virtual void f(); } +/// +/// OverridesIndirectMethodInBase will return true if given C::f as the method +/// and { A } as the set of bases. +static bool +OverridesIndirectMethodInBases(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + if (Bases.count(MD->getParent())) + return true; + + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // Check "indirect overriders". + if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) + return true; + } + + return false; +} + +bool +VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, + uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass) const { + // If the base and the first base in the primary base chain have the same + // offsets, then this overrider will be used. + if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) + return true; + + // We know now that Base (or a direct or indirect base of it) is a primary + // base in part of the class hierarchy, but not a primary base in the most + // derived class. + + // If the overrider is the first base in the primary base chain, we know + // that the overrider will be used. + if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) + return true; + + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + + const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; + PrimaryBases.insert(RD); + + // Now traverse the base chain, starting with the first base, until we find + // the base that is no longer a primary base. + while (true) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Now check if this is the primary base that is not a primary base in the + // most derived class. + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + FirstBaseOffsetInLayoutClass) { + // We found it, stop walking the chain. + break; + } + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + } + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + + RD = PrimaryBase; + } + + // If the final overrider is an override of one of the primary bases, + // then we know that it will be used. + return OverridesIndirectMethodInBases(Overrider, PrimaryBases); +} + +/// FindNearestOverriddenMethod - Given a method, returns the overridden method +/// from the nearest base. Returns null if no method was found. +static const CXXMethodDecl * +FindNearestOverriddenMethod(const CXXMethodDecl *MD, + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + OverriddenMethodsSetTy OverriddenMethods; + ComputeAllOverriddenMethods(MD, OverriddenMethods); + + for (int I = Bases.size(), E = 0; I != E; --I) { + const CXXRecordDecl *PrimaryBase = Bases[I - 1]; + + // Now check the overriden methods. + for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), + E = OverriddenMethods.end(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // We found our overridden method. + if (OverriddenMD->getParent() == PrimaryBase) + return OverriddenMD; + } + } + + return 0; +} + +void +VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + uint64_t FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + uint64_t PrimaryBaseOffset; + uint64_t PrimaryBaseOffsetInLayoutClass; + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; + } + + AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass, PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + } + + // Now go through all virtual member functions and add them. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(Base, MD); + + // Check if this virtual member function overrides a method in a primary + // base. If this is the case, and the return type doesn't require adjustment + // then we can just use the member function from the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + if (ComputeReturnAdjustmentBaseOffset(Context, MD, + OverriddenMD).isEmpty()) { + // Replace the method info of the overridden method with our own + // method. + assert(MethodInfoMap.count(OverriddenMD) && + "Did not find the overridden method!"); + MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; + + MethodInfo MethodInfo(Base.getBaseOffset(), + BaseOffsetInLayoutClass, + OverriddenMethodInfo.VTableIndex); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + + 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; + } + } + + // Insert the method info for this method. + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, + Components.size()); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + + // Check if this overrider is going to be used. + const CXXMethodDecl *OverriderMD = Overrider.Method; + if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, + FirstBaseInPrimaryBaseChain, + FirstBaseOffsetInLayoutClass)) { + Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); + continue; + } + + // Check if this overrider needs a return adjustment. + BaseOffset ReturnAdjustmentOffset = + Overriders.getReturnAdjustmentOffset(Base, MD); + + ReturnAdjustment ReturnAdjustment = + ComputeReturnAdjustment(ReturnAdjustmentOffset); + + AddMethod(Overrider.Method, ReturnAdjustment); + } +} + +void VTableBuilder::LayoutVTable() { + LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0), + /*BaseIsMorallyVirtual=*/false, + MostDerivedClassIsVirtual, + MostDerivedClassOffset); + + VisitedVirtualBasesSetTy VBases; + + // Determine the primary virtual bases. + DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, + VBases); + VBases.clear(); + + LayoutVTablesForVirtualBases(MostDerivedClass, VBases); +} + +void +VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, + uint64_t OffsetInLayoutClass) { + assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); + + // Add vcall and vbase offsets for this vtable. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, + Base, BaseIsVirtualInLayoutClass, + OffsetInLayoutClass); + Components.append(Builder.components_begin(), Builder.components_end()); + + // Check if we need to add these vcall offsets. + if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; + + if (VCallOffsets.empty()) + VCallOffsets = Builder.getVCallOffsets(); + } + + // If we're laying out the most derived class we want to keep track of the + // virtual base class offset offsets. + if (Base.getBase() == MostDerivedClass) + VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); + + // Add the offset to top. + // FIXME: We should not use / 8 here. + int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - + MostDerivedClassOffset) / 8; + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); + + uint64_t AddressPoint = Components.size(); + + // Now go through all virtual member functions and add them. + PrimaryBasesSetVectorTy PrimaryBases; + AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass, + PrimaryBases); + + // Compute 'this' pointer adjustments. + ComputeThisAdjustments(); + + // 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(); + + 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; + } + + // Layout secondary vtables. + LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); +} + +void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + uint64_t OffsetInLayoutClass) { + // Itanium C++ ABI 2.5.2: + // Following the primary virtual table of a derived class are secondary + // virtual tables for each of its proper base classes, except any primary + // base(s) with which it shares its primary virtual table. + + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + // Ignore virtual bases, we'll emit them later. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Ignore bases that don't have a vtable. + if (!BaseDecl->isDynamicClass()) + continue; + + if (isBuildingConstructorVTable()) { + // Itanium C++ ABI 2.6.4: + // Some of the base class subobjects may not need construction virtual + // tables, which will therefore not be present in the construction + // virtual table group, even though the subobject virtual tables are + // present in the main virtual table group for the complete object. + if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) + continue; + } + + // Get the base offset of this base. + uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); + uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; + + uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; + + // Don't emit a secondary vtable for a primary base. We might however want + // to emit secondary vtables for other bases of this base. + if (BaseDecl == PrimaryBase) { + LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, BaseOffsetInLayoutClass); + continue; + } + + // Layout the primary vtable (and any secondary vtables) for this base. + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, + /*BaseIsVirtualInLayoutClass=*/false, + BaseOffsetInLayoutClass); + } +} + +void +VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Check if this base has a primary base. + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + + // Check if it's virtual. + if (Layout.getPrimaryBaseWasVirtual()) { + bool IsPrimaryVirtualBase = true; + + if (isBuildingConstructorVTable()) { + // Check if the base is actually a primary base in the class we use for + // layout. + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + uint64_t PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); + + // We know that the base is not a primary base in the layout class if + // the base offsets are different. + if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) + IsPrimaryVirtualBase = false; + } + + if (IsPrimaryVirtualBase) + PrimaryVirtualBases.insert(PrimaryBase); + } + } + + // Traverse bases, looking for more primary virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + uint64_t BaseOffsetInLayoutClass; + + if (I->isVirtual()) { + if (!VBases.insert(BaseDecl)) + continue; + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + BaseOffsetInLayoutClass = LayoutClassLayout.getVBaseClassOffset(BaseDecl); + } else { + BaseOffsetInLayoutClass = + OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); + } + + DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); + } +} + +void +VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + // Itanium C++ ABI 2.5.2: + // Then come the virtual base virtual tables, also in inheritance graph + // order, and again excluding primary bases (which share virtual tables with + // the classes for which they are primary). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Check if this base needs a vtable. (If it's virtual, not a primary base + // of some other class, and we haven't visited it before). + if (I->isVirtual() && BaseDecl->isDynamicClass() && + !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + uint64_t BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + uint64_t BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsMorallyVirtual=*/true, + /*BaseIsVirtualInLayoutClass=*/true, + BaseOffsetInLayoutClass); + } + + // We only need to check the base for virtual base vtables if it actually + // has virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVTablesForVirtualBases(BaseDecl, VBases); + } +} + +/// dumpLayout - Dump the vtable layout. +void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { + + if (isBuildingConstructorVTable()) { + Out << "Construction vtable for ('"; + Out << MostDerivedClass->getQualifiedNameAsString() << "', "; + // FIXME: Don't use / 8 . + Out << MostDerivedClassOffset / 8 << ") in '"; + Out << LayoutClass->getQualifiedNameAsString(); + } else { + Out << "Vtable for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + } + Out << "' (" << Components.size() << " entries).\n"; + + // Iterate through the address points and insert them into a new map where + // they are keyed by the index and not the base object. + // Since an address point can be shared by multiple subobjects, we use an + // STL multimap. + std::multimap AddressPointsByIndex; + for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), + E = AddressPoints.end(); I != E; ++I) { + const BaseSubobject& Base = I->first; + uint64_t Index = I->second; + + AddressPointsByIndex.insert(std::make_pair(Index, Base)); + } + + for (unsigned I = 0, E = Components.size(); I != E; ++I) { + uint64_t Index = I; + + Out << llvm::format("%4d | ", I); + + const VTableComponent &Component = Components[I]; + + // Dump the component. + switch (Component.getKind()) { + + case VTableComponent::CK_VCallOffset: + Out << "vcall_offset (" << Component.getVCallOffset() << ")"; + break; + + case VTableComponent::CK_VBaseOffset: + Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; + break; + + case VTableComponent::CK_OffsetToTop: + Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; + break; + + case VTableComponent::CK_RTTI: + Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; + break; + + case VTableComponent::CK_FunctionPointer: { + const CXXMethodDecl *MD = Component.getFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << Str; + if (MD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this function pointer has a return adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "\n [return adjustment: "; + Out << Thunk.Return.NonVirtual << " non-virtual"; + + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } + + Out << ']'; + } + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { + bool IsComplete = + Component.getKind() == VTableComponent::CK_CompleteDtorPointer; + + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString(); + if (IsComplete) + Out << "() [complete]"; + else + Out << "() [deleting]"; + + if (DD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this destructor has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } + + break; + } + + case VTableComponent::CK_UnusedFunctionPointer: { + const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); + + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << "[unused] " << Str; + if (MD->isPure()) + Out << " [pure]"; + } + + } + + Out << '\n'; + + // Dump the next address point. + uint64_t NextIndex = Index + 1; + if (AddressPointsByIndex.count(NextIndex)) { + if (AddressPointsByIndex.count(NextIndex) == 1) { + const BaseSubobject &Base = + AddressPointsByIndex.find(NextIndex)->second; + + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); + Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; + } else { + uint64_t BaseOffset = + AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); + + // We store the class names in a set to get a stable order. + std::set ClassNames; + for (std::multimap::const_iterator I = + AddressPointsByIndex.lower_bound(NextIndex), E = + AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { + assert(I->second.getBaseOffset() == BaseOffset && + "Invalid base offset!"); + const CXXRecordDecl *RD = I->second.getBase(); + ClassNames.insert(RD->getQualifiedNameAsString()); + } + + for (std::set::const_iterator I = ClassNames.begin(), + E = ClassNames.end(); I != E; ++I) { + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << *I; + Out << ", " << BaseOffset / 8 << ") vtable address --\n"; + } + } + } + } + + Out << '\n'; + + if (isBuildingConstructorVTable()) + return; + + if (MostDerivedClass->getNumVBases()) { + // We store the virtual base class names and their offsets in a map to get + // a stable order. + + std::map ClassNamesAndOffsets; + for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), + E = VBaseOffsetOffsets.end(); I != E; ++I) { + std::string ClassName = I->first->getQualifiedNameAsString(); + int64_t OffsetOffset = I->second; + ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); + } + + Out << "Virtual base offset offsets for '"; + Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; + Out << ClassNamesAndOffsets.size(); + Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; + + for (std::map::const_iterator I = + ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); + I != E; ++I) + Out << " " << I->first << " | " << I->second << '\n'; + + Out << "\n"; + } + + if (!Thunks.empty()) { + // We store the method names in a map to get a stable order. + std::map MethodNamesAndDecls; + + 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, + MD); + + MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); + } + + for (std::map::const_iterator I = + MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); + I != E; ++I) { + const std::string &MethodName = I->first; + const CXXMethodDecl *MD = I->second; + + ThunkInfoVectorTy ThunksVector = Thunks[MD]; + std::sort(ThunksVector.begin(), ThunksVector.end()); + + Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); + Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; + + for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { + const ThunkInfo &Thunk = ThunksVector[I]; + + 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 adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + } + + Out << '\n'; + } + + Out << '\n'; + + } + } +} + +} + +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 + // order of declaration of the corresponding member functions in the class. + // + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. + + int64_t CurrentIndex = 0; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (PrimaryBase) { + assert(PrimaryBase->isDefinition() && + "Should have the definition decl of the primary base!"); + + // Since the record decl shares its vtable pointer with the primary base + // we need to start counting at the end of the primary base's vtable. + CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); + } + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + for (ASTRecordLayout::primary_base_info_iterator + I = Layout.primary_base_begin(), E = Layout.primary_base_end(); + I != E; ++I) + PrimaryBases.insert((*I).getBase()); + + const CXXDestructorDecl *ImplicitVirtualDtor = 0; + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + const CXXMethodDecl *MD = *i; + + // We only want virtual methods. + if (!MD->isVirtual()) + continue; + + // Check if this method overrides a method in the primary base. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, PrimaryBases)) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, + OverriddenMD).isEmpty()) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + const CXXDestructorDecl *OverriddenDD = + cast(OverriddenMD); + + // Add both the complete and deleting entries. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + } else { + MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); + } + + // We don't need to add an entry for this method. + continue; + } + } + + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + if (MD->isImplicit()) { + assert(!ImplicitVirtualDtor && + "Did already see an implicit virtual dtor!"); + ImplicitVirtualDtor = DD; + continue; + } + + // Add the complete dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + + // Add the deleting dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + } else { + // Add the entry. + MethodVTableIndices[MD] = CurrentIndex++; + } + } + + if (ImplicitVirtualDtor) { + // Itanium C++ ABI 2.5.2: + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. + + // Add the complete dtor. + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = + CurrentIndex++; + + // Add the deleting dtor. + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = + CurrentIndex++; + } + + NumVirtualFunctionPointers[RD] = CurrentIndex; +} + +uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { + llvm::DenseMap::iterator I = + NumVirtualFunctionPointers.find(RD); + if (I != NumVirtualFunctionPointers.end()) + return I->second; + + ComputeMethodVTableIndices(RD); + + I = NumVirtualFunctionPointers.find(RD); + assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); + return I->second; +} + +uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) { + MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); + if (I != MethodVTableIndices.end()) + return I->second; + + const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); + + ComputeMethodVTableIndices(RD); + + I = MethodVTableIndices.find(GD); + assert(I != MethodVTableIndices.end() && "Did not find index!"); + return I->second; +} + +int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { + ClassPairTy ClassPair(RD, VBase); + + VirtualBaseClassOffsetOffsetsMapTy::iterator I = + VirtualBaseClassOffsetOffsets.find(ClassPair); + if (I != VirtualBaseClassOffsetOffsets.end()) + return I->second; + + VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, + BaseSubobject(RD, 0), + /*BaseIsVirtual=*/false, + /*OffsetInLayoutClass=*/0); + + for (VCallAndVBaseOffsetBuilder::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)); + } + + I = VirtualBaseClassOffsetOffsets.find(ClassPair); + assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); + + return I->second; +} + +uint64_t +CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { + assert(AddressPoints.count(std::make_pair(RD, Base)) && + "Did not find address point!"); + + uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); + assert(AddressPoint && "Address point must not be zero!"); + + return AddressPoint; +} + +llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkInfo &Thunk) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute the mangled name. + llvm::SmallString<256> Name; + if (const CXXDestructorDecl* DD = dyn_cast(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); + + // 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(GD.getDecl()); + const FunctionProtoType *FPT = MD->getType()->getAs(); + QualType ResultType = FPT->getResultType(); + QualType ThisType = MD->getThisType(getContext()); + + 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()); + + // 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)); + + // 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)); + } + + // Get our callee. + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); + + 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(); + + 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()); + + // Set the right linkage. + Fn->setLinkage(CGM.getFunctionLinkage(MD)); + + // Set the right visibility. + CGM.setGlobalVisibility(Fn, MD); +} + +void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) +{ + llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Strip off a bitcast if we got one back. + if (llvm::ConstantExpr *CE = dyn_cast(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(Entry)->getType()->getElementType() != + CGM.getTypes().GetFunctionTypeForVTable(MD)) { + llvm::GlobalValue *OldThunkFn = cast(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(Entry); + CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); +} + +void CodeGenVTables::EmitThunks(GlobalDecl GD) +{ + const CXXMethodDecl *MD = + cast(GD.getDecl())->getCanonicalDecl(); + + // We don't need to generate thunks for the base destructor. + if (isa(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]; + + // Check if we've computed this information before. + if (LayoutData) + return; + + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + + // Add the VTable layout. + uint64_t NumVTableComponents = Builder.getNumVTableComponents(); + LayoutData = new uint64_t[NumVTableComponents + 1]; + + // 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(); + const CXXRecordDecl *VBase = cast(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 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(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(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 *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVTable(RD, OutName); + llvm::StringRef Name = OutName.str(); + + ComputeVTableRelatedInformation(RD); + + 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()); + } + + 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); +} + +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); + + // If this is the magic class __cxxabiv1::__fundamental_type_info, + // we will emit the typeinfo for the fundamental types. This is the + // same behaviour as GCC. + const DeclContext *DC = RD->getDeclContext(); + if (RD->getIdentifier() && + RD->getIdentifier()->isStr("__fundamental_type_info") && + isa(DC) && + cast(DC)->getIdentifier() && + cast(DC)->getIdentifier()->isStr("__cxxabiv1") && + DC->getParent()->isTranslationUnit()) + CGM.EmitFundamentalRTTIDescriptors(); +} + +void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const CXXRecordDecl *RD = MD->getParent(); + + // If the class doesn't have a vtable we don't need to emit one. + 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 we have no key funcion and this is a explicit instantiation declaration, + // we will produce a vtable at the explicit instantiation. We don't need one + // here. + if (RDKind == clang::TSK_ExplicitInstantiationDeclaration) + return; + + // 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 && + MDKind == TSK_ExplicitInstantiationDefinition) + return; + } + + if (VTables.count(RD)) + return; + + if (RDKind == TSK_ImplicitInstantiation) + CGM.DeferredVTables.push_back(RD); + else + GenerateClassData(CGM.getVTableLinkage(RD), RD); +} diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h new file mode 100644 index 0000000..6c18ca8 --- /dev/null +++ b/lib/CodeGen/CGVTables.h @@ -0,0 +1,368 @@ +//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of virtual tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGVTABLE_H +#define CLANG_CODEGEN_CGVTABLE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/GlobalVariable.h" +#include "GlobalDecl.h" + +namespace clang { + class CXXRecordDecl; + +namespace CodeGen { + class CodeGenModule; + +/// 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; } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; + } + + 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; + + /// 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; + } +}; + +/// 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) { } + + 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 +// the base class. +class BaseSubobject { + /// Base - The base class declaration. + const CXXRecordDecl *Base; + + /// BaseOffset - The offset from the most derived class to the base class. + uint64_t BaseOffset; + +public: + BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) + : Base(Base), BaseOffset(BaseOffset) { } + + /// getBase - Returns the base class declaration. + const CXXRecordDecl *getBase() const { return Base; } + + /// getBaseOffset - Returns the base class offset. + uint64_t getBaseOffset() const { return BaseOffset; } + + friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { + return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; + } +}; + +} // end namespace CodeGen +} // end namespace clang + +namespace llvm { + +template<> struct DenseMapInfo { + static clang::CodeGen::BaseSubobject getEmptyKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey()); + } + + static clang::CodeGen::BaseSubobject getTombstoneKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { + return + DenseMapInfo::getHashValue(Base.getBase()) ^ + DenseMapInfo::getHashValue(Base.getBaseOffset()); + } + + static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, + const clang::CodeGen::BaseSubobject &RHS) { + return LHS == RHS; + } +}; + +// It's OK to treat BaseSubobject as a POD type. +template <> struct isPodLike { + static const bool value = true; +}; + +} + +namespace clang { +namespace CodeGen { + +class CodeGenVTables { + CodeGenModule &CGM; + + /// MethodVTableIndices - Contains the index (relative to the vtable address + /// point) where the function pointer for a virtual function is stored. + typedef llvm::DenseMap MethodVTableIndicesTy; + MethodVTableIndicesTy MethodVTableIndices; + + typedef std::pair ClassPairTy; + + /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to + /// the address point) in bytes where the offsets for virtual bases of a class + /// are stored. + typedef llvm::DenseMap + VirtualBaseClassOffsetOffsetsMapTy; + VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + + /// VTables - All the vtables which have been defined. + llvm::DenseMap VTables; + + /// NumVirtualFunctionPointers - Contains the number of virtual function + /// pointers in the vtable for a given record decl. + llvm::DenseMap NumVirtualFunctionPointers; + + typedef llvm::SmallVector ThunkInfoVectorTy; + typedef llvm::DenseMap ThunksMapTy; + + /// Thunks - Contains all thunks that a given method decl will need. + ThunksMapTy Thunks; + + typedef llvm::DenseMap 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 std::pair BaseSubobjectPairTy; + typedef llvm::DenseMap AddressPointsMapTy; + + /// Address points - Address points for all vtables. + AddressPointsMapTy AddressPoints; + + /// VTableAddressPointsMapTy - Address points for a single vtable. + typedef llvm::DenseMap VTableAddressPointsMapTy; + + typedef llvm::SmallVector, 1> + VTableThunksTy; + + typedef llvm::DenseMap + 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 SubVTTIndiciesMapTy; + + /// SubVTTIndicies - Contains indices into the various sub-VTTs. + SubVTTIndiciesMapTy SubVTTIndicies; + + typedef llvm::DenseMap + SecondaryVirtualPointerIndicesMapTy; + + /// 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 *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: + CodeGenVTables(CodeGenModule &CGM) + : CGM(CGM) { } + + // isKeyFunctionInAnotherTU - True if this record has a key function and it is + // in another translation unit. + static bool isKeyFunctionInAnotherTU(ASTContext &Context, + const CXXRecordDecl *RD) { + assert (RD->isDynamicClass() && "Non dynamic classes have no key."); + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + return KeyFunction && !KeyFunction->getBody(); + } + + /// needsVTTParameter - Return whether the given global decl needs a VTT + /// parameter, which it does if it's a base constructor or destructor with + /// virtual bases. + static bool needsVTTParameter(GlobalDecl GD); + + /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the + /// given record decl. + uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base); + + /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the + /// virtual pointer for the given subobject is located. + uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, + BaseSubobject Base); + + /// getMethodVTableIndex - Return the index (relative to the vtable address + /// point) where the function pointer for the given virtual function is + /// stored. + uint64_t getMethodVTableIndex(GlobalDecl GD); + + /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the + /// vtable address point) where the offset of the virtual base that contains + /// the given base is stored, otherwise, if no virtual base contains the given + /// class, return 0. Base must be a virtual base class or an unambigious + /// base. + int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); + + /// getAddressPoint - Get the address point of the given subobject in the + /// class decl. + uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); + + /// 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); + + /// 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); + + // 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 required to be generated + /// upon definition of a KeyFunction. This includes the vtable, the + /// rtti data structure and the VTT. + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); +}; + +} // end namespace CodeGen +} // end namespace clang +#endif diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 91fb714..92ef9dc 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -34,69 +34,64 @@ namespace CodeGen { /// simple LLVM SSA value, a pair of SSA values for complex numbers, or the /// address of an aggregate value in memory. class RValue { - llvm::Value *V1, *V2; - // TODO: Encode this into the low bit of pointer for more efficient - // return-by-value. - enum { Scalar, Complex, Aggregate } Flavor; + enum Flavor { Scalar, Complex, Aggregate }; - bool Volatile:1; -public: + // Stores first value and flavor. + llvm::PointerIntPair V1; + // Stores second value and volatility. + llvm::PointerIntPair V2; - bool isScalar() const { return Flavor == Scalar; } - bool isComplex() const { return Flavor == Complex; } - bool isAggregate() const { return Flavor == Aggregate; } +public: + bool isScalar() const { return V1.getInt() == Scalar; } + bool isComplex() const { return V1.getInt() == Complex; } + bool isAggregate() const { return V1.getInt() == Aggregate; } - bool isVolatileQualified() const { return Volatile; } + bool isVolatileQualified() const { return V2.getInt(); } /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); - return V1; + return V1.getPointer(); } /// getComplexVal - Return the real/imag components of this complex value. /// std::pair getComplexVal() const { - return std::pair(V1, V2); + return std::make_pair(V1.getPointer(), V2.getPointer()); } /// getAggregateAddr() - Return the Value* of the address of the aggregate. llvm::Value *getAggregateAddr() const { assert(isAggregate() && "Not an aggregate!"); - return V1; + return V1.getPointer(); } static RValue get(llvm::Value *V) { RValue ER; - ER.V1 = V; - ER.Flavor = Scalar; - ER.Volatile = false; + ER.V1.setPointer(V); + ER.V1.setInt(Scalar); + ER.V2.setInt(false); return ER; } static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { RValue ER; - ER.V1 = V1; - ER.V2 = V2; - ER.Flavor = Complex; - ER.Volatile = false; + ER.V1.setPointer(V1); + ER.V2.setPointer(V2); + ER.V1.setInt(Complex); + ER.V2.setInt(false); return ER; } static RValue getComplex(const std::pair &C) { - RValue ER; - ER.V1 = C.first; - ER.V2 = C.second; - ER.Flavor = Complex; - ER.Volatile = false; - return ER; + return getComplex(C.first, C.second); } // FIXME: Aggregate rvalues need to retain information about whether they are // volatile or not. Remove default to find all places that probably get this // wrong. - static RValue getAggregate(llvm::Value *V, bool Vol = false) { + static RValue getAggregate(llvm::Value *V, bool Volatile = false) { RValue ER; - ER.V1 = V; - ER.Flavor = Aggregate; - ER.Volatile = Vol; + ER.V1.setPointer(V); + ER.V1.setInt(Aggregate); + ER.V2.setInt(Volatile); return ER; } }; @@ -220,7 +215,7 @@ public: } // bitfield lvalue - llvm::Value *getBitFieldAddr() const { + llvm::Value *getBitFieldBaseAddr() const { assert(isBitField()); return V; } @@ -269,11 +264,17 @@ public: return R; } - static LValue MakeBitfield(llvm::Value *V, const CGBitFieldInfo &Info, + /// \brief Create a new object to represent a bit-field access. + /// + /// \param BaseValue - The base address of the structure containing the + /// bit-field. + /// \param Info - The information describing how to perform the bit-field + /// access. + static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info, unsigned CVR) { LValue R; R.LVType = BitField; - R.V = V; + R.V = BaseValue; R.BitFieldInfo = &Info; R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp deleted file mode 100644 index fc6d1a8..0000000 --- a/lib/CodeGen/CGVtable.cpp +++ /dev/null @@ -1,3170 +0,0 @@ -//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of virtual tables. -// -//===----------------------------------------------------------------------===// - -#include "CodeGenModule.h" -#include "CodeGenFunction.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/RecordLayout.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" -#include -#include - -using namespace clang; -using namespace CodeGen; - -namespace { - -/// BaseOffset - Represents an offset from a derived class to a direct or -/// indirect base class. -struct BaseOffset { - /// DerivedClass - The derived class. - const CXXRecordDecl *DerivedClass; - - /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. - const CXXRecordDecl *VirtualBase; - - /// NonVirtualOffset - The offset from the derived class to the base class. - /// (Or the offset from the virtual base class to the base class, if the - /// path from the derived class to the base class involves a virtual base - /// class. - int64_t NonVirtualOffset; - - BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } - BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) - : DerivedClass(DerivedClass), VirtualBase(VirtualBase), - NonVirtualOffset(NonVirtualOffset) { } - - bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } -}; - -/// FinalOverriders - Contains the final overrider member functions for all -/// member functions in the base subobjects of a class. -class FinalOverriders { -public: - /// OverriderInfo - Information about a final overrider. - struct OverriderInfo { - /// Method - The method decl of the overrider. - const CXXMethodDecl *Method; - - /// Offset - the base offset of the overrider in the layout class. - uint64_t Offset; - - OverriderInfo() : Method(0), Offset(0) { } - }; - -private: - /// MostDerivedClass - The most derived class for which the final overriders - /// are stored. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building final overriders for a - /// construction vtable, this holds the offset from the layout class to the - /// most derived class. - const uint64_t MostDerivedClassOffset; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if the final overriders are for a - /// construction vtable. - const CXXRecordDecl *LayoutClass; - - ASTContext &Context; - - /// MostDerivedClassLayout - the AST record layout of the most derived class. - const ASTRecordLayout &MostDerivedClassLayout; - - /// BaseSubobjectMethodPairTy - Uniquely identifies a member function - /// in a base subobject. - typedef std::pair - BaseSubobjectMethodPairTy; - - typedef llvm::DenseMap OverridersMapTy; - - /// OverridersMap - The final overriders for all virtual member functions of - /// all the base subobjects of the most derived class. - OverridersMapTy OverridersMap; - - /// VisitedVirtualBases - A set of all the visited virtual bases, used to - /// avoid visiting virtual bases more than once. - llvm::SmallPtrSet VisitedVirtualBases; - - typedef llvm::DenseMap - AdjustmentOffsetsMapTy; - - /// ReturnAdjustments - Holds return adjustments for all the overriders that - /// need to perform return value adjustments. - AdjustmentOffsetsMapTy ReturnAdjustments; - - // FIXME: We might be able to get away with making this a SmallSet. - typedef llvm::SmallSetVector OffsetSetVectorTy; - - /// SubobjectOffsetsMapTy - This map is used for keeping track of all the - /// base subobject offsets that a single class declaration might refer to. - /// - /// For example, in: - /// - /// struct A { virtual void f(); }; - /// struct B1 : A { }; - /// struct B2 : A { }; - /// struct C : B1, B2 { virtual void f(); }; - /// - /// when we determine that C::f() overrides A::f(), we need to update the - /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map - /// will have the subobject offsets for both A copies. - typedef llvm::DenseMap - SubobjectOffsetsMapTy; - - /// ComputeFinalOverriders - Compute the final overriders for a given base - /// subobject (and all its direct and indirect bases). - void ComputeFinalOverriders(BaseSubobject Base, - bool BaseSubobjectIsVisitedVBase, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets); - - /// AddOverriders - Add the final overriders for this base subobject to the - /// map of final overriders. - void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets); - - /// PropagateOverrider - Propagate the NewMD overrider to all the functions - /// that OldMD overrides. For example, if we have: - /// - /// struct A { virtual void f(); }; - /// struct B : A { virtual void f(); }; - /// struct C : B { virtual void f(); }; - /// - /// and we want to override B::f with C::f, we also need to override A::f with - /// C::f. - void PropagateOverrider(const CXXMethodDecl *OldMD, - BaseSubobject NewBase, - uint64_t OverriderOffsetInLayoutClass, - const CXXMethodDecl *NewMD, - SubobjectOffsetsMapTy &Offsets); - - static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, - SubobjectOffsetsMapTy &Offsets); - -public: - FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass); - - /// getOverrider - Get the final overrider for the given method declaration in - /// the given base subobject. - OverriderInfo getOverrider(BaseSubobject Base, - const CXXMethodDecl *MD) const { - assert(OverridersMap.count(std::make_pair(Base, MD)) && - "Did not find overrider!"); - - return OverridersMap.lookup(std::make_pair(Base, MD)); - } - - /// getReturnAdjustmentOffset - Get the return adjustment offset for the - /// method decl in the given base subobject. Returns an empty base offset if - /// no adjustment is needed. - BaseOffset getReturnAdjustmentOffset(BaseSubobject Base, - const CXXMethodDecl *MD) const { - return ReturnAdjustments.lookup(std::make_pair(Base, MD)); - } - - /// dump - dump the final overriders. - void dump() { - assert(VisitedVirtualBases.empty() && - "Visited virtual bases aren't empty!"); - dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0)); - VisitedVirtualBases.clear(); - } - - /// dump - dump the final overriders for a base subobject, and all its direct - /// and indirect base subobjects. - void dump(llvm::raw_ostream &Out, BaseSubobject Base); -}; - -#define DUMP_OVERRIDERS 0 - -FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, - const CXXRecordDecl *LayoutClass) - : MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), - MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) { - - // Compute the final overriders. - SubobjectOffsetsMapTy Offsets; - ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), - /*BaseSubobjectIsVisitedVBase=*/false, - MostDerivedClassOffset, Offsets); - VisitedVirtualBases.clear(); - -#if DUMP_OVERRIDERS - // And dump them (for now). - dump(); - - // Also dump the base offsets (for now). - for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(), - E = Offsets.end(); I != E; ++I) { - const OffsetSetVectorTy& OffsetSetVector = I->second; - - llvm::errs() << "Base offsets for "; - llvm::errs() << I->first->getQualifiedNameAsString() << '\n'; - - for (unsigned I = 0, E = OffsetSetVector.size(); I != E; ++I) - llvm::errs() << " " << I << " - " << OffsetSetVector[I] / 8 << '\n'; - } -#endif -} - -void FinalOverriders::AddOverriders(BaseSubobject Base, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets) { - const CXXRecordDecl *RD = Base.getBase(); - - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // First, propagate the overrider. - PropagateOverrider(MD, Base, OffsetInLayoutClass, MD, Offsets); - - // Add the overrider as the final overrider of itself. - OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; - assert(!Overrider.Method && "Overrider should not exist yet!"); - - Overrider.Offset = OffsetInLayoutClass; - Overrider.Method = MD; - } -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { - int64_t NonVirtualOffset = 0; - - unsigned NonVirtualStart = 0; - const CXXRecordDecl *VirtualBase = 0; - - // First, look for the virtual base class. - for (unsigned I = 0, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - if (Element.Base->isVirtual()) { - // FIXME: Can we break when we find the first virtual base? - // (If we can't, can't we just iterate over the path in reverse order?) - NonVirtualStart = I + 1; - QualType VBaseType = Element.Base->getType(); - VirtualBase = - cast(VBaseType->getAs()->getDecl()); - } - } - - // Now compute the non-virtual offset. - for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - - // Check the base class offset. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - - const RecordType *BaseType = Element.Base->getType()->getAs(); - const CXXRecordDecl *Base = cast(BaseType->getDecl()); - - NonVirtualOffset += Layout.getBaseClassOffset(Base); - } - - // FIXME: This should probably use CharUnits or something. Maybe we should - // even change the base offsets in ASTRecordLayout to be specified in - // CharUnits. - return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); - -} - -static BaseOffset ComputeBaseOffset(ASTContext &Context, - const CXXRecordDecl *BaseRD, - const CXXRecordDecl *DerivedRD) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - - if (!const_cast(DerivedRD)-> - isDerivedFrom(const_cast(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - return ComputeBaseOffset(Context, DerivedRD, Paths.front()); -} - -static BaseOffset -ComputeReturnAdjustmentBaseOffset(ASTContext &Context, - const CXXMethodDecl *DerivedMD, - const CXXMethodDecl *BaseMD) { - const FunctionType *BaseFT = BaseMD->getType()->getAs(); - const FunctionType *DerivedFT = DerivedMD->getType()->getAs(); - - // Canonicalize the return types. - CanQualType CanDerivedReturnType = - Context.getCanonicalType(DerivedFT->getResultType()); - CanQualType CanBaseReturnType = - Context.getCanonicalType(BaseFT->getResultType()); - - assert(CanDerivedReturnType->getTypeClass() == - CanBaseReturnType->getTypeClass() && - "Types must have same type class!"); - - if (CanDerivedReturnType == CanBaseReturnType) { - // No adjustment needed. - return BaseOffset(); - } - - if (isa(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs()->getPointeeType(); - } else if (isa(CanDerivedReturnType)) { - CanDerivedReturnType = - CanDerivedReturnType->getAs()->getPointeeType(); - CanBaseReturnType = - CanBaseReturnType->getAs()->getPointeeType(); - } else { - assert(false && "Unexpected return type!"); - } - - // We need to compare unqualified types here; consider - // const T *Base::foo(); - // T *Derived::foo(); - if (CanDerivedReturnType.getUnqualifiedType() == - CanBaseReturnType.getUnqualifiedType()) { - // No adjustment needed. - return BaseOffset(); - } - - const CXXRecordDecl *DerivedRD = - cast(cast(CanDerivedReturnType)->getDecl()); - - const CXXRecordDecl *BaseRD = - cast(cast(CanBaseReturnType)->getDecl()); - - return ComputeBaseOffset(Context, BaseRD, DerivedRD); -} - -void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, - BaseSubobject NewBase, - uint64_t OverriderOffsetInLayoutClass, - const CXXMethodDecl *NewMD, - SubobjectOffsetsMapTy &Offsets) { - for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(), - E = OldMD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - - // We want to override OverriddenMD in all subobjects, for example: - // - /// struct A { virtual void f(); }; - /// struct B1 : A { }; - /// struct B2 : A { }; - /// struct C : B1, B2 { virtual void f(); }; - /// - /// When overriding A::f with C::f we need to do so in both A subobjects. - const OffsetSetVectorTy &OffsetVector = Offsets[OverriddenRD]; - - // Go through all the subobjects. - for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { - uint64_t Offset = OffsetVector[I]; - - BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset); - BaseSubobjectMethodPairTy SubobjectAndMethod = - std::make_pair(OverriddenSubobject, OverriddenMD); - - OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod]; - - assert(Overrider.Method && "Did not find existing overrider!"); - - // Check if we need return adjustments or base adjustments. - // (We don't want to do this for pure virtual member functions). - if (!NewMD->isPure()) { - // Get the return adjustment base offset. - BaseOffset ReturnBaseOffset = - ComputeReturnAdjustmentBaseOffset(Context, NewMD, OverriddenMD); - - if (!ReturnBaseOffset.isEmpty()) { - // Store the return adjustment base offset. - ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; - } - } - - // Set the new overrider. - Overrider.Offset = OverriderOffsetInLayoutClass; - Overrider.Method = NewMD; - - // And propagate it further. - PropagateOverrider(OverriddenMD, NewBase, OverriderOffsetInLayoutClass, - NewMD, Offsets); - } - } -} - -void -FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, - SubobjectOffsetsMapTy &Offsets) { - // Iterate over the new offsets. - for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), - E = NewOffsets.end(); I != E; ++I) { - const CXXRecordDecl *NewRD = I->first; - const OffsetSetVectorTy& NewOffsetVector = I->second; - - OffsetSetVectorTy &OffsetVector = Offsets[NewRD]; - - // Merge the new offsets set vector into the old. - OffsetVector.insert(NewOffsetVector.begin(), NewOffsetVector.end()); - } -} - -void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, - bool BaseSubobjectIsVisitedVBase, - uint64_t OffsetInLayoutClass, - SubobjectOffsetsMapTy &Offsets) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - SubobjectOffsetsMapTy NewOffsets; - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have any virtual member functions. - if (!BaseDecl->isPolymorphic()) - continue; - - bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; - uint64_t BaseOffset; - uint64_t BaseOffsetInLayoutClass; - if (I->isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) - IsVisitedVirtualBase = true; - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); - BaseOffsetInLayoutClass = Layout.getBaseClassOffset(BaseDecl) + - OffsetInLayoutClass; - } - - // Compute the final overriders for this base. - // We always want to compute the final overriders, even if the base is a - // visited virtual base. Consider: - // - // struct A { - // virtual void f(); - // virtual void g(); - // }; - // - // struct B : virtual A { - // void f(); - // }; - // - // struct C : virtual A { - // void g (); - // }; - // - // struct D : B, C { }; - // - // Here, we still want to compute the overriders for A as a base of C, - // because otherwise we'll miss that C::g overrides A::f. - ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), - IsVisitedVirtualBase, BaseOffsetInLayoutClass, - NewOffsets); - } - - /// Now add the overriders for this particular subobject. - /// (We don't want to do this more than once for a virtual base). - if (!BaseSubobjectIsVisitedVBase) - AddOverriders(Base, OffsetInLayoutClass, NewOffsets); - - // And merge the newly discovered subobject offsets. - MergeSubobjectOffsets(NewOffsets, Offsets); - - /// Finally, add the offset for our own subobject. - Offsets[RD].insert(Base.getBaseOffset()); -} - -void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have any virtual member functions. - if (!BaseDecl->isPolymorphic()) - continue; - - uint64_t BaseOffset; - if (I->isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) { - // We've visited this base before. - continue; - } - - BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffset = Layout.getBaseClassOffset(BaseDecl) + - Base.getBaseOffset(); - } - - dump(Out, BaseSubobject(BaseDecl, BaseOffset)); - } - - Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; - Out << Base.getBaseOffset() / 8 << ")\n"; - - // Now dump the overriders for this base subobject. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - OverriderInfo Overrider = getOverrider(Base, MD); - - Out << " " << MD->getQualifiedNameAsString() << " - ("; - Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << ", " << Overrider.Offset / 8 << ')'; - - AdjustmentOffsetsMapTy::const_iterator AI = - ReturnAdjustments.find(std::make_pair(Base, MD)); - if (AI != ReturnAdjustments.end()) { - const BaseOffset &Offset = AI->second; - - Out << " [ret-adj: "; - if (Offset.VirtualBase) - Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - - Out << Offset.NonVirtualOffset << " nv]"; - } - - Out << "\n"; - } -} - -/// VtableComponent - Represents a single component in a vtable. -class VtableComponent { -public: - enum Kind { - CK_VCallOffset, - CK_VBaseOffset, - CK_OffsetToTop, - CK_RTTI, - CK_FunctionPointer, - - /// CK_CompleteDtorPointer - A pointer to the complete destructor. - CK_CompleteDtorPointer, - - /// CK_DeletingDtorPointer - A pointer to the deleting destructor. - CK_DeletingDtorPointer, - - /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer - /// will end up never being called. Such vtable function pointers are - /// represented as a CK_UnusedFunctionPointer. - CK_UnusedFunctionPointer - }; - - static VtableComponent MakeVCallOffset(int64_t Offset) { - return VtableComponent(CK_VCallOffset, Offset); - } - - static VtableComponent MakeVBaseOffset(int64_t Offset) { - return VtableComponent(CK_VBaseOffset, Offset); - } - - static VtableComponent MakeOffsetToTop(int64_t Offset) { - return VtableComponent(CK_OffsetToTop, Offset); - } - - static VtableComponent MakeRTTI(const CXXRecordDecl *RD) { - return VtableComponent(CK_RTTI, reinterpret_cast(RD)); - } - - static VtableComponent MakeFunction(const CXXMethodDecl *MD) { - assert(!isa(MD) && - "Don't use MakeFunction with destructors!"); - - return VtableComponent(CK_FunctionPointer, - reinterpret_cast(MD)); - } - - static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_CompleteDtorPointer, - reinterpret_cast(DD)); - } - - static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_DeletingDtorPointer, - reinterpret_cast(DD)); - } - - static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { - assert(!isa(MD) && - "Don't use MakeUnusedFunction with destructors!"); - return VtableComponent(CK_UnusedFunctionPointer, - reinterpret_cast(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); - } - - int64_t getVCallOffset() const { - assert(getKind() == CK_VCallOffset && "Invalid component kind!"); - - return getOffset(); - } - - int64_t getVBaseOffset() const { - assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); - - return getOffset(); - } - - int64_t getOffsetToTop() const { - assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); - - return getOffset(); - } - - const CXXRecordDecl *getRTTIDecl() const { - assert(getKind() == CK_RTTI && "Invalid component kind!"); - - return reinterpret_cast(getPointer()); - } - - const CXXMethodDecl *getFunctionDecl() const { - assert(getKind() == CK_FunctionPointer); - - return reinterpret_cast(getPointer()); - } - - const CXXDestructorDecl *getDestructorDecl() const { - assert((getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); - - return reinterpret_cast(getPointer()); - } - - const CXXMethodDecl *getUnusedFunctionDecl() const { - assert(getKind() == CK_UnusedFunctionPointer); - - return reinterpret_cast(getPointer()); - } - -private: - VtableComponent(Kind ComponentKind, int64_t Offset) { - assert((ComponentKind == CK_VCallOffset || - ComponentKind == CK_VBaseOffset || - ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); - assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); - - Value = ((Offset << 3) | ComponentKind); - } - - VtableComponent(Kind ComponentKind, uintptr_t Ptr) { - assert((ComponentKind == CK_RTTI || - ComponentKind == CK_FunctionPointer || - ComponentKind == CK_CompleteDtorPointer || - ComponentKind == CK_DeletingDtorPointer || - ComponentKind == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); - - Value = Ptr | ComponentKind; - } - - int64_t getOffset() const { - assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || - getKind() == CK_OffsetToTop) && "Invalid component kind!"); - - return Value >> 3; - } - - uintptr_t getPointer() const { - assert((getKind() == CK_RTTI || - getKind() == CK_FunctionPointer || - getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer || - getKind() == CK_UnusedFunctionPointer) && - "Invalid component kind!"); - - return static_cast(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. - /// (The reason that we're not simply using a PointerIntPair here is that we - /// need the offsets to be 64-bit, even when on a 32-bit machine). - int64_t Value; -}; - -/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. -struct VCallOffsetMap { - - typedef std::pair MethodAndOffsetPairTy; - - /// Offsets - Keeps track of methods and their offsets. - // FIXME: This should be a real map and not a vector. - llvm::SmallVector Offsets; - - /// MethodsCanShareVCallOffset - Returns whether two virtual member functions - /// can share the same vcall offset. - static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS); - -public: - /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the - /// add was successful, or false if there was already a member function with - /// the same signature in the map. - bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); - - /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the - /// vtable address point) for the given virtual member function. - int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); - - // empty - Return whether the offset map is empty or not. - bool empty() const { return Offsets.empty(); } -}; - -static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - ASTContext &C = LHS->getASTContext(); // TODO: thread this down - CanQual - LT = C.getCanonicalType(LHS->getType()).getAs(), - RT = C.getCanonicalType(RHS->getType()).getAs(); - - // Fast-path matches in the canonical types. - if (LT == RT) return true; - - // Force the signatures to match. We can't rely on the overrides - // list here because there isn't necessarily an inheritance - // relationship between the two methods. - if (LT.getQualifiers() != RT.getQualifiers() || - LT->getNumArgs() != RT->getNumArgs()) - return false; - for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) - if (LT->getArgType(I) != RT->getArgType(I)) - return false; - return true; -} - -bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, - const CXXMethodDecl *RHS) { - assert(LHS->isVirtual() && "LHS must be virtual!"); - assert(RHS->isVirtual() && "LHS must be virtual!"); - - // A destructor can share a vcall offset with another destructor. - if (isa(LHS)) - return isa(RHS); - - // FIXME: We need to check more things here. - - // The methods must have the same name. - DeclarationName LHSName = LHS->getDeclName(); - DeclarationName RHSName = RHS->getDeclName(); - if (LHSName != RHSName) - return false; - - // And the same signatures. - return HasSameVirtualSignature(LHS, RHS); -} - -bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, - int64_t OffsetOffset) { - // Check if we can reuse an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return false; - } - - // Add the offset. - Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); - return true; -} - -int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { - // Look for an offset. - for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { - if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) - return Offsets[I].second; - } - - assert(false && "Should always find a vcall offset offset!"); - return 0; -} - -/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. -class VCallAndVBaseOffsetBuilder { -public: - typedef llvm::DenseMap - VBaseOffsetOffsetsMapTy; - -private: - /// MostDerivedClass - The most derived class for which we're building vcall - /// and vbase offsets. - const CXXRecordDecl *MostDerivedClass; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// Components - vcall and vbase offset components - typedef llvm::SmallVector VtableComponentVectorTy; - VtableComponentVectorTy Components; - - /// VisitedVirtualBases - Visited virtual bases. - llvm::SmallPtrSet VisitedVirtualBases; - - /// VCallOffsets - Keeps track of vcall offsets. - VCallOffsetMap VCallOffsets; - - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, - /// relative to the address point. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// FinalOverriders - The final overriders of the most derived class. - /// (Can be null when we're not building a vtable of the most derived class). - const FinalOverriders *Overriders; - - /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the - /// given base subobject. - void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - uint64_t RealBaseOffset); - - /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); - - /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); - - /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in - /// bytes, relative to the vtable address point. - int64_t getCurrentOffsetOffset() const; - -public: - VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, - const CXXRecordDecl *LayoutClass, - const FinalOverriders *Overriders, - BaseSubobject Base, bool BaseIsVirtual, - uint64_t OffsetInLayoutClass) - : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), - Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { - - // Add vcall and vbase offsets. - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); - } - - /// Methods for iterating over the components. - typedef VtableComponentVectorTy::const_reverse_iterator const_iterator; - const_iterator components_begin() const { return Components.rbegin(); } - const_iterator components_end() const { return Components.rend(); } - - const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } - const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { - return VBaseOffsetOffsets; - } -}; - -void -VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t RealBaseOffset) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); - - // Itanium C++ ABI 2.5.2: - // ..in classes sharing a virtual table with a primary base class, the vcall - // and vbase offsets added by the derived class all come before the vcall - // and vbase offsets required by the base class, so that the latter may be - // laid out as required by the base class without regard to additions from - // the derived class(es). - - // (Since we're emitting the vcall and vbase offsets in reverse order, we'll - // emit them for the primary base first). - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); - - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (PrimaryBaseIsVirtual) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseIsVirtual, RealBaseOffset); - } - - AddVBaseOffsets(Base.getBase(), RealBaseOffset); - - // We only want to add vcall offsets for virtual bases. - if (BaseIsVirtual) - AddVCallOffsets(Base, RealBaseOffset); -} - -int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { - // OffsetIndex is the index of this vcall or vbase offset, relative to the - // vtable address point. (We subtract 3 to account for the information just - // above the address point, the RTTI info, the offset to top, and the - // vcall offset itself). - int64_t OffsetIndex = -(int64_t)(3 + Components.size()); - - // FIXME: We shouldn't use / 8 here. - int64_t OffsetOffset = OffsetIndex * - (int64_t)Context.Target.getPointerWidth(0) / 8; - - return OffsetOffset; -} - -void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, - uint64_t VBaseOffset) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - // Handle the primary base first. - if (PrimaryBase) { - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - VBaseOffset); - } - - // Add the vcall offsets. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - int64_t OffsetOffset = getCurrentOffsetOffset(); - - // Don't add a vcall offset if we already have one for this member function - // signature. - if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) - continue; - - int64_t Offset = 0; - - if (Overriders) { - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders->getOverrider(Base, MD); - - /// The vcall offset is the offset from the virtual base to the object - /// where the function was overridden. - // FIXME: We should not use / 8 here. - Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; - } - - Components.push_back(VtableComponent::MakeVCallOffset(Offset)); - } - - // And iterate over all non-virtual bases (ignoring the primary base). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - if (BaseDecl == PrimaryBase) - continue; - - // Get the base offset of this base. - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); - } -} - -void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass) { - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Add vbase offsets. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Check if this is a virtual base that we haven't visited before. - if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { - // FIXME: We shouldn't use / 8 here. - int64_t Offset = - (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - - OffsetInLayoutClass) / 8; - - // Add the vbase offset offset. - assert(!VBaseOffsetOffsets.count(BaseDecl) && - "vbase offset offset already exists!"); - - int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); - VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); - - Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); - } - - // Check the base class looking for more vbase offsets. - AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); - } -} - -/// VtableBuilder - Class for building vtable layout information. -class VtableBuilder { -public: - /// PrimaryBasesSetVectorTy - A set vector of direct and indirect - /// primary bases. - typedef llvm::SmallSetVector - PrimaryBasesSetVectorTy; - - typedef llvm::DenseMap - VBaseOffsetOffsetsMapTy; - - typedef llvm::DenseMap - AddressPointsMapTy; - -private: - /// VTables - Global vtable information. - CodeGenVTables &VTables; - - /// MostDerivedClass - The most derived class for which we're building this - /// vtable. - const CXXRecordDecl *MostDerivedClass; - - /// MostDerivedClassOffset - If we're building a construction vtable, this - /// holds the offset from the layout class to the most derived class. - const uint64_t MostDerivedClassOffset; - - /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual - /// base. (This only makes sense when building a construction vtable). - bool MostDerivedClassIsVirtual; - - /// LayoutClass - The class we're using for layout information. Will be - /// different than the most derived class if we're building a construction - /// vtable. - const CXXRecordDecl *LayoutClass; - - /// Context - The ASTContext which we will use for layout information. - ASTContext &Context; - - /// FinalOverriders - The final overriders of the most derived class. - const FinalOverriders Overriders; - - /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual - /// bases in this vtable. - llvm::DenseMap VCallOffsetsForVBases; - - /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for - /// the most derived class. - VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - - /// Components - The components of the vtable being built. - llvm::SmallVector Components; - - /// AddressPoints - Address points for the vtable being built. - AddressPointsMapTy AddressPoints; - - /// MethodInfo - Contains information about a method in a vtable. - /// (Used for computing 'this' pointer adjustment thunks. - struct MethodInfo { - /// BaseOffset - The base offset of this method. - const uint64_t BaseOffset; - - /// BaseOffsetInLayoutClass - The base offset in the layout class of this - /// method. - const uint64_t BaseOffsetInLayoutClass; - - /// VtableIndex - The index in the vtable that this method has. - /// (For destructors, this is the index of the complete destructor). - const uint64_t VtableIndex; - - MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, - uint64_t VtableIndex) - : BaseOffset(BaseOffset), - BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), - VtableIndex(VtableIndex) { } - - MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { } - }; - - typedef llvm::DenseMap MethodInfoMapTy; - - /// MethodInfoMap - The information for all methods in the vtable we're - /// currently building. - MethodInfoMapTy MethodInfoMap; - - typedef llvm::DenseMap VtableThunksMapTy; - - /// VTableThunks - The thunks by vtable index in the vtable currently being - /// built. - VtableThunksMapTy VTableThunks; - - typedef llvm::SmallVector ThunkInfoVectorTy; - typedef llvm::DenseMap ThunksMapTy; - - /// 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, const ThunkInfo &Thunk); - - /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the - /// part of the vtable we're currently building. - void ComputeThisAdjustments(); - - typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; - - /// PrimaryVirtualBases - All known virtual bases who are a primary base of - /// some other base. - VisitedVirtualBasesSetTy PrimaryVirtualBases; - - /// ComputeReturnAdjustment - Compute the return adjustment given a return - /// adjustment base offset. - ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); - - /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting - /// the 'this' pointer from the base subobject to the derived subobject. - BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const; - - /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the - /// given virtual member function, its offset in the layout class and its - /// final overrider. - ThisAdjustment - ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider); - - /// AddMethod - Add a single virtual member function to the vtable - /// components vector. - void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); - - /// IsOverriderUsed - Returns whether the overrider will ever be used in this - /// part of the vtable. - /// - /// Itanium C++ ABI 2.5.2: - /// - /// struct A { virtual void f(); }; - /// struct B : virtual public A { int i; }; - /// struct C : virtual public A { int j; }; - /// struct D : public B, public C {}; - /// - /// When B and C are declared, A is a primary base in each case, so although - /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this - /// adjustment is required and no thunk is generated. However, inside D - /// objects, A is no longer a primary base of C, so if we allowed calls to - /// C::f() to use the copy of A's vtable in the C subobject, we would need - /// to adjust this from C* to B::A*, which would require a third-party - /// thunk. Since we require that a call to C::f() first convert to A*, - /// C-in-D's copy of A's vtable is never referenced, so this is not - /// necessary. - bool IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const; - - - /// AddMethods - Add the methods of this base subobject and all its - /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases); - - // LayoutVtable - Layout the vtable for the given base class, including its - // secondary vtables and any vtables for virtual bases. - void LayoutVtable(); - - /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the - /// given base subobject, as well as all its secondary vtables. - void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t OffsetInLayoutClass); - - /// LayoutSecondaryVtables - Layout the secondary vtables for the given base - /// subobject. - /// - /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass); - - /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this - /// class hierarchy. - void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases); - - /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the - /// given base (excluding any primary bases). - void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases); - - /// isBuildingConstructionVtable - Return whether this vtable builder is - /// building a construction vtable. - bool isBuildingConstructorVtable() const { - return MostDerivedClass != LayoutClass; - } - -public: - VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, - const CXXRecordDecl *LayoutClass) - : VTables(VTables), MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), - MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), - LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), - Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { - - 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(Components.begin()); - } - - const uint64_t *vtable_components_data_end() const { - return reinterpret_cast(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, const ThunkInfo &Thunk) { - assert(!isBuildingConstructorVtable() && - "Can't add thunks for construction vtable"); - - llvm::SmallVector &ThunksVector = Thunks[MD]; - - // Check if we have this thunk already. - if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != - ThunksVector.end()) - return; - - ThunksVector.push_back(Thunk); -} - -/// OverridesMethodInBases - Checks whether whether this virtual member -/// function overrides a member function in any of the given bases. -/// Returns the overridden member function, or null if none was found. -static const CXXMethodDecl * -OverridesMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - assert(OverriddenMD->isCanonicalDecl() && - "Should have the canonical decl of the overridden RD!"); - - if (Bases.count(OverriddenRD)) - return OverriddenMD; - } - - return 0; -} - -void VtableBuilder::ComputeThisAdjustments() { - // Now go through the method info map and see if any of the methods need - // 'this' pointer adjustments. - for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), - E = MethodInfoMap.end(); I != E; ++I) { - const CXXMethodDecl *MD = I->first; - const MethodInfo &MethodInfo = I->second; - - // Ignore adjustments for unused function pointers. - uint64_t VtableIndex = MethodInfo.VtableIndex; - if (Components[VtableIndex].getKind() == - VtableComponent::CK_UnusedFunctionPointer) - continue; - - // Get the final overrider for this method. - FinalOverriders::OverriderInfo Overrider = - 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); - - if (ThisAdjustment.isEmpty()) - continue; - - // Add it. - VTableThunks[VtableIndex].This = ThisAdjustment; - - if (isa(MD)) { - // Add an adjustment for the deleting destructor as well. - VTableThunks[VtableIndex + 1].This = ThisAdjustment; - } - } - - /// 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); - } -} - -ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { - ReturnAdjustment Adjustment; - - if (!Offset.isEmpty()) { - if (Offset.VirtualBase) { - // Get the virtual base offset offset. - if (Offset.DerivedClass == MostDerivedClass) { - // We can get the offset offset directly from our map. - Adjustment.VBaseOffsetOffset = - VBaseOffsetOffsets.lookup(Offset.VirtualBase); - } else { - Adjustment.VBaseOffsetOffset = - VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, - Offset.VirtualBase); - } - - // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again, - // we can get rid of this assert. - assert(Adjustment.VBaseOffsetOffset != 0 && - "Invalid vbase offset offset!"); - } - - Adjustment.NonVirtual = Offset.NonVirtualOffset; - } - - return Adjustment; -} - -BaseOffset -VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const { - const CXXRecordDecl *BaseRD = Base.getBase(); - const CXXRecordDecl *DerivedRD = Derived.getBase(); - - CXXBasePaths Paths(/*FindAmbiguities=*/true, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - - if (!const_cast(DerivedRD)-> - isDerivedFrom(const_cast(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return BaseOffset(); - } - - // We have to go through all the paths, and see which one leads us to the - // right base subobject. - for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); - I != E; ++I) { - BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); - - // FIXME: Should not use * 8 here. - uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; - - if (Offset.VirtualBase) { - // If we have a virtual base class, the non-virtual offset is relative - // to the virtual base class offset. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - /// Get the virtual base offset, relative to the most derived class - /// layout. - OffsetToBaseSubobject += - LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); - } else { - // Otherwise, the non-virtual offset is relative to the derived class - // offset. - OffsetToBaseSubobject += Derived.getBaseOffset(); - } - - // Check if this path gives us the right base subobject. - if (OffsetToBaseSubobject == Base.getBaseOffset()) { - // Since we're going from the base class _to_ the derived class, we'll - // invert the non-virtual offset here. - Offset.NonVirtualOffset = -Offset.NonVirtualOffset; - return Offset; - } - } - - return BaseOffset(); -} - -ThisAdjustment -VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider) { - // Ignore adjustments for pure virtual member functions. - if (Overrider.Method->isPure()) - return ThisAdjustment(); - - BaseSubobject OverriddenBaseSubobject(MD->getParent(), - BaseOffsetInLayoutClass); - - BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), - Overrider.Offset); - - // Compute the adjustment offset. - BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, - OverriderBaseSubobject); - if (Offset.isEmpty()) - return ThisAdjustment(); - - ThisAdjustment Adjustment; - - if (Offset.VirtualBase) { - // Get the vcall offset map for this virtual base. - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; - - if (VCallOffsets.empty()) { - // We don't have vcall offsets for this virtual base, go ahead and - // build them. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, - /*FinalOverriders=*/0, - BaseSubobject(Offset.VirtualBase, 0), - /*BaseIsVirtual=*/true, - /*OffsetInLayoutClass=*/0); - - VCallOffsets = Builder.getVCallOffsets(); - } - - Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); - } - - // Set the non-virtual part of the adjustment. - Adjustment.NonVirtual = Offset.NonVirtualOffset; - - return Adjustment; -} - -void -VtableBuilder::AddMethod(const CXXMethodDecl *MD, - ReturnAdjustment ReturnAdjustment) { - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - assert(ReturnAdjustment.isEmpty() && - "Destructor can't have return adjustment!"); - - // Add both the complete destructor and the deleting destructor. - Components.push_back(VtableComponent::MakeCompleteDtor(DD)); - Components.push_back(VtableComponent::MakeDeletingDtor(DD)); - } else { - // Add the return adjustment if necessary. - if (!ReturnAdjustment.isEmpty()) - VTableThunks[Components.size()].Return = ReturnAdjustment; - - // Add the function. - Components.push_back(VtableComponent::MakeFunction(MD)); - } -} - -/// OverridesIndirectMethodInBase - Return whether the given member function -/// overrides any methods in the set of given bases. -/// Unlike OverridesMethodInBase, this checks "overriders of overriders". -/// For example, if we have: -/// -/// struct A { virtual void f(); } -/// struct B : A { virtual void f(); } -/// struct C : B { virtual void f(); } -/// -/// OverridesIndirectMethodInBase will return true if given C::f as the method -/// and { A } as the set of bases. -static bool -OverridesIndirectMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - assert(OverriddenMD->isCanonicalDecl() && - "Should have the canonical decl of the overridden RD!"); - - if (Bases.count(OverriddenRD)) - return true; - - // Check "indirect overriders". - if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) - return true; - } - - return false; -} - -bool -VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const { - // If the base and the first base in the primary base chain have the same - // offsets, then this overrider will be used. - if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) - return true; - - // We know now that Base (or a direct or indirect base of it) is a primary - // base in part of the class hierarchy, but not a primary base in the most - // derived class. - - // If the overrider is the first base in the primary base chain, we know - // that the overrider will be used. - if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) - return true; - - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - - const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; - PrimaryBases.insert(RD); - - // Now traverse the base chain, starting with the first base, until we find - // the base that is no longer a primary base. - while (true) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - break; - - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - // Now check if this is the primary base that is not a primary base in the - // most derived class. - if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != - FirstBaseOffsetInLayoutClass) { - // We found it, stop walking the chain. - break; - } - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should always be at offset 0!"); - } - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - - RD = PrimaryBase; - } - - // If the final overrider is an override of one of the primary bases, - // then we know that it will be used. - return OverridesIndirectMethodInBases(Overrider, PrimaryBases); -} - -/// FindNearestOverriddenMethod - Given a method, returns the overridden method -/// from the nearest base. Returns null if no method was found. -static const CXXMethodDecl * -FindNearestOverriddenMethod(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { - for (int I = Bases.size(), E = 0; I != E; --I) { - const CXXRecordDecl *PrimaryBase = Bases[I - 1]; - - // Now check the overriden methods. - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - - // We found our overridden method. - if (OverriddenMD->getParent() == PrimaryBase) - return OverriddenMD; - } - } - - return 0; -} - -void -VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - uint64_t PrimaryBaseOffset; - uint64_t PrimaryBaseOffsetInLayoutClass; - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass; - } - - AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - assert(false && "Found a duplicate primary base!"); - } - - // Now go through all virtual member functions and add them. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(Base, MD); - - // Check if this virtual member function overrides a method in a primary - // base. If this is the case, and the return type doesn't require adjustment - // then we can just use the member function from the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) { - // Replace the method info of the overridden method with our own - // method. - assert(MethodInfoMap.count(OverriddenMD) && - "Did not find the overridden method!"); - MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; - - MethodInfo MethodInfo(Base.getBaseOffset(), - BaseOffsetInLayoutClass, - OverriddenMethodInfo.VtableIndex); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - - 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; - } - } - - // Insert the method info for this method. - MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, - Components.size()); - - assert(!MethodInfoMap.count(MD) && - "Should not have method info for this method yet!"); - MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); - - // Check if this overrider is going to be used. - const CXXMethodDecl *OverriderMD = Overrider.Method; - if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, - FirstBaseInPrimaryBaseChain, - FirstBaseOffsetInLayoutClass)) { - Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD)); - continue; - } - - // Check if this overrider needs a return adjustment. - BaseOffset ReturnAdjustmentOffset = - Overriders.getReturnAdjustmentOffset(Base, MD); - - ReturnAdjustment ReturnAdjustment = - ComputeReturnAdjustment(ReturnAdjustmentOffset); - - AddMethod(Overrider.Method, ReturnAdjustment); - } -} - -void VtableBuilder::LayoutVtable() { - LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0), - MostDerivedClassIsVirtual, - MostDerivedClassOffset); - - VisitedVirtualBasesSetTy VBases; - - // Determine the primary virtual bases. - DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, - VBases); - VBases.clear(); - - LayoutVtablesForVirtualBases(MostDerivedClass, VBases); -} - -void -VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t OffsetInLayoutClass) { - assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); - - // Add vcall and vbase offsets for this vtable. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, - Base, BaseIsVirtual, OffsetInLayoutClass); - Components.append(Builder.components_begin(), Builder.components_end()); - - // Check if we need to add these vcall offsets. - if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) { - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; - - if (VCallOffsets.empty()) - VCallOffsets = Builder.getVCallOffsets(); - } - - // If we're laying out the most derived class we want to keep track of the - // virtual base class offset offsets. - if (Base.getBase() == MostDerivedClass) - VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - - // Add the offset to top. - // FIXME: We should not use / 8 here. - int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - - MostDerivedClassOffset) / 8; - Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop)); - - // Next, add the RTTI. - Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass)); - - uint64_t AddressPoint = Components.size(); - - // Now go through all virtual member functions and add them. - PrimaryBasesSetVectorTy PrimaryBases; - AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass, - PrimaryBases); - - // Compute 'this' pointer adjustments. - ComputeThisAdjustments(); - - // 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(); - - 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; - if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass) - BaseIsMorallyVirtual = false; - - // Layout secondary vtables. - LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); -} - -void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass) { - // Itanium C++ ABI 2.5.2: - // Following the primary virtual table of a derived class are secondary - // virtual tables for each of its proper base classes, except any primary - // base(s) with which it shares its primary virtual table. - - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - // Ignore virtual bases, we'll emit them later. - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Ignore bases that don't have a vtable. - if (!BaseDecl->isDynamicClass()) - continue; - - if (isBuildingConstructorVtable()) { - // Itanium C++ ABI 2.6.4: - // Some of the base class subobjects may not need construction virtual - // tables, which will therefore not be present in the construction - // virtual table group, even though the subobject virtual tables are - // present in the main virtual table group for the complete object. - if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) - continue; - } - - // Get the base offset of this base. - uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); - uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; - - uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; - - // Don't emit a secondary vtable for a primary base. We might however want - // to emit secondary vtables for other bases of this base. - if (BaseDecl == PrimaryBase) { - LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - BaseIsMorallyVirtual, BaseOffsetInLayoutClass); - continue; - } - - // Layout the primary vtable (and any secondary vtables) for this base. - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/false, - BaseOffsetInLayoutClass); - } -} - -void -VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Check if this base has a primary base. - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - - // Check if it's virtual. - if (Layout.getPrimaryBaseWasVirtual()) { - bool IsPrimaryVirtualBase = true; - - if (isBuildingConstructorVtable()) { - // Check if the base is actually a primary base in the class we use for - // layout. - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - uint64_t PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(PrimaryBase); - - // We know that the base is not a primary base in the layout class if - // the base offsets are different. - if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass) - IsPrimaryVirtualBase = false; - } - - if (IsPrimaryVirtualBase) - PrimaryVirtualBases.insert(PrimaryBase); - } - } - - // Traverse bases, looking for more primary virtual bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - uint64_t BaseOffsetInLayoutClass; - - if (I->isVirtual()) { - if (!VBases.insert(BaseDecl)) - continue; - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - - BaseOffsetInLayoutClass = LayoutClassLayout.getVBaseClassOffset(BaseDecl); - } else { - BaseOffsetInLayoutClass = - OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); - } - - DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); - } -} - -void -VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases) { - // Itanium C++ ABI 2.5.2: - // Then come the virtual base virtual tables, also in inheritance graph - // order, and again excluding primary bases (which share virtual tables with - // the classes for which they are primary). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Check if this base needs a vtable. (If it's virtual, not a primary base - // of some other class, and we haven't visited it before). - if (I->isVirtual() && BaseDecl->isDynamicClass() && - !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - uint64_t BaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); - - const ASTRecordLayout &LayoutClassLayout = - Context.getASTRecordLayout(LayoutClass); - uint64_t BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffset(BaseDecl); - - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/true, - BaseOffsetInLayoutClass); - } - - // We only need to check the base for virtual base vtables if it actually - // has virtual bases. - if (BaseDecl->getNumVBases()) - LayoutVtablesForVirtualBases(BaseDecl, VBases); - } -} - -/// dumpLayout - Dump the vtable layout. -void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { - - if (isBuildingConstructorVtable()) { - Out << "Construction vtable for ('"; - Out << MostDerivedClass->getQualifiedNameAsString() << "', "; - // FIXME: Don't use / 8 . - Out << MostDerivedClassOffset / 8 << ") in '"; - Out << LayoutClass->getQualifiedNameAsString(); - } else { - Out << "Vtable for '"; - Out << MostDerivedClass->getQualifiedNameAsString(); - } - Out << "' (" << Components.size() << " entries).\n"; - - // Iterate through the address points and insert them into a new map where - // they are keyed by the index and not the base object. - // Since an address point can be shared by multiple subobjects, we use an - // STL multimap. - std::multimap AddressPointsByIndex; - for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(), - E = AddressPoints.end(); I != E; ++I) { - const BaseSubobject& Base = I->first; - uint64_t Index = I->second; - - AddressPointsByIndex.insert(std::make_pair(Index, Base)); - } - - for (unsigned I = 0, E = Components.size(); I != E; ++I) { - uint64_t Index = I; - - Out << llvm::format("%4d | ", I); - - const VtableComponent &Component = Components[I]; - - // Dump the component. - switch (Component.getKind()) { - - case VtableComponent::CK_VCallOffset: - Out << "vcall_offset (" << Component.getVCallOffset() << ")"; - break; - - case VtableComponent::CK_VBaseOffset: - Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; - break; - - case VtableComponent::CK_OffsetToTop: - Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; - break; - - case VtableComponent::CK_RTTI: - Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; - break; - - case VtableComponent::CK_FunctionPointer: { - const CXXMethodDecl *MD = Component.getFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << Str; - if (MD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this function pointer has a return adjustment, dump it. - if (!Thunk.Return.isEmpty()) { - Out << "\n [return adjustment: "; - Out << Thunk.Return.NonVirtual << " non-virtual"; - - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; - Out << " vbase offset offset"; - } - - Out << ']'; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VtableComponent::CK_CompleteDtorPointer: - case VtableComponent::CK_DeletingDtorPointer: { - bool IsComplete = - Component.getKind() == VtableComponent::CK_CompleteDtorPointer; - - const CXXDestructorDecl *DD = Component.getDestructorDecl(); - - Out << DD->getQualifiedNameAsString(); - if (IsComplete) - Out << "() [complete]"; - else - Out << "() [deleting]"; - - if (DD->isPure()) - Out << " [pure]"; - - ThunkInfo Thunk = VTableThunks.lookup(I); - if (!Thunk.isEmpty()) { - // If this destructor has a 'this' pointer adjustment, dump it. - if (!Thunk.This.isEmpty()) { - Out << "\n [this adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - - Out << ']'; - } - } - - break; - } - - case VtableComponent::CK_UnusedFunctionPointer: { - const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); - - std::string Str = - PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, - MD); - Out << "[unused] " << Str; - if (MD->isPure()) - Out << " [pure]"; - } - - } - - Out << '\n'; - - // Dump the next address point. - uint64_t NextIndex = Index + 1; - if (AddressPointsByIndex.count(NextIndex)) { - if (AddressPointsByIndex.count(NextIndex) == 1) { - const BaseSubobject &Base = - AddressPointsByIndex.find(NextIndex)->second; - - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); - Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; - } else { - uint64_t BaseOffset = - AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); - - // We store the class names in a set to get a stable order. - std::set ClassNames; - for (std::multimap::const_iterator I = - AddressPointsByIndex.lower_bound(NextIndex), E = - AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { - assert(I->second.getBaseOffset() == BaseOffset && - "Invalid base offset!"); - const CXXRecordDecl *RD = I->second.getBase(); - ClassNames.insert(RD->getQualifiedNameAsString()); - } - - for (std::set::const_iterator I = ClassNames.begin(), - E = ClassNames.end(); I != E; ++I) { - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << *I; - Out << ", " << BaseOffset / 8 << ") vtable address --\n"; - } - } - } - } - - Out << '\n'; - - if (isBuildingConstructorVtable()) - return; - - if (MostDerivedClass->getNumVBases()) { - // We store the virtual base class names and their offsets in a map to get - // a stable order. - - std::map ClassNamesAndOffsets; - for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), - E = VBaseOffsetOffsets.end(); I != E; ++I) { - std::string ClassName = I->first->getQualifiedNameAsString(); - int64_t OffsetOffset = I->second; - ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); - } - - Out << "Virtual base offset offsets for '"; - Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; - Out << ClassNamesAndOffsets.size(); - Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; - - for (std::map::const_iterator I = - ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); - I != E; ++I) - Out << " " << I->first << " | " << I->second << '\n'; - - Out << "\n"; - } - - if (!Thunks.empty()) { - // We store the method names in a map to get a stable order. - std::map MethodNamesAndDecls; - - 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, - MD); - - MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); - } - - for (std::map::const_iterator I = - MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); - I != E; ++I) { - const std::string &MethodName = I->first; - const CXXMethodDecl *MD = I->second; - - ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); - - Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); - Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; - - for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { - const ThunkInfo &Thunk = ThunksVector[I]; - - 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 adjustment: "; - Out << Thunk.This.NonVirtual << " non-virtual"; - - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; - Out << " vcall offset offset"; - } - } - - Out << '\n'; - } - - Out << '\n'; - - } - } -} - -} - -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 - // order of declaration of the corresponding member functions in the class. - // - // There is an entry for any virtual function declared in a class, - // whether it is a new function or overrides a base class function, - // unless it overrides a function from the primary base, and conversion - // between their return types does not require an adjustment. - - int64_t CurrentIndex = 0; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (PrimaryBase) { - assert(PrimaryBase->isDefinition() && - "Should have the definition decl of the primary base!"); - - // Since the record decl shares its vtable pointer with the primary base - // we need to start counting at the end of the primary base's vtable. - CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); - } - - // Collect all the primary bases, so we can check whether methods override - // a method from the base. - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - for (ASTRecordLayout::primary_base_info_iterator - I = Layout.primary_base_begin(), E = Layout.primary_base_end(); - I != E; ++I) - PrimaryBases.insert((*I).getBase()); - - const CXXDestructorDecl *ImplicitVirtualDtor = 0; - - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - - // We only want virtual methods. - if (!MD->isVirtual()) - continue; - - // Check if this method overrides a method in the primary base. - if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInBases(MD, PrimaryBases)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, - OverriddenMD).isEmpty()) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast(OverriddenMD); - - // Add both the complete and deleting entries. - MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } else { - MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD); - } - - // We don't need to add an entry for this method. - continue; - } - } - - if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - if (MD->isImplicit()) { - assert(!ImplicitVirtualDtor && - "Did already see an implicit virtual dtor!"); - ImplicitVirtualDtor = DD; - continue; - } - - // Add the complete dtor. - MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; - - // Add the deleting dtor. - MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } else { - // Add the entry. - MethodVtableIndices[MD] = CurrentIndex++; - } - } - - if (ImplicitVirtualDtor) { - // Itanium C++ ABI 2.5.2: - // If a class has an implicitly-defined virtual destructor, - // its entries come after the declared virtual function pointers. - - // Add the complete dtor. - MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = - CurrentIndex++; - - // Add the deleting dtor. - MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = - CurrentIndex++; - } - - NumVirtualFunctionPointers[RD] = CurrentIndex; -} - -uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { - llvm::DenseMap::iterator I = - NumVirtualFunctionPointers.find(RD); - if (I != NumVirtualFunctionPointers.end()) - return I->second; - - ComputeMethodVtableIndices(RD); - - I = NumVirtualFunctionPointers.find(RD); - assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); - return I->second; -} - -uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) { - MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); - if (I != MethodVtableIndices.end()) - return I->second; - - const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); - - ComputeMethodVtableIndices(RD); - - I = MethodVtableIndices.find(GD); - assert(I != MethodVtableIndices.end() && "Did not find index!"); - return I->second; -} - -int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { - ClassPairTy ClassPair(RD, VBase); - - VirtualBaseClassOffsetOffsetsMapTy::iterator I = - VirtualBaseClassOffsetOffsets.find(ClassPair); - if (I != VirtualBaseClassOffsetOffsets.end()) - return I->second; - - VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, - BaseSubobject(RD, 0), - /*BaseIsVirtual=*/false, - /*OffsetInLayoutClass=*/0); - - for (VCallAndVBaseOffsetBuilder::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)); - } - - I = VirtualBaseClassOffsetOffsets.find(ClassPair); - - // FIXME: The assertion below assertion currently fails with the old vtable - /// layout code if there is a non-virtual thunk adjustment in a vtable. - // Once the new layout is in place, this return should be removed. - if (I == VirtualBaseClassOffsetOffsets.end()) - return 0; - - assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); - - return I->second; -} - -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::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, - const ThunkInfo &Thunk) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // Compute the mangled name. - llvm::SmallString<256> Name; - if (const CXXDestructorDecl* DD = dyn_cast(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); - - // 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(GD.getDecl()); - const FunctionProtoType *FPT = MD->getType()->getAs(); - QualType ResultType = FPT->getResultType(); - QualType ThisType = MD->getThisType(getContext()); - - 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()); - - // 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)); - - // 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)); - } - - // Get our callee. - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); - - 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(); - - 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()); - - // Set the right linkage. - Fn->setLinkage(CGM.getFunctionLinkage(MD)); - - // Set the right visibility. - CGM.setGlobalVisibility(Fn, MD); -} - -void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) -{ - llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // Strip off a bitcast if we got one back. - if (llvm::ConstantExpr *CE = dyn_cast(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(Entry)->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVtable(MD)) { - llvm::GlobalValue *OldThunkFn = cast(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(Entry); - CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); -} - -void CodeGenVTables::EmitThunks(GlobalDecl GD) -{ - const CXXMethodDecl *MD = - cast(GD.getDecl())->getCanonicalDecl(); - - // We don't need to generate thunks for the base destructor. - if (isa(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]; - - // Check if we've computed this information before. - if (LayoutData) - return; - - VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); - - // Add the VTable layout. - uint64_t NumVTableComponents = Builder.getNumVTableComponents(); - LayoutData = new uint64_t[NumVTableComponents + 1]; - - // 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(); - const CXXRecordDecl *VBase = cast(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 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(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(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 *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVtable(RD, OutName); - llvm::StringRef Name = OutName.str(); - - ComputeVTableRelatedInformation(RD); - - 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()); - } - - 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); -} - -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(GD.getDecl()); - const CXXRecordDecl *RD = MD->getParent(); - - // If the class doesn't have a vtable we don't need to emit one. - 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 we have no key funcion and this is a explicit instantiation declaration, - // we will produce a vtable at the explicit instantiation. We don't need one - // here. - if (RDKind == clang::TSK_ExplicitInstantiationDeclaration) - return; - - // 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 && - MDKind == TSK_ExplicitInstantiationDefinition) - return; - } - - if (Vtables.count(RD)) - return; - - 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 deleted file mode 100644 index 6073555..0000000 --- a/lib/CodeGen/CGVtable.h +++ /dev/null @@ -1,361 +0,0 @@ -//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This contains code dealing with C++ code generation of virtual tables. -// -//===----------------------------------------------------------------------===// - -#ifndef CLANG_CODEGEN_CGVTABLE_H -#define CLANG_CODEGEN_CGVTABLE_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/GlobalVariable.h" -#include "GlobalDecl.h" - -namespace clang { - class CXXRecordDecl; - -namespace CodeGen { - class CodeGenModule; - -/// 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; } - - friend bool operator==(const ReturnAdjustment &LHS, - const ReturnAdjustment &RHS) { - return LHS.NonVirtual == RHS.NonVirtual && - LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; - } - - 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; - - /// 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; - } -}; - -/// 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) { } - - 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 -// the base class. -class BaseSubobject { - /// Base - The base class declaration. - const CXXRecordDecl *Base; - - /// BaseOffset - The offset from the most derived class to the base class. - uint64_t BaseOffset; - -public: - BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) - : Base(Base), BaseOffset(BaseOffset) { } - - /// getBase - Returns the base class declaration. - const CXXRecordDecl *getBase() const { return Base; } - - /// getBaseOffset - Returns the base class offset. - uint64_t getBaseOffset() const { return BaseOffset; } - - friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { - return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; - } -}; - -} // end namespace CodeGen -} // end namespace clang - -namespace llvm { - -template<> struct DenseMapInfo { - static clang::CodeGen::BaseSubobject getEmptyKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey()); - } - - static clang::CodeGen::BaseSubobject getTombstoneKey() { - return clang::CodeGen::BaseSubobject( - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey()); - } - - static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { - return - DenseMapInfo::getHashValue(Base.getBase()) ^ - DenseMapInfo::getHashValue(Base.getBaseOffset()); - } - - static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, - const clang::CodeGen::BaseSubobject &RHS) { - return LHS == RHS; - } -}; - -// It's OK to treat BaseSubobject as a POD type. -template <> struct isPodLike { - static const bool value = true; -}; - -} - -namespace clang { -namespace CodeGen { - -class CodeGenVTables { - CodeGenModule &CGM; - - /// MethodVtableIndices - Contains the index (relative to the vtable address - /// point) where the function pointer for a virtual function is stored. - typedef llvm::DenseMap MethodVtableIndicesTy; - MethodVtableIndicesTy MethodVtableIndices; - - typedef std::pair ClassPairTy; - - /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to - /// the address point) in bytes where the offsets for virtual bases of a class - /// are stored. - typedef llvm::DenseMap - VirtualBaseClassOffsetOffsetsMapTy; - VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; - - /// Vtables - All the vtables which have been defined. - llvm::DenseMap Vtables; - - /// NumVirtualFunctionPointers - Contains the number of virtual function - /// pointers in the vtable for a given record decl. - llvm::DenseMap NumVirtualFunctionPointers; - - typedef llvm::SmallVector ThunkInfoVectorTy; - typedef llvm::DenseMap ThunksMapTy; - - /// Thunks - Contains all thunks that a given method decl will need. - ThunksMapTy Thunks; - - typedef llvm::DenseMap 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, uint64_t> AddressPointsMapTy; - - /// Address points - Address points for all vtables. - AddressPointsMapTy AddressPoints; - - /// VTableAddressPointsMapTy - Address points for a single vtable. - typedef llvm::DenseMap VTableAddressPointsMapTy; - - typedef llvm::SmallVector, 1> - VTableThunksTy; - - typedef llvm::DenseMap - 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 SubVTTIndiciesMapTy; - - /// SubVTTIndicies - Contains indices into the various sub-VTTs. - SubVTTIndiciesMapTy SubVTTIndicies; - - - typedef llvm::DenseMap, uint64_t> - SecondaryVirtualPointerIndicesMapTy; - - /// 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 *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: - CodeGenVTables(CodeGenModule &CGM) - : CGM(CGM) { } - - /// needsVTTParameter - Return whether the given global decl needs a VTT - /// parameter, which it does if it's a base constructor or destructor with - /// virtual bases. - static bool needsVTTParameter(GlobalDecl GD); - - /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the - /// given record decl. - uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base); - - /// 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. - uint64_t getMethodVtableIndex(GlobalDecl GD); - - /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the - /// vtable address point) where the offset of the virtual base that contains - /// the given base is stored, otherwise, if no virtual base contains the given - /// class, return 0. Base must be a virtual base class or an unambigious - /// base. - int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase); - - /// getAddressPoint - Get the address point of the given subobject in the - /// class decl. - uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD); - - /// 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); - - /// 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); - - // 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 required to be generated - /// upon definition of a KeyFunction. This includes the vtable, the - /// rtti data structure and the VTT. - /// - /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. - void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); -}; - -} // end namespace CodeGen -} // end namespace clang -#endif diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index e72a1d9..dfd2a39 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -23,7 +23,7 @@ add_clang_library(clangCodeGen CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp - CGVtable.cpp + CGVTables.cpp CGVTT.cpp CodeGenFunction.cpp CodeGenModule.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f38d8a1..d3bf164 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -246,15 +246,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { const FunctionDecl *FD = cast(CurGD.getDecl()); - - Stmt *Body = FD->getBody(); - if (Body) - EmitStmt(Body); - else { - assert(FD->isImplicit() && "non-implicit function def has no body"); - assert(FD->isCopyAssignment() && "implicit function not copy assignment"); - SynthesizeCXXCopyAssignment(Args); - } + assert(FD->getBody()); + EmitStmt(FD->getBody()); } void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { @@ -480,6 +473,14 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, } void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs()) { + if (cast(RT->getDecl())->isEmpty()) + return; + } + } + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); @@ -749,6 +750,11 @@ void CodeGenFunction::EmitCleanupBlock() { return; } + // Scrub debug location info. + for (llvm::BasicBlock::iterator LBI = Info.CleanupBlock->begin(), + LBE = Info.CleanupBlock->end(); LBI != LBE; ++LBI) + Builder.SetInstDebugLocation(LBI); + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f21350d..90a3ec4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -32,6 +32,7 @@ namespace llvm { class BasicBlock; class LLVMContext; + class MDNode; class Module; class SwitchInst; class Twine; @@ -148,19 +149,17 @@ public: /// block. class EHCleanupBlock { CodeGenFunction& CGF; - llvm::BasicBlock *Cont; + llvm::BasicBlock *PreviousInsertionBlock; llvm::BasicBlock *CleanupHandler; - llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *PreviousInvokeDest; public: EHCleanupBlock(CodeGenFunction &cgf) - : CGF(cgf), Cont(CGF.createBasicBlock("cont")), - CleanupHandler(CGF.createBasicBlock("ehcleanup")), - CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + : CGF(cgf), + PreviousInsertionBlock(CGF.Builder.GetInsertBlock()), + CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)), PreviousInvokeDest(CGF.getInvokeDest()) { - CGF.EmitBranch(Cont); llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.Builder.SetInsertPoint(CleanupHandler); CGF.setInvokeDest(TerminateHandler); } ~EHCleanupBlock(); @@ -186,7 +185,8 @@ public: public: DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CleanupEntryBB(CGF.createBasicBlock("cleanup")), + CleanupExitBB(0), CurInvokeDest(CGF.getInvokeDest()), EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); @@ -474,11 +474,15 @@ public: /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, bool ctor); /// GenerateObjCSetter - Synthesize an Objective-C property setter function /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + bool IndirectObjCSetterArg(const CGFunctionInfo &FI); + bool IvarTypeWithAggrGCObjects(QualType Ty); //===--------------------------------------------------------------------===// // Block Bits @@ -532,14 +536,16 @@ public: /// InitializeVTablePointer - Initialize the vtable pointer of the given /// subobject. /// - /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointer(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass); typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; - void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointers(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -549,7 +555,6 @@ public: void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); - void SynthesizeCXXCopyAssignment(const FunctionArgList &Args); /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes in @@ -670,6 +675,9 @@ public: llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, const llvm::Twine &Name = "tmp"); + /// InitTempAlloca - Provide an initial value for the given alloca. + void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value); + /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary /// value needs to be stored into an alloca (for example, to avoid explicit @@ -704,6 +712,12 @@ public: RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false, bool IsInitializer = false); + /// EmitsAnyExprToMem - Emits the code necessary to evaluate an + /// arbitrary expression into the given memory location. + void EmitAnyExprToMem(const Expr *E, llvm::Value *Location, + bool IsLocationVolatile = false, + bool IsInitializer = false); + /// EmitAggregateCopy - Emit an aggrate copy. /// /// \param isVolatile - True iff either the source or the destination is @@ -765,22 +779,23 @@ public: } /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a - /// complete class down to one of its virtual bases. - llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value, - bool IsVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base); - + /// complete class to the given direct base. + llvm::Value * + GetAddressOfDirectBaseInCompleteClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual); + /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. - llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, + llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); - + llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *DerivedClassDecl, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This, @@ -789,31 +804,17 @@ public: void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassAggrCopyAssignment(llvm::Value *DestValue, - llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl); void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const CXXRecordDecl *ClassDecl); void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::Value *This, + bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); @@ -842,7 +843,7 @@ public: llvm::Value *This); void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::Value *This); + bool ForVirtualBase, llvm::Value *This); void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); void PopCXXTemporary(); @@ -1033,6 +1034,7 @@ public: // Note: only availabe for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); + LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E); // Note: only available for agg return types LValue EmitCallExprLValue(const CallExpr *E); // Note: only available for agg return types @@ -1100,7 +1102,8 @@ public: llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - const Decl *TargetDecl = 0); + const Decl *TargetDecl = 0, + llvm::Instruction **callOrInvoke = 0); RValue EmitCall(QualType FnType, llvm::Value *Callee, ReturnValueSlot ReturnValue, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a2ad31e..cc90a28 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,6 +35,7 @@ #include "llvm/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Target/TargetData.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; @@ -47,7 +48,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - MangleCtx(C), VTables(*this), Runtime(0), CFConstantStringClassRef(0), + MangleCtx(C, diags), VTables(*this), Runtime(0), + CFConstantStringClassRef(0), + NSConstantStringClassRef(0), VMContext(M.getContext()) { if (!Features.ObjC1) @@ -78,7 +81,6 @@ void CodeGenModule::createObjCRuntime() { } void CodeGenModule::Release() { - EmitFundamentalRTTIDescriptors(); EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); @@ -313,7 +315,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return CodeGenModule::GVA_C99Inline; - + + // If this is a virtual method and its class has a key method in another + // translation unit, we know that this method will be present in that + // translation unit. In this translation unit we will use this method + // only for inlining and analysis. This is the semantics of c99 inline. + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isVirtual() && + CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD)) + return CodeGenModule::GVA_C99Inline; + } + return CodeGenModule::GVA_CXXInline; } @@ -491,11 +504,11 @@ void CodeGenModule::EmitDeferred() { // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. - while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) { - if (!DeferredVtables.empty()) { - const CXXRecordDecl *RD = DeferredVtables.back(); - DeferredVtables.pop_back(); - getVTables().GenerateClassData(getVtableLinkage(RD), RD); + while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { + if (!DeferredVTables.empty()) { + const CXXRecordDecl *RD = DeferredVTables.back(); + DeferredVTables.pop_back(); + getVTables().GenerateClassData(getVTableLinkage(RD), RD); continue; } @@ -687,30 +700,30 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Defer code generation when possible if this is a static definition, inline // function etc. These we only want to emit if they are used. - if (MayDeferGeneration(Global)) { - // If the value has already been used, add it directly to the - // DeferredDeclsToEmit list. - MangleBuffer MangledName; - getMangledName(MangledName, GD); - if (GetGlobalValue(MangledName)) - DeferredDeclsToEmit.push_back(GD); - else { - // Otherwise, remember that we saw a deferred decl with this name. The - // first use of the mangled name will cause it to move into - // DeferredDeclsToEmit. - DeferredDecls[MangledName] = GD; - } + if (!MayDeferGeneration(Global)) { + // Emit the definition if it can't be deferred. + EmitGlobalDefinition(GD); return; } - - // Otherwise emit the definition. - EmitGlobalDefinition(GD); + + // If the value has already been used, add it directly to the + // DeferredDeclsToEmit list. + MangleBuffer MangledName; + getMangledName(MangledName, GD); + if (GetGlobalValue(MangledName)) + DeferredDeclsToEmit.push_back(GD); + else { + // Otherwise, remember that we saw a deferred decl with this name. The + // first use of the mangled name will cause it to move into + // DeferredDeclsToEmit. + DeferredDecls[MangledName] = GD; + } } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast(GD.getDecl()); - PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(), + PrettyStackTraceDecl CrashInfo(const_cast(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); @@ -718,16 +731,18 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { getVTables().EmitVTableRelatedData(GD); if (const CXXConstructorDecl *CD = dyn_cast(D)) - EmitCXXConstructor(CD, GD.getCtorType()); - else if (const CXXDestructorDecl *DD = dyn_cast(D)) - EmitCXXDestructor(DD, GD.getDtorType()); - else if (isa(D)) - EmitGlobalFunctionDefinition(GD); - else if (const VarDecl *VD = dyn_cast(D)) - EmitGlobalVarDefinition(VD); - else { - assert(0 && "Invalid argument to EmitGlobalDefinition()"); - } + return EmitCXXConstructor(CD, GD.getCtorType()); + + if (const CXXDestructorDecl *DD = dyn_cast(D)) + return EmitCXXDestructor(DD, GD.getDtorType()); + + if (isa(D)) + return EmitGlobalFunctionDefinition(GD); + + if (const VarDecl *VD = dyn_cast(D)) + return EmitGlobalVarDefinition(VD); + + assert(0 && "Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the @@ -764,12 +779,16 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; - if (!isa(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - std::vector(), false); + + const llvm::FunctionType *FTy; + if (isa(Ty)) { + FTy = cast(Ty); + } else { + FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + std::vector(), false); IsIncompleteFunction = true; } - llvm::Function *F = llvm::Function::Create(cast(Ty), + llvm::Function *F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, MangledName, &getModule()); assert(F->getName() == MangledName && "name was uniqued!"); @@ -811,7 +830,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, } } - return F; + // Make sure the result is of the requested type. + if (!IsIncompleteFunction) { + assert(F->getType()->getElementType() == Ty); + return F; + } + + const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + return llvm::ConstantExpr::getBitCast(F, PTy); } /// GetAddrOfFunction - Return the address of the given function. If Ty is @@ -959,7 +985,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { } llvm::GlobalVariable::LinkageTypes -CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) { +CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) return llvm::GlobalVariable::InternalLinkage; @@ -1204,9 +1230,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { // TODO: Do invokes ever occur in C code? If so, we should handle them too. - unsigned OpNo = UI.getOperandNo(); - llvm::CallInst *CI = dyn_cast(*UI++); - if (!CI || OpNo != 0) continue; + llvm::Value::use_iterator I = UI++; // Increment before the CI is erased. + llvm::CallInst *CI = dyn_cast(*I); + llvm::CallSite CS(CI); + if (!CI || !CS.isCallee(I)) continue; // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. @@ -1220,8 +1247,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, bool DontTransform = false; for (llvm::Function::arg_iterator AI = NewFn->arg_begin(), E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) { - if (CI->getNumOperands()-1 == ArgNo || - CI->getOperand(ArgNo+1)->getType() != AI->getType()) { + if (CS.arg_size() == ArgNo || + CS.getArgument(ArgNo)->getType() != AI->getType()) { DontTransform = true; break; } @@ -1231,7 +1258,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, // Okay, we can transform this. Create the new call instruction and copy // over the required information. - ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo); + ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo); llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(), ArgList.end(), "", CI); ArgList.clear(); @@ -1578,6 +1605,90 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { return GV; } +llvm::Constant * +CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) { + unsigned StringLength = 0; + bool isUTF16 = false; + llvm::StringMapEntry &Entry = + GetConstantCFStringEntry(CFConstantStringMap, Literal, + getTargetData().isLittleEndian(), + isUTF16, StringLength); + + if (llvm::Constant *C = Entry.getValue()) + return C; + + llvm::Constant *Zero = + llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); + llvm::Constant *Zeros[] = { Zero, Zero }; + + // If we don't already have it, get _NSConstantStringClassReference. + if (!NSConstantStringClassRef) { + const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + Ty = llvm::ArrayType::get(Ty, 0); + llvm::Constant *GV = CreateRuntimeVariable(Ty, + Features.ObjCNonFragileABI ? + "OBJC_CLASS_$_NSConstantString" : + "_NSConstantStringClassReference"); + // Decay array -> ptr + NSConstantStringClassRef = + llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + } + + QualType NSTy = getContext().getNSConstantStringType(); + + const llvm::StructType *STy = + cast(getTypes().ConvertType(NSTy)); + + std::vector Fields(3); + + // Class pointer. + Fields[0] = NSConstantStringClassRef; + + // String pointer. + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); + + llvm::GlobalValue::LinkageTypes Linkage; + bool isConstant; + if (isUTF16) { + // FIXME: why do utf strings get "_" labels instead of "L" labels? + Linkage = llvm::GlobalValue::InternalLinkage; + // Note: -fwritable-strings doesn't make unicode NSStrings writable, but + // does make plain ascii ones writable. + isConstant = true; + } else { + Linkage = llvm::GlobalValue::PrivateLinkage; + isConstant = !Features.WritableStrings; + } + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, + ".str"); + if (isUTF16) { + CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); + GV->setAlignment(Align.getQuantity()); + } + Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + + // String length. + const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); + Fields[2] = llvm::ConstantInt::get(Ty, StringLength); + + // The struct. + C = llvm::ConstantStruct::get(STy, Fields); + GV = new llvm::GlobalVariable(getModule(), C->getType(), true, + llvm::GlobalVariable::PrivateLinkage, C, + "_unnamed_nsstring_"); + // FIXME. Fix section. + if (const char *Sect = + Features.ObjCNonFragileABI + ? getContext().Target.getNSStringNonFragileABISection() + : getContext().Target.getNSStringSection()) + GV->setSection(Sect); + Entry.setValue(GV); + + return GV; +} + /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { @@ -1709,6 +1820,39 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } } +/// EmitObjCIvarInitializations - Emit information for ivar initialization +/// for an implementation. +void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { + if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0) + return; + DeclContext* DC = const_cast(dyn_cast(D)); + assert(DC && "EmitObjCIvarInitializations - null DeclContext"); + IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + Selector cxxSelector = getContext().Selectors.getSelector(0, &II); + ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().VoidTy, 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(DTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); + + II = &getContext().Idents.get(".cxx_construct"); + cxxSelector = getContext().Selectors.getSelector(0, &II); + // The constructor returns 'self'. + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().getObjCIdType(), 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(CTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); + + +} + /// EmitNamespace - Emit all declarations in a namespace. void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); @@ -1805,6 +1949,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast(D); EmitObjCPropertyImplementations(OMD); + EmitObjCIvarInitializations(OMD); Runtime->GenerateClass(OMD); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index e9f78bc..93d8ddf 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -21,7 +21,7 @@ #include "CGBlocks.h" #include "CGCall.h" #include "CGCXX.h" -#include "CGVtable.h" +#include "CGVTables.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -94,7 +94,8 @@ class CodeGenModule : public BlockModule { /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; - + friend class CodeGenVTables; + CGObjCRuntime* Runtime; CGDebugInfo* DebugInfo; @@ -132,6 +133,7 @@ class CodeGenModule : public BlockModule { llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; + llvm::DenseMap StaticLocalDeclMap; /// CXXGlobalInits - Global variables with initializers that need to run /// before main. @@ -145,6 +147,10 @@ class CodeGenModule : public BlockModule { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// NSConstantStringClassRef - Cached reference to the class for constant + /// strings. This value has type int * but is actually an Obj-C class pointer. + llvm::Constant *NSConstantStringClassRef; + /// Lazily create the Objective-C runtime void createObjCRuntime(); @@ -169,6 +175,14 @@ public: /// been configured. bool hasObjCRuntime() { return !!Runtime; } + llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { + return StaticLocalDeclMap[VD]; + } + void setStaticLocalDeclAddress(const VarDecl *D, + llvm::GlobalVariable *GV) { + StaticLocalDeclMap[D] = GV; + } + CGDebugInfo *getDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } @@ -218,7 +232,7 @@ public: /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor /// for the given type. - llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty); + llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); /// GetAddrOfThunk - Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); @@ -227,11 +241,11 @@ public: llvm::Constant *GetWeakRefReference(const ValueDecl *VD); /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to - /// its base class. Returns null if the offset is 0. + /// a class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); - + const CXXBaseSpecifierArray &BasePath); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. @@ -240,6 +254,10 @@ public: /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object /// for the given string. llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal); + + /// GetAddrOfConstantNSString - Return a pointer to a constant NSString object + /// for the given string. + llvm::Constant *GetAddrOfConstantNSString(const StringLiteral *Literal); /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array /// for the given string literal. @@ -416,16 +434,16 @@ public: llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); - /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, + /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes - getVtableLinkage(const CXXRecordDecl *RD); + getVTableLinkage(const CXXRecordDecl *RD); /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; - std::vector DeferredVtables; + std::vector DeferredVTables; private: llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref); @@ -464,6 +482,7 @@ private: void EmitGlobalVarDefinition(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); + void EmitObjCIvarInitializations(ObjCImplementationDecl *D); // C++ related functions. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 9b74106d..10e71e2 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -52,7 +52,6 @@ namespace clang { namespace CodeGen { class CGRecordLayout; - class CodeGenTypes; /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. @@ -124,10 +123,10 @@ public: const llvm::FunctionType *GetFunctionType(GlobalDecl GD); - /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable, + /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, /// and/or incomplete argument types, this will return the opaque type. - const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD); + const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 077db7c..8658cfb 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -25,7 +25,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" -#include "CGVtable.h" +#include "CGVTables.h" #define MANGLE_CHECKER 0 @@ -111,6 +111,7 @@ public: private: bool mangleSubstitution(const NamedDecl *ND); bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); bool mangleStandardSubstitution(const NamedDecl *ND); @@ -121,6 +122,7 @@ private: addSubstitution(reinterpret_cast(ND)); } void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); @@ -138,6 +140,7 @@ private: unsigned KnownArity); void mangleUnscopedName(const NamedDecl *ND); void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, @@ -147,6 +150,7 @@ private: unsigned NumTemplateArgs); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); @@ -172,6 +176,9 @@ private: void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); + void mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -306,8 +313,6 @@ static bool isStd(const NamespaceDecl *NS) { static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { while (isa(DC)) { - assert(cast(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); DC = DC->getParent(); } @@ -429,6 +434,31 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { addSubstitution(ND); } +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // ::= + // ::= + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + // FIXME: How to cope with operators here? + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (!Dependent->isIdentifier()) { + // FIXME: We can't possibly know the arity of the operator here! + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle dependent operator name"); + Diags.Report(FullSourceLoc(), DiagID); + return; + } + + mangleSourceName(Dependent->getIdentifier()); + addSubstitution(Template); +} + void CXXNameMangler::mangleNumber(int64_t Number) { // ::= [n] if (Number < 0) { @@ -475,11 +505,12 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { if (const TemplateSpecializationType *TST = dyn_cast(QTy)) { if (!mangleSubstitution(QualType(TST, 0))) { - TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); - assert(TD && "FIXME: Support dependent template names"); - mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TST->getArgs(), + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } @@ -741,6 +772,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { addSubstitution(cast(DC)); } +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // ::=