From 4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa Mon Sep 17 00:00:00 2001 From: rdivacky Date: Tue, 1 Dec 2009 11:08:04 +0000 Subject: Update clang to r90226. --- Makefile | 4 +- clang.xcodeproj/project.pbxproj | 24 +- include/clang/AST/ASTContext.h | 35 +- include/clang/AST/Attr.h | 42 +- include/clang/AST/Decl.h | 46 + include/clang/AST/DeclBase.h | 4 +- include/clang/AST/DeclCXX.h | 41 +- include/clang/AST/DeclTemplate.h | 3 +- include/clang/AST/DeclarationName.h | 26 +- include/clang/AST/Expr.h | 86 +- include/clang/AST/ExprCXX.h | 626 ++++--- include/clang/AST/RecordLayout.h | 112 +- include/clang/AST/Redeclarable.h | 13 +- include/clang/AST/Stmt.h | 95 +- include/clang/AST/StmtCXX.h | 6 +- include/clang/AST/StmtNodes.def | 9 +- include/clang/AST/TemplateBase.h | 36 + include/clang/AST/Type.h | 30 +- include/clang/Analysis/Analyses/LiveVariables.h | 6 +- include/clang/Analysis/PathDiagnostic.h | 19 +- .../clang/Analysis/PathSensitive/AnalysisContext.h | 14 +- include/clang/Analysis/PathSensitive/BugReporter.h | 21 +- include/clang/Analysis/PathSensitive/BugType.h | 30 +- include/clang/Analysis/PathSensitive/Checker.h | 101 +- .../Analysis/PathSensitive/CheckerVisitor.def | 18 +- .../Checkers/UndefinedAssignmentChecker.h | 33 - .../clang/Analysis/PathSensitive/ExplodedGraph.h | 14 +- .../clang/Analysis/PathSensitive/GRCoreEngine.h | 4 +- .../clang/Analysis/PathSensitive/GRExprEngine.h | 131 +- include/clang/Analysis/PathSensitive/GRState.h | 28 +- include/clang/Analysis/PathSensitive/MemRegion.h | 161 +- .../clang/Analysis/PathSensitive/ValueManager.h | 3 + include/clang/Basic/BuiltinsX86.def | 4 +- include/clang/Basic/DiagnosticDriverKinds.td | 3 + include/clang/Basic/DiagnosticFrontendKinds.td | 2 + include/clang/Basic/DiagnosticGroups.td | 7 +- include/clang/Basic/DiagnosticLexKinds.td | 2 + include/clang/Basic/DiagnosticParseKinds.td | 11 +- include/clang/Basic/DiagnosticSemaKinds.td | 58 +- include/clang/Basic/IdentifierTable.h | 9 +- include/clang/Basic/LangOptions.h | 15 +- include/clang/Basic/OnDiskHashTable.h | 1 - include/clang/Basic/TargetInfo.h | 3 +- include/clang/Basic/TokenKinds.def | 111 +- include/clang/CodeGen/CodeGenOptions.h | 52 +- include/clang/Driver/ArgList.h | 83 +- include/clang/Driver/CC1Options.h | 2 - include/clang/Driver/CC1Options.td | 395 +++- include/clang/Driver/Makefile | 4 +- include/clang/Driver/OptParser.td | 15 +- include/clang/Driver/OptSpecifier.h | 3 + include/clang/Driver/Options.h | 2 - include/clang/Frontend/ASTConsumers.h | 1 + include/clang/Frontend/ASTUnit.h | 43 +- include/clang/Frontend/AnalysisConsumer.h | 2 +- include/clang/Frontend/CommandLineSourceLoc.h | 49 +- include/clang/Frontend/CompilerInstance.h | 18 + include/clang/Frontend/CompilerInvocation.h | 18 +- include/clang/Frontend/DeclXML.def | 58 +- include/clang/Frontend/FrontendAction.h | 17 - include/clang/Frontend/FrontendOptions.h | 2 +- include/clang/Frontend/LangStandard.h | 83 + include/clang/Frontend/LangStandards.def | 83 + include/clang/Frontend/PCHBitCodes.h | 8 +- include/clang/Frontend/PathDiagnosticClients.h | 2 - include/clang/Frontend/StmtXML.def | 89 +- include/clang/Frontend/TextDiagnosticBuffer.h | 4 + include/clang/Lex/Lexer.h | 5 +- include/clang/Lex/Preprocessor.h | 6 +- include/clang/Parse/Action.h | 152 +- include/clang/Parse/AttributeList.h | 35 +- include/clang/Parse/DeclSpec.h | 21 +- include/clang/Parse/Parser.h | 74 +- include/clang/Sema/CodeCompleteConsumer.h | 22 +- lib/AST/ASTContext.cpp | 113 +- lib/AST/Decl.cpp | 205 +- lib/AST/DeclBase.cpp | 15 +- lib/AST/DeclCXX.cpp | 46 +- lib/AST/DeclPrinter.cpp | 15 +- lib/AST/DeclTemplate.cpp | 7 +- lib/AST/DeclarationName.cpp | 44 + lib/AST/Expr.cpp | 212 ++- lib/AST/ExprCXX.cpp | 244 +-- lib/AST/ExprConstant.cpp | 62 +- lib/AST/RecordLayoutBuilder.cpp | 259 ++- lib/AST/RecordLayoutBuilder.h | 20 +- lib/AST/Stmt.cpp | 6 +- lib/AST/StmtDumper.cpp | 3 +- lib/AST/StmtPrinter.cpp | 52 +- lib/AST/StmtProfile.cpp | 46 +- lib/AST/StmtViz.cpp | 5 +- lib/AST/TemplateBase.cpp | 14 +- lib/AST/Type.cpp | 6 + lib/AST/TypePrinter.cpp | 10 + lib/Analysis/AnalysisContext.cpp | 87 +- lib/Analysis/ArrayBoundChecker.cpp | 12 +- lib/Analysis/AttrNonNullChecker.cpp | 8 +- lib/Analysis/BadCallChecker.cpp | 57 - lib/Analysis/BasicConstraintManager.cpp | 7 +- lib/Analysis/BasicObjCFoundationChecks.cpp | 73 +- lib/Analysis/BasicObjCFoundationChecks.h | 12 +- lib/Analysis/BasicStore.cpp | 5 +- lib/Analysis/BugReporter.cpp | 23 +- lib/Analysis/BugReporterVisitors.cpp | 4 +- lib/Analysis/CFG.cpp | 22 +- lib/Analysis/CFRefCount.cpp | 252 ++- lib/Analysis/CMakeLists.txt | 7 +- lib/Analysis/CallAndMessageChecker.cpp | 267 +++ lib/Analysis/CallGraph.cpp | 4 +- lib/Analysis/CallInliner.cpp | 2 +- lib/Analysis/CastToStructChecker.cpp | 4 +- lib/Analysis/CheckDeadStores.cpp | 18 +- lib/Analysis/CheckObjCDealloc.cpp | 7 +- lib/Analysis/CheckObjCInstMethSignature.cpp | 2 +- lib/Analysis/CheckObjCUnusedIVars.cpp | 36 +- lib/Analysis/CheckSecuritySyntaxOnly.cpp | 9 +- lib/Analysis/CheckSizeofPointer.cpp | 3 +- lib/Analysis/Checker.cpp | 35 + lib/Analysis/DereferenceChecker.cpp | 68 +- lib/Analysis/DivZeroChecker.cpp | 7 +- lib/Analysis/Environment.cpp | 3 +- lib/Analysis/FixedAddressChecker.cpp | 4 +- lib/Analysis/GRCoreEngine.cpp | 7 +- lib/Analysis/GRExprEngine.cpp | 462 ++--- lib/Analysis/GRExprEngineExperimentalChecks.cpp | 2 + lib/Analysis/GRExprEngineInternalChecks.cpp | 400 ---- lib/Analysis/GRExprEngineInternalChecks.h | 6 +- lib/Analysis/GRState.cpp | 23 +- lib/Analysis/LiveVariables.cpp | 25 +- lib/Analysis/MallocChecker.cpp | 21 +- lib/Analysis/MemRegion.cpp | 132 +- lib/Analysis/NSAutoreleasePoolChecker.cpp | 6 +- lib/Analysis/NSErrorChecker.cpp | 7 +- lib/Analysis/PointerArithChecker.cpp | 4 +- lib/Analysis/PointerSubChecker.cpp | 4 +- lib/Analysis/PthreadLockChecker.cpp | 8 +- lib/Analysis/RangeConstraintManager.cpp | 11 +- lib/Analysis/RegionStore.cpp | 92 +- lib/Analysis/ReturnPointerRangeChecker.cpp | 5 +- lib/Analysis/ReturnStackAddressChecker.cpp | 13 +- lib/Analysis/ReturnUndefChecker.cpp | 4 +- lib/Analysis/SVals.cpp | 2 +- lib/Analysis/SimpleSValuator.cpp | 3 +- lib/Analysis/Store.cpp | 10 +- lib/Analysis/UndefBranchChecker.cpp | 117 ++ lib/Analysis/UndefResultChecker.cpp | 86 + lib/Analysis/UndefinedArgChecker.cpp | 56 - lib/Analysis/UndefinedArraySubscriptChecker.cpp | 4 +- lib/Analysis/UndefinedAssignmentChecker.cpp | 22 +- lib/Analysis/UninitializedValues.cpp | 7 +- lib/Analysis/VLASizeChecker.cpp | 9 +- lib/Analysis/ValueManager.cpp | 11 +- lib/Basic/TargetInfo.cpp | 1 + lib/Basic/Targets.cpp | 49 + lib/Basic/TokenKinds.cpp | 55 +- lib/CodeGen/CGBlocks.cpp | 16 +- lib/CodeGen/CGBuiltin.cpp | 11 +- lib/CodeGen/CGCXX.cpp | 346 ++-- lib/CodeGen/CGCXXClass.cpp | 179 -- lib/CodeGen/CGCXXExpr.cpp | 524 ------ lib/CodeGen/CGCXXTemp.cpp | 163 -- lib/CodeGen/CGCall.cpp | 62 + lib/CodeGen/CGClass.cpp | 235 +++ lib/CodeGen/CGDebugInfo.cpp | 42 +- lib/CodeGen/CGDecl.cpp | 20 +- lib/CodeGen/CGException.cpp | 390 +++- lib/CodeGen/CGExpr.cpp | 84 +- lib/CodeGen/CGExprAgg.cpp | 30 +- lib/CodeGen/CGExprCXX.cpp | 527 ++++++ lib/CodeGen/CGExprComplex.cpp | 31 +- lib/CodeGen/CGExprConstant.cpp | 13 +- lib/CodeGen/CGExprScalar.cpp | 181 +- lib/CodeGen/CGObjCGNU.cpp | 13 +- lib/CodeGen/CGObjCMac.cpp | 21 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 34 +- lib/CodeGen/CGRtti.cpp | 45 +- lib/CodeGen/CGStmt.cpp | 136 +- lib/CodeGen/CGTemporaries.cpp | 143 ++ lib/CodeGen/CGVtable.cpp | 546 ++++-- lib/CodeGen/CGVtable.h | 86 +- lib/CodeGen/CMakeLists.txt | 8 +- lib/CodeGen/CodeGenFunction.cpp | 35 +- lib/CodeGen/CodeGenFunction.h | 178 +- lib/CodeGen/CodeGenModule.cpp | 182 +- lib/CodeGen/CodeGenModule.h | 18 +- lib/CodeGen/CodeGenTypes.cpp | 9 +- lib/CodeGen/CodeGenTypes.h | 31 +- lib/CodeGen/Mangle.cpp | 816 ++++---- lib/CodeGen/Mangle.h | 91 +- lib/CodeGen/ModuleBuilder.cpp | 4 +- lib/CodeGen/TargetABIInfo.cpp | 28 +- lib/Driver/ArgList.cpp | 112 +- lib/Driver/CC1Options.cpp | 9 +- lib/Driver/Compilation.cpp | 7 + lib/Driver/Driver.cpp | 7 +- lib/Driver/DriverOptions.cpp | 5 - lib/Driver/Tools.cpp | 179 +- lib/Driver/Types.cpp | 1 + lib/Frontend/ASTUnit.cpp | 102 +- lib/Frontend/AnalysisConsumer.cpp | 32 +- lib/Frontend/Backend.cpp | 79 +- lib/Frontend/CMakeLists.txt | 1 + lib/Frontend/CacheTokens.cpp | 14 +- lib/Frontend/CompilerInstance.cpp | 22 +- lib/Frontend/CompilerInvocation.cpp | 807 +++++++- lib/Frontend/DependencyFile.cpp | 3 +- lib/Frontend/DiagChecker.cpp | 3 +- lib/Frontend/FrontendAction.cpp | 9 +- lib/Frontend/FrontendActions.cpp | 13 +- lib/Frontend/GeneratePCH.cpp | 7 +- lib/Frontend/HTMLDiagnostics.cpp | 3 +- lib/Frontend/InitHeaderSearch.cpp | 157 +- lib/Frontend/InitPreprocessor.cpp | 7 + lib/Frontend/LangStandards.cpp | 44 + lib/Frontend/PCHReader.cpp | 22 +- lib/Frontend/PCHReaderDecl.cpp | 4 + lib/Frontend/PCHReaderStmt.cpp | 4 + lib/Frontend/PCHWriter.cpp | 24 +- lib/Frontend/PCHWriterStmt.cpp | 4 + lib/Frontend/PlistDiagnostics.cpp | 4 +- lib/Frontend/PrintParserCallbacks.cpp | 15 +- lib/Frontend/RewriteMacros.cpp | 3 +- lib/Frontend/RewriteObjC.cpp | 2 +- lib/Frontend/StmtXML.cpp | 5 +- lib/Frontend/TextDiagnosticBuffer.cpp | 21 +- lib/Frontend/VerifyDiagnosticsClient.cpp | 8 +- lib/Headers/stdint.h | 71 +- lib/Index/Analyzer.cpp | 9 +- lib/Index/DeclReferenceMap.cpp | 3 +- lib/Index/ResolveLocation.cpp | 7 +- lib/Index/SelectorMap.cpp | 3 +- lib/Lex/Lexer.cpp | 11 +- lib/Lex/LiteralSupport.cpp | 42 +- lib/Lex/PPDirectives.cpp | 5 +- lib/Lex/PPLexerChange.cpp | 20 +- lib/Lex/PTHLexer.cpp | 14 +- lib/Parse/AttributeList.cpp | 24 +- lib/Parse/MinimalAction.cpp | 2 +- lib/Parse/ParseCXXInlineMethods.cpp | 3 +- lib/Parse/ParseDecl.cpp | 126 +- lib/Parse/ParseDeclCXX.cpp | 270 ++- lib/Parse/ParseExpr.cpp | 29 +- lib/Parse/ParseExprCXX.cpp | 113 +- lib/Parse/ParseObjc.cpp | 8 +- lib/Parse/ParseStmt.cpp | 187 +- lib/Parse/ParseTemplate.cpp | 50 +- lib/Parse/ParseTentative.cpp | 88 +- lib/Parse/Parser.cpp | 27 +- lib/Rewrite/HTMLRewrite.cpp | 6 +- lib/Rewrite/TokenRewriter.cpp | 3 +- lib/Sema/CodeCompleteConsumer.cpp | 492 ++--- lib/Sema/Lookup.h | 46 +- lib/Sema/ParseAST.cpp | 3 - lib/Sema/Sema.cpp | 15 +- lib/Sema/Sema.h | 354 ++-- lib/Sema/SemaCodeComplete.cpp | 103 +- lib/Sema/SemaDecl.cpp | 183 +- lib/Sema/SemaDeclAttr.cpp | 223 ++- lib/Sema/SemaDeclCXX.cpp | 230 ++- lib/Sema/SemaExpr.cpp | 1957 ++++++++++++-------- lib/Sema/SemaExprCXX.cpp | 210 +-- lib/Sema/SemaInit.cpp | 45 +- lib/Sema/SemaLookup.cpp | 52 +- lib/Sema/SemaOverload.cpp | 556 +++--- lib/Sema/SemaStmt.cpp | 246 ++- lib/Sema/SemaTemplate.cpp | 723 +++++--- lib/Sema/SemaTemplateDeduction.cpp | 108 +- lib/Sema/SemaTemplateInstantiate.cpp | 54 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 38 +- lib/Sema/SemaType.cpp | 1 + lib/Sema/TreeTransform.h | 673 +++---- test/Analysis/MissingDealloc.m | 4 +- test/Analysis/casts.c | 2 +- test/Analysis/casts.m | 4 +- test/Analysis/cfref_PR2519.c | 8 +- test/Analysis/concrete-address.c | 4 +- test/Analysis/dead-stores.c | 46 +- test/Analysis/fields.c | 4 +- test/Analysis/misc-ps-64.m | 8 +- test/Analysis/misc-ps-basic-store.m | 2 +- test/Analysis/misc-ps-eager-assume.m | 2 +- test/Analysis/misc-ps-ranges.m | 4 +- test/Analysis/misc-ps-region-store-i386.m | 2 +- test/Analysis/misc-ps-region-store-x86_64.m | 2 +- test/Analysis/misc-ps-region-store.m | 75 +- test/Analysis/misc-ps.m | 51 +- ...il-receiver-undefined-larger-than-voidptr-ret.m | 26 +- test/Analysis/null-deref-ps.c | 8 +- test/Analysis/plist-output.m | 739 +++++++- test/Analysis/rdar-6442306-1.m | 4 +- ...dar-6600344-nil-receiver-undefined-struct-ret.m | 4 +- test/Analysis/region-only-test.c | 13 - test/Analysis/retain-release-gc-only.m | 16 +- test/Analysis/retain-release.m | 48 +- test/Analysis/stack-addr-ps.c | 17 +- test/Analysis/uninit-msg-expr.m | 2 +- test/Analysis/uninit-ps-rdar6145427.m | 2 +- test/Analysis/unused-ivars.m | 16 + test/CMakeLists.txt | 5 + test/CXX/basic/basic.link/p9.cpp | 11 + .../basic/basic.lookup/basic.lookup.unqual/p15.cpp | 2 +- .../dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp | 4 +- .../temp.class.spec/temp.class.spec.mfunc/p1.cpp | 1 - .../temp.decls/temp.class/temp.mem.func/p1.cpp | 34 +- test/CXX/temp/temp.param/p2.cpp | 3 +- test/CXX/temp/temp.param/p9.cpp | 23 + test/CodeCompletion/property.m | 29 - test/CodeGen/2008-07-17-no-emit-on-error.c | 4 + ...2008-07-22-bitfield-init-after-zero-len-array.c | 2 +- test/CodeGen/2008-07-30-implicit-initialization.c | 2 +- test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c | 2 +- test/CodeGen/2008-08-04-void-pointer-arithmetic.c | 2 +- test/CodeGen/2008-08-19-cast-of-typedef.c | 2 +- test/CodeGen/PR2001-bitfield-reload.c | 5 +- test/CodeGen/arm-arguments.c | 4 +- test/CodeGen/builtins-ffs_parity_popcount.c | 15 - test/CodeGen/builtins-powi.c | 28 - test/CodeGen/const-init.c | 4 +- test/CodeGen/debug-info.c | 2 +- test/CodeGen/flexible-array-init.c | 7 +- test/CodeGen/func-return-member.c | 5 +- test/CodeGen/incomplete-function-type.c | 6 +- test/CodeGen/rdr-6098585-default-after-caserange.c | 2 +- .../rdr-6098585-default-fallthrough-to-caserange.c | 2 +- test/CodeGen/rdr-6098585-empty-case-range.c | 2 +- .../rdr-6098585-fallthrough-to-empty-range.c | 2 +- test/CodeGen/rdr-6098585-unsigned-caserange.c | 2 +- test/CodeGen/stack-protector.c | 6 +- test/CodeGen/static-order.c | 5 +- test/CodeGen/switch.c | 27 +- test/CodeGen/vector.c | 2 +- test/CodeGen/visibility.c | 6 +- test/CodeGenCXX/condition.cpp | 110 ++ test/CodeGenCXX/conditional-temporaries.cpp | 28 + test/CodeGenCXX/const-global-linkage.cpp | 13 + test/CodeGenCXX/const-init.cpp | 17 +- test/CodeGenCXX/copy-assign-synthesis-2.cpp | 4 + test/CodeGenCXX/copy-constructor-synthesis.cpp | 11 + test/CodeGenCXX/default-arguments.cpp | 58 +- test/CodeGenCXX/dyncast.cpp | 12 +- test/CodeGenCXX/eh.cpp | 68 + test/CodeGenCXX/mangle-template.cpp | 68 + test/CodeGenCXX/member-expressions.cpp | 27 + test/CodeGenCXX/member-function-pointers.cpp | 18 + test/CodeGenCXX/member-pointer-cast.cpp | 21 + test/CodeGenCXX/member-templates.cpp | 31 + test/CodeGenCXX/new-with-default-arg.cpp | 33 + test/CodeGenCXX/new.cpp | 20 +- test/CodeGenCXX/references.cpp | 5 + test/CodeGenCXX/temp-1.cpp | 83 - test/CodeGenCXX/temp-order.cpp | 199 ++ test/CodeGenCXX/virt-dtor-key.cpp | 9 + test/CodeGenCXX/virt.cpp | 93 +- test/CodeGenCXX/virtual-base-cast.cpp | 38 +- test/CodeGenCXX/virtual-base-destructor-call.cpp | 19 + test/CodeGenCXX/virtual-bases.cpp | 17 + .../virtual-functions-incomplete-types.cpp | 30 + test/CodeGenCXX/x86_64-arguments.cpp | 27 +- test/CodeGenObjC/class-obj-hidden-visibility.m | 6 - test/CodeGenObjC/constant-strings.m | 2 +- test/CodeGenObjC/continuation-class.m | 2 +- test/CodeGenObjC/dot-syntax-1.m | 2 +- test/CodeGenObjC/dot-syntax.m | 2 +- test/CodeGenObjC/encode-test.m | 3 + test/CodeGenObjC/hidden-synthesized-ivar.m | 13 - test/CodeGenObjC/hidden-visibility.m | 2 +- test/CodeGenObjC/hidden.m | 2 +- test/CodeGenObjC/messages-2.m | 2 +- test/CodeGenObjC/messages.m | 6 +- test/CodeGenObjC/metadata_symbols.m | 2 +- test/CodeGenObjC/newproperty-nested-synthesis-1.m | 2 +- test/CodeGenObjC/property-getter-dot-syntax.m | 2 +- test/CodeGenObjC/property.m | 2 +- .../protocol-definition-hidden-visibility.m | 19 - test/CodeGenObjC/sel-as-builtin-type.m | 23 + test/CodeGenObjC/undefined-protocol.m | 6 + test/CodeGenObjC/variadic-sends.m | 20 +- test/Coverage/ast-printing.c | 8 +- test/Coverage/ast-printing.cpp | 8 +- test/Coverage/ast-printing.m | 6 +- test/Coverage/parse-callbacks.c | 4 +- test/Coverage/parse-callbacks.m | 4 +- test/Driver/clang-translation.c | 14 +- test/Driver/flags.c | 6 +- test/FixIt/fixit-cxx0x.cpp | 14 + test/Frontend/mmacosx-version-min-test.c | 1 - test/Frontend/output-failures.c | 4 + test/Frontend/rewrite-macros.c | 2 +- test/Index/c-index-api-fn-scan.m | 217 +++ test/Index/c-index-api-loadTU-test.m | 124 -- test/Index/c-index-api-test.m | 224 --- test/Index/c-index-pch.h | 7 - test/Index/foo.h | 8 - test/Index/objc.h | 11 - test/Index/t1.c | 31 - test/Index/t1.m | 23 - test/Index/t2.c | 14 - test/Index/t2.m | 16 - test/Lexer/constants-ms.c | 12 + test/Misc/diag-checker.c | 5 - test/PCH/method_pool.m | 2 +- test/PCH/objc_import.m | 2 +- test/PCH/objc_methods.m | 2 +- test/PCH/objc_property.m | 2 +- test/PCH/reloc.c | 2 +- test/Parser/MicrosoftExtensions.c | 2 +- test/Parser/attributes.c | 1 + test/Parser/cxx-attributes.cpp | 9 + test/Parser/cxx-parse-member-pointer-op.cpp | 13 - test/Parser/cxx-template-decl.cpp | 4 +- test/Parser/cxx-using-declaration.cpp | 5 +- test/Parser/cxx0x-attributes.cpp | 61 + test/Parser/cxx0x-literal-operators.cpp | 5 + test/Parser/if-scope-c90.c | 2 +- test/Parser/if-scope-c99.c | 2 +- test/Preprocessor/assembler-with-cpp.c | 4 +- test/Preprocessor/cxx_true.cpp | 6 +- test/Preprocessor/feature_tests.c | 4 +- test/Preprocessor/init.c | 101 +- test/Preprocessor/line-directive.c | 2 +- test/Preprocessor/macro_paste_bcpl_comment.c | 2 +- test/Preprocessor/stdint.c | 37 +- test/Rewriter/id-test-3.m | 2 +- test/Rewriter/ivar-encoding-1.m | 2 +- test/Rewriter/ivar-encoding-2.m | 2 +- test/Rewriter/metadata-test-1.m | 2 +- test/Rewriter/metadata-test-2.m | 2 +- test/Rewriter/method-encoding-1.m | 2 +- test/Rewriter/objc-encoding-bug-1.m | 2 +- test/Rewriter/objc-string-concat-1.m | 2 +- test/Rewriter/objc-synchronized-1.m | 2 +- test/Rewriter/protocol-rewrite-1.m | 2 +- test/Rewriter/rewrite-api-bug.m | 2 +- test/Rewriter/rewrite-foreach-1.m | 2 +- test/Rewriter/rewrite-foreach-2.m | 2 +- test/Rewriter/rewrite-foreach-3.m | 2 +- test/Rewriter/rewrite-foreach-4.m | 2 +- test/Rewriter/rewrite-foreach-5.m | 2 +- test/Rewriter/rewrite-foreach-6.m | 2 +- test/Rewriter/rewrite-nest.m | 2 +- test/Rewriter/rewrite-protocol-type-1.m | 2 +- test/Rewriter/rewrite-try-catch.m | 2 +- test/Rewriter/static-type-protocol-1.m | 2 +- test/Rewriter/undecl-objc-h.m | 2 +- test/Rewriter/undeclared-method-1.m | 2 +- test/Rewriter/undef-field-reference-1.m | 2 +- test/Rewriter/va-method.m | 2 +- test/Sema/align-arm-apcs.c | 2 +- test/Sema/altivec-init.c | 2 +- test/Sema/carbon.c | 2 +- test/Sema/cast.c | 4 + test/Sema/exprs.c | 2 +- test/Sema/switch.c | 12 +- test/Sema/wchar.c | 4 +- test/SemaCXX/alignof-sizeof-reference.cpp | 9 + test/SemaCXX/attr-cxx0x.cpp | 36 + test/SemaCXX/attr-sentinel.cpp | 6 + test/SemaCXX/class-layout.cpp | 17 + test/SemaCXX/class.cpp | 8 + test/SemaCXX/condition.cpp | 8 + test/SemaCXX/converting-constructor.cpp | 7 + test/SemaCXX/implicit-int.cpp | 2 +- test/SemaCXX/member-pointers-2.cpp | 36 + test/SemaCXX/nested-name-spec.cpp | 3 +- test/SemaCXX/new-delete.cpp | 12 + test/SemaCXX/pseudo-destructors.cpp | 9 + test/SemaCXX/qual-id-test.cpp | 4 +- test/SemaCXX/reinterpret-cast.cpp | 10 +- test/SemaCXX/switch-0x.cpp | 11 + test/SemaCXX/switch.cpp | 27 + test/SemaCXX/typedef-redecl.cpp | 2 +- test/SemaCXX/using-directive.cpp | 10 + test/SemaObjC/cocoa.m | 2 +- test/SemaObjC/foreach.m | 2 +- test/SemaObjC/ivar-ref-misuse.m | 2 +- test/SemaTemplate/current-instantiation.cpp | 9 + test/SemaTemplate/default-arguments-cxx0x.cpp | 26 + test/SemaTemplate/dependent-names.cpp | 70 + test/SemaTemplate/dependent-sized_array.cpp | 17 + test/SemaTemplate/destructor-template.cpp | 7 + test/SemaTemplate/instantiate-function-1.cpp | 3 - test/SemaTemplate/instantiate-member-template.cpp | 15 + test/SemaTemplate/instantiate-method.cpp | 23 +- test/SemaTemplate/instantiate-static-var.cpp | 36 +- test/SemaTemplate/instantiation-depth.cpp | 2 +- test/SemaTemplate/nested-name-spec-template.cpp | 2 +- test/SemaTemplate/overload-uneval.cpp | 42 + test/SemaTemplate/qualified-id.cpp | 11 + test/SemaTemplate/temp_arg_nontype.cpp | 9 + test/SemaTemplate/temp_explicit.cpp | 17 + tools/CIndex/CIndex.cpp | 777 ++++---- tools/CMakeLists.txt | 4 +- tools/c-index-test/CMakeLists.txt | 3 + tools/c-index-test/Makefile | 3 +- tools/c-index-test/c-index-test.c | 134 +- tools/clang-cc/CMakeLists.txt | 1 + tools/clang-cc/Makefile | 2 +- tools/clang-cc/Options.cpp | 327 ++-- tools/clang-cc/Options.h | 7 +- tools/clang-cc/clang-cc.cpp | 173 +- tools/driver/CMakeLists.txt | 11 +- tools/driver/Makefile | 2 +- tools/driver/cc1_main.cpp | 68 +- tools/driver/driver.cpp | 17 +- tools/index-test/CMakeLists.txt | 2 + tools/index-test/Makefile | 3 +- tools/index-test/index-test.cpp | 33 +- tools/scan-build/ccc-analyzer | 632 +++++++ tools/scan-build/scan-build | 1297 +++++++++++++ tools/scan-build/scanview.css | 62 + tools/scan-build/sorttable.js | 493 +++++ tools/wpa/CMakeLists.txt | 20 - tools/wpa/Makefile | 16 - tools/wpa/clang-wpa.cpp | 62 - utils/C++Tests/Clang-Code-Compile/lit.local.cfg | 2 +- utils/C++Tests/Clang-Syntax/lit.local.cfg | 1 + utils/C++Tests/LLVM-Code-Compile/lit.local.cfg | 24 + utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg | 23 + utils/C++Tests/LLVM-Syntax/lit.local.cfg | 3 +- utils/C++Tests/lit.cfg | 12 +- utils/analyzer/ubiviz | 74 + utils/ccc-analyzer | 632 ------- utils/scan-build | 1297 ------------- utils/scanview.css | 62 - utils/sorttable.js | 493 ----- utils/ubiviz | 74 - www/analyzer/installation.html | 2 +- www/analyzer/latest_checker.html.incl | 2 +- www/cxx_status.html | 11 +- 529 files changed, 20353 insertions(+), 12610 deletions(-) delete mode 100644 include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h create mode 100644 include/clang/Frontend/LangStandard.h create mode 100644 include/clang/Frontend/LangStandards.def delete mode 100644 lib/Analysis/BadCallChecker.cpp create mode 100644 lib/Analysis/CallAndMessageChecker.cpp create mode 100644 lib/Analysis/Checker.cpp delete mode 100644 lib/Analysis/GRExprEngineInternalChecks.cpp create mode 100644 lib/Analysis/UndefBranchChecker.cpp create mode 100644 lib/Analysis/UndefResultChecker.cpp delete mode 100644 lib/Analysis/UndefinedArgChecker.cpp delete mode 100644 lib/CodeGen/CGCXXClass.cpp delete mode 100644 lib/CodeGen/CGCXXExpr.cpp delete mode 100644 lib/CodeGen/CGCXXTemp.cpp create mode 100644 lib/CodeGen/CGClass.cpp create mode 100644 lib/CodeGen/CGExprCXX.cpp create mode 100644 lib/CodeGen/CGTemporaries.cpp create mode 100644 lib/Frontend/LangStandards.cpp delete mode 100644 test/Analysis/region-only-test.c create mode 100644 test/CXX/basic/basic.link/p9.cpp create mode 100644 test/CXX/temp/temp.param/p9.cpp delete mode 100644 test/CodeCompletion/property.m delete mode 100644 test/CodeGen/builtins-ffs_parity_popcount.c delete mode 100644 test/CodeGen/builtins-powi.c create mode 100644 test/CodeGenCXX/condition.cpp create mode 100644 test/CodeGenCXX/conditional-temporaries.cpp create mode 100644 test/CodeGenCXX/const-global-linkage.cpp create mode 100644 test/CodeGenCXX/copy-assign-synthesis-2.cpp create mode 100644 test/CodeGenCXX/eh.cpp create mode 100644 test/CodeGenCXX/mangle-template.cpp create mode 100644 test/CodeGenCXX/member-pointer-cast.cpp create mode 100644 test/CodeGenCXX/member-templates.cpp create mode 100644 test/CodeGenCXX/new-with-default-arg.cpp delete mode 100644 test/CodeGenCXX/temp-1.cpp create mode 100644 test/CodeGenCXX/temp-order.cpp create mode 100644 test/CodeGenCXX/virt-dtor-key.cpp create mode 100644 test/CodeGenCXX/virtual-base-destructor-call.cpp create mode 100644 test/CodeGenCXX/virtual-bases.cpp create mode 100644 test/CodeGenCXX/virtual-functions-incomplete-types.cpp delete mode 100644 test/CodeGenObjC/class-obj-hidden-visibility.m delete mode 100644 test/CodeGenObjC/hidden-synthesized-ivar.m delete mode 100644 test/CodeGenObjC/protocol-definition-hidden-visibility.m create mode 100644 test/CodeGenObjC/sel-as-builtin-type.m create mode 100644 test/CodeGenObjC/undefined-protocol.m create mode 100644 test/FixIt/fixit-cxx0x.cpp delete mode 100644 test/Frontend/mmacosx-version-min-test.c create mode 100644 test/Frontend/output-failures.c create mode 100644 test/Index/c-index-api-fn-scan.m delete mode 100644 test/Index/c-index-api-test.m delete mode 100644 test/Index/c-index-pch.h delete mode 100644 test/Index/foo.h delete mode 100644 test/Index/objc.h delete mode 100644 test/Index/t1.c delete mode 100644 test/Index/t1.m delete mode 100644 test/Index/t2.c delete mode 100644 test/Index/t2.m create mode 100644 test/Lexer/constants-ms.c delete mode 100644 test/Misc/diag-checker.c create mode 100644 test/Parser/cxx-attributes.cpp delete mode 100644 test/Parser/cxx-parse-member-pointer-op.cpp create mode 100644 test/Parser/cxx0x-attributes.cpp create mode 100644 test/Parser/cxx0x-literal-operators.cpp create mode 100644 test/SemaCXX/alignof-sizeof-reference.cpp create mode 100644 test/SemaCXX/attr-cxx0x.cpp create mode 100644 test/SemaCXX/attr-sentinel.cpp create mode 100644 test/SemaCXX/member-pointers-2.cpp create mode 100644 test/SemaCXX/switch-0x.cpp create mode 100644 test/SemaTemplate/default-arguments-cxx0x.cpp create mode 100644 test/SemaTemplate/dependent-sized_array.cpp create mode 100644 test/SemaTemplate/overload-uneval.cpp create mode 100755 tools/scan-build/ccc-analyzer create mode 100755 tools/scan-build/scan-build create mode 100644 tools/scan-build/scanview.css create mode 100644 tools/scan-build/sorttable.js delete mode 100644 tools/wpa/CMakeLists.txt delete mode 100644 tools/wpa/Makefile delete mode 100644 tools/wpa/clang-wpa.cpp create mode 100644 utils/C++Tests/LLVM-Code-Compile/lit.local.cfg create mode 100644 utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg create mode 100755 utils/analyzer/ubiviz delete mode 100755 utils/ccc-analyzer delete mode 100755 utils/scan-build delete mode 100644 utils/scanview.css delete mode 100644 utils/sorttable.js delete mode 100755 utils/ubiviz diff --git a/Makefile b/Makefile index 17ccc73..9002123d 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ install-local:: 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` ; do \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \ if test \! -d "$$instdir" ; then \ $(EchoCmd) Making install directory $$instdir ; \ @@ -58,7 +58,7 @@ 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` ; do \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \ done ; \ fi diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index f0a2194..1ad7019 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -31,14 +31,14 @@ 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 /* CGCXXClass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.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 */; }; 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */; }; 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */; }; - 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */; }; + 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */; }; 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C01F6108128710072DEE4 /* CGRtti.cpp */; }; - 1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */; }; + 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 */; }; @@ -369,7 +369,7 @@ 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 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.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 = ""; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = ""; tabWidth = 2; }; @@ -378,9 +378,9 @@ 1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CodeCompleteConsumer.cpp; path = lib/Sema/CodeCompleteConsumer.cpp; sourceTree = ""; tabWidth = 2; }; 1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = ""; tabWidth = 2; }; 1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = ""; tabWidth = 2; }; - 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprCXX.cpp; path = lib/CodeGen/CGExprCXX.cpp; sourceTree = ""; tabWidth = 2; }; 1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = ""; tabWidth = 2; }; - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = ""; tabWidth = 2; }; + 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGTemporaries.cpp; path = lib/CodeGen/CGTemporaries.cpp; sourceTree = ""; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = ""; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = ""; }; 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = ""; }; @@ -1265,11 +1265,10 @@ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */, 35475B1F0E79973F0000BFE4 /* CGCall.cpp */, 35475B220E7997680000BFE4 /* CGCall.h */, + 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */, 1A5D5E570E5E81010023C059 /* CGCXX.cpp */, 1A649E1E0F9599DA005B965E /* CGCXX.h */, - 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */, - 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */, - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */, + 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */, 35A3E7000DD3874400757F74 /* CGDebugInfo.cpp */, 35A3E7010DD3874400757F74 /* CGDebugInfo.h */, DE4264FB0C113592005A861D /* CGDecl.cpp */, @@ -1287,6 +1286,7 @@ 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */, 1A6C01F6108128710072DEE4 /* CGRtti.cpp */, DE4772F90C10EAE5002239E8 /* CGStmt.cpp */, + 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */, 35475B230E7997680000BFE4 /* CGValue.h */, 1A81AA18108144F40094E50B /* CGVtable.cpp */, 1A81AA5D108278A20094E50B /* CGVtable.h */, @@ -1899,7 +1899,7 @@ 1A2A54C30FD1DD1C00F4CE45 /* RewriteTest.cpp in Sources */, 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */, 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */, - 1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */, + 1A6FE7090FD6F85800E00CA9 /* CGTemporaries.cpp in Sources */, BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */, 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */, @@ -1922,10 +1922,10 @@ 9012911D1048068D0083456D /* ASTUnit.cpp in Sources */, 90129121104812F90083456D /* CIndex.cpp in Sources */, 90F9EFAA104ABDED00D09A15 /* c-index-test.c in Sources */, - 1A4C41BF105B4C0B0047B5E7 /* CGCXXClass.cpp in Sources */, + 1A4C41BF105B4C0B0047B5E7 /* CGClass.cpp in Sources */, 1A6B6CD410693FC900BB4A8F /* CodeCompleteConsumer.cpp in Sources */, 1A6B6CD510693FC900BB4A8F /* SemaCodeComplete.cpp in Sources */, - 1A6B6E9A1069833600BB4A8F /* CGCXXExpr.cpp in Sources */, + 1A6B6E9A1069833600BB4A8F /* CGExprCXX.cpp in Sources */, 1A535ED9107BC45E000C3AE7 /* CXXInheritance.cpp in Sources */, 1A6C01F7108128710072DEE4 /* CGRtti.cpp in Sources */, 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f9d2f71..4f29e5d 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -120,8 +120,7 @@ class ASTContext { QualType ObjCIdTypedefType; /// ObjCSelType - another pseudo built-in typedef type (set by Sema). - QualType ObjCSelType; - const RecordType *SelStructType; + QualType ObjCSelTypedefType; /// ObjCProtoType - another pseudo built-in typedef type (set by Sema). QualType ObjCProtoType; @@ -244,6 +243,7 @@ public: // pseudo-builtins QualType ObjCIdRedefinitionType; QualType ObjCClassRedefinitionType; + QualType ObjCSelRedefinitionType; /// \brief Source ranges for all of the comments in the source file, /// sorted in order of appearance in the translation unit. @@ -316,7 +316,7 @@ public: CanQualType OverloadTy; CanQualType DependentTy; CanQualType UndeducedAutoTy; - CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy; + CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, @@ -532,8 +532,7 @@ public: QualType Canon = QualType()); QualType getTemplateSpecializationType(TemplateName T, - const TemplateArgumentLoc *Args, - unsigned NumArgs, + const TemplateArgumentListInfo &Args, QualType Canon = QualType()); QualType getQualifiedNameType(NestedNameSpecifier *NNS, @@ -696,7 +695,7 @@ public: void setObjCIdType(QualType T); void setObjCSelType(QualType T); - QualType getObjCSelType() const { return ObjCSelType; } + QualType getObjCSelType() const { return ObjCSelTypedefType; } void setObjCProtoType(QualType QT); QualType getObjCProtoType() const { return ObjCProtoType; } @@ -734,6 +733,8 @@ public: return getExtQualType(T, Qs); } + DeclarationName getNameForTemplate(TemplateName Name); + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template); @@ -796,6 +797,20 @@ public: return getTypeInfo(T).first; } + /// getByteWidth - Return the size of a byte, in bits + uint64_t getByteSize() { + return getTypeSize(CharTy); + } + + /// getTypeSizeInBytes - Return the size of the specified type, in bytes. + /// This method does not work on incomplete types. + uint64_t getTypeSizeInBytes(QualType T) { + return getTypeSize(T) / getByteSize(); + } + uint64_t getTypeSizeInBytes(const Type *T) { + return getTypeSize(T) / getByteSize(); + } + /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. /// This method does not work on incomplete types. unsigned getTypeAlign(QualType T) { @@ -811,10 +826,7 @@ public: /// a data type. unsigned getPreferredTypeAlign(const Type *T); - /// getDeclAlignInBytes - Return the alignment of the specified decl - /// that should be returned by __alignof(). Note that bitfields do - /// not have a valid alignment, so this method will assert on them. - unsigned getDeclAlignInBytes(const Decl *D); + unsigned getDeclAlignInBytes(const Decl *D, bool RefAsPointee = false); /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field @@ -1023,8 +1035,7 @@ public: return T == ObjCClassTypedefType; } bool isObjCSelType(QualType T) const { - assert(SelStructType && "isObjCSelType used before 'SEL' type is built"); - return T->getAsStructureType() == SelStructType; + return T == ObjCSelTypedefType; } bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index b36ff12..2c7ab9d 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -15,12 +15,12 @@ #define LLVM_CLANG_AST_ATTR_H #include "llvm/Support/Casting.h" -using llvm::dyn_cast; - +#include "llvm/ADT/StringRef.h" #include #include #include #include +using llvm::dyn_cast; namespace clang { class ASTContext; @@ -49,6 +49,7 @@ public: AnalyzerNoReturn, // Clang-specific. Annotate, AsmLabel, // Represent GCC asm label extension. + BaseCheck, Blocks, CDecl, Cleanup, @@ -59,9 +60,11 @@ public: Deprecated, Destructor, FastCall, + Final, Format, FormatArg, GNUInline, + Hiding, IBOutletKind, // Clang-specific. Use "Kind" suffix to not conflict with Malloc, NoDebug, @@ -71,6 +74,7 @@ public: NoThrow, ObjCException, ObjCNSObject, + Override, CFReturnsRetained, // Clang/Checker-specific. NSReturnsRetained, // Clang/Checker-specific. Overloadable, // Clang-specific @@ -184,12 +188,24 @@ public: class AlignedAttr : public Attr { unsigned Alignment; public: - AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} + AlignedAttr(unsigned alignment) + : Attr(Aligned), Alignment(alignment) {} /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } + + /// getMaxAlignment - Get the maximum alignment of attributes on this list. + unsigned getMaxAlignment() const { + const AlignedAttr *Next = getNext(); + if (Next) + return std::max(Next->getMaxAlignment(), Alignment); + else + return Alignment; + } - virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } + virtual Attr* clone(ASTContext &C) const { + return ::new (C) AlignedAttr(Alignment); + } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { @@ -201,7 +217,7 @@ public: class AnnotateAttr : public Attr { std::string Annotation; public: - AnnotateAttr(const std::string &ann) : Attr(Annotate), Annotation(ann) {} + AnnotateAttr(llvm::StringRef ann) : Attr(Annotate), Annotation(ann) {} const std::string& getAnnotation() const { return Annotation; } @@ -217,7 +233,7 @@ public: class AsmLabelAttr : public Attr { std::string Label; public: - AsmLabelAttr(const std::string &L) : Attr(AsmLabel), Label(L) {} + AsmLabelAttr(llvm::StringRef L) : Attr(AsmLabel), Label(L) {} const std::string& getLabel() const { return Label; } @@ -235,7 +251,7 @@ DEF_SIMPLE_ATTR(AlwaysInline); class AliasAttr : public Attr { std::string Aliasee; public: - AliasAttr(const std::string &aliasee) : Attr(Alias), Aliasee(aliasee) {} + AliasAttr(llvm::StringRef aliasee) : Attr(Alias), Aliasee(aliasee) {} const std::string& getAliasee() const { return Aliasee; } @@ -304,11 +320,12 @@ DEF_SIMPLE_ATTR(Malloc); DEF_SIMPLE_ATTR(NoReturn); DEF_SIMPLE_ATTR(AnalyzerNoReturn); DEF_SIMPLE_ATTR(Deprecated); +DEF_SIMPLE_ATTR(Final); class SectionAttr : public Attr { std::string Name; public: - SectionAttr(const std::string &N) : Attr(Section), Name(N) {} + SectionAttr(llvm::StringRef N) : Attr(Section), Name(N) {} const std::string& getName() const { return Name; } @@ -367,11 +384,11 @@ class FormatAttr : public Attr { std::string Type; int formatIdx, firstArg; public: - FormatAttr(const std::string &type, int idx, int first) : Attr(Format), + FormatAttr(llvm::StringRef type, int idx, int first) : Attr(Format), Type(type), formatIdx(idx), firstArg(first) {} const std::string& getType() const { return Type; } - void setType(const std::string &type) { Type = type; } + void setType(llvm::StringRef type) { Type = type; } int getFormatIdx() const { return formatIdx; } int getFirstArg() const { return firstArg; } @@ -544,6 +561,11 @@ public: DEF_SIMPLE_ATTR(CFReturnsRetained); DEF_SIMPLE_ATTR(NSReturnsRetained); +// C++0x member checking attributes. +DEF_SIMPLE_ATTR(BaseCheck); +DEF_SIMPLE_ATTR(Hiding); +DEF_SIMPLE_ATTR(Override); + #undef DEF_SIMPLE_ATTR } // end namespace clang diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ac79a91..f794477 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -54,6 +54,32 @@ public: TypeLoc getTypeLoc() const; }; +/// UnresolvedSet - A set of unresolved declarations. This is needed +/// in a lot of places, but isn't really worth breaking into its own +/// header right now. +class UnresolvedSet { + typedef llvm::SmallVector DeclsTy; + DeclsTy Decls; + +public: + void addDecl(NamedDecl *D) { + Decls.push_back(D); + } + + bool replace(const NamedDecl* Old, NamedDecl *New) { + for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) + if (*I == Old) + return (*I = New, true); + return false; + } + + unsigned size() const { return Decls.size(); } + + typedef DeclsTy::const_iterator iterator; + iterator begin() const { return Decls.begin(); } + iterator end() const { return Decls.end(); } +}; + /// TranslationUnitDecl - The top declaration context. class TranslationUnitDecl : public Decl, public DeclContext { ASTContext &Ctx; @@ -172,6 +198,26 @@ public: /// \brief Determine whether this declaration has linkage. bool hasLinkage() const; + /// \brief Describes the different kinds of linkage + /// (C++ [basic.link], C99 6.2.2) that an entity may have. + enum Linkage { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage + }; + + /// \brief Determine what kind of linkage this entity has. + Linkage getLinkage() const; + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for /// the underlying named decl. NamedDecl *getUnderlyingDecl(); diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 79f7663..e1f948f 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -503,12 +503,12 @@ private: /// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when /// doing something to a specific decl. class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { - Decl *TheDecl; + const Decl *TheDecl; SourceLocation Loc; SourceManager &SM; const char *Message; public: - PrettyStackTraceDecl(Decl *theDecl, SourceLocation L, + PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, SourceManager &sm, const char *Msg) : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index e5bf78c..990403e7 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -376,13 +376,13 @@ class CXXRecordDecl : public RecordDecl { /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a /// CXXConversionDecl. - OverloadedFunctionDecl Conversions; + UnresolvedSet Conversions; /// VisibleConversions - Overload set containing the conversion functions /// of this C++ class and all those inherited conversion functions that /// are visible in this class. Each of the entries in this overload set is /// a CXXConversionDecl or a FunctionTemplateDecl. - OverloadedFunctionDecl VisibleConversions; + UnresolvedSet VisibleConversions; /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. @@ -400,7 +400,7 @@ class CXXRecordDecl : public RecordDecl { const llvm::SmallPtrSet &TopConversionsTypeSet, const llvm::SmallPtrSet &HiddenConversionTypes); void collectConversionFunctions( - llvm::SmallPtrSet& ConversionsTypeSet); + llvm::SmallPtrSet& ConversionsTypeSet) const; protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -581,22 +581,34 @@ public: /// getConversions - Retrieve the overload set containing all of the /// conversion functions in this class. - OverloadedFunctionDecl *getConversionFunctions() { + UnresolvedSet *getConversionFunctions() { assert((this->isDefinition() || cast(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } - const OverloadedFunctionDecl *getConversionFunctions() const { + const UnresolvedSet *getConversionFunctions() const { assert((this->isDefinition() || cast(getTypeForDecl())->isBeingDefined()) && "getConversionFunctions() called on incomplete type"); return &Conversions; } + typedef UnresolvedSet::iterator conversion_iterator; + conversion_iterator conversion_begin() const { return Conversions.begin(); } + conversion_iterator conversion_end() const { return Conversions.end(); } + + /// Replaces a conversion function with a new declaration. + /// + /// Returns true if the old conversion was found. + bool replaceConversion(const NamedDecl* Old, NamedDecl *New) { + return Conversions.replace(Old, New); + } + /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. - OverloadedFunctionDecl *getVisibleConversionFunctions(); + const UnresolvedSet *getVisibleConversionFunctions(); + /// addVisibleConversionFunction - Add a new conversion function to the /// list of visible conversion functions. void addVisibleConversionFunction(CXXConversionDecl *ConvDecl); @@ -1502,9 +1514,9 @@ class UsingDirectiveDecl : public NamedDecl { SourceLocation IdentLoc; /// NominatedNamespace - Namespace nominated by using-directive. - NamespaceDecl *NominatedNamespace; + NamedDecl *NominatedNamespace; - /// Enclosing context containing both using-directive and nomintated + /// Enclosing context containing both using-directive and nominated /// namespace. DeclContext *CommonAncestor; @@ -1520,12 +1532,12 @@ class UsingDirectiveDecl : public NamedDecl { SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Nominated, + NamedDecl *Nominated, DeclContext *CommonAncestor) : NamedDecl(Decl::UsingDirective, DC, L, getName()), NamespaceLoc(NamespcLoc), QualifierRange(QualifierRange), Qualifier(Qualifier), IdentLoc(IdentLoc), - NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0), + NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) { } @@ -1538,8 +1550,13 @@ public: /// name of the namespace. NestedNameSpecifier *getQualifier() const { return Qualifier; } + NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; } + const NamedDecl *getNominatedNamespaceAsWritten() const { + return NominatedNamespace; + } + /// getNominatedNamespace - Returns namespace nominated by using-directive. - NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; } + NamespaceDecl *getNominatedNamespace(); const NamespaceDecl *getNominatedNamespace() const { return const_cast(this)->getNominatedNamespace(); @@ -1562,7 +1579,7 @@ public: SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Nominated, + NamedDecl *Nominated, DeclContext *CommonAncestor); static bool classof(const Decl *D) { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 14f6660..3ecc4bb 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -955,8 +955,7 @@ public: TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, - TemplateArgumentLoc *ArgInfos, - unsigned NumArgInfos, + const TemplateArgumentListInfo &ArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl); /// Get the list of template parameters diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index a30f6e8..676bd2c 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -25,6 +25,7 @@ namespace llvm { namespace clang { class CXXSpecialName; class CXXOperatorIdName; + class CXXLiteralOperatorIdName; class DeclarationNameExtra; class IdentifierInfo; class MultiKeywordSelector; @@ -48,6 +49,7 @@ public: CXXDestructorName, CXXConversionFunctionName, CXXOperatorName, + CXXLiteralOperatorName, CXXUsingDirective }; @@ -115,6 +117,12 @@ private: return 0; } + CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { + if (getNameKind() == CXXLiteralOperatorName) + return reinterpret_cast(Ptr & ~PtrMask); + return 0; + } + // Construct a declaration name from the name of a C++ constructor, // destructor, or conversion function. DeclarationName(CXXSpecialName *Name) @@ -131,6 +139,12 @@ private: Ptr |= StoredDeclarationNameExtra; } + DeclarationName(CXXLiteralOperatorIdName *Name) + : Ptr(reinterpret_cast(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + /// Construct a declaration name from a raw pointer. DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } @@ -201,7 +215,7 @@ public: N.Ptr = reinterpret_cast (P); return N; } - + static DeclarationName getFromOpaqueInteger(uintptr_t P) { DeclarationName N; N.Ptr = P; @@ -218,6 +232,10 @@ public: /// kind of overloaded operator. OverloadedOperatorKind getCXXOverloadedOperator() const; + /// getCXXLiteralIdentifier - If this name is the name of a literal + /// operator, retrieve the identifier associated with it. + IdentifierInfo *getCXXLiteralIdentifier() const; + /// getObjCSelector - Get the Objective-C selector stored in this /// declaration name. Selector getObjCSelector() const; @@ -293,7 +311,7 @@ public: /// getIdentifier - Create a declaration name that is a simple /// identifier. - DeclarationName getIdentifier(IdentifierInfo *ID) { + DeclarationName getIdentifier(const IdentifierInfo *ID) { return DeclarationName(ID); } @@ -324,6 +342,10 @@ public: /// getCXXOperatorName - Get the name of the overloadable C++ /// operator corresponding to Op. DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); + + /// getCXXLiteralOperatorName - Get the name of the literal operator function + /// with II as the identifier. + DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II); }; /// Insertion operator for diagnostics. This allows sending DeclarationName's diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index dfc5b13..7cf9aab 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -35,6 +35,7 @@ namespace clang { class CXXOperatorCallExpr; class CXXMemberCallExpr; class TemplateArgumentLoc; + class TemplateArgumentListInfo; /// 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 @@ -366,6 +367,10 @@ struct ExplicitTemplateArgumentList { const TemplateArgumentLoc *getTemplateArgs() const { return reinterpret_cast (this + 1); } + + void initializeFrom(const TemplateArgumentListInfo &List); + void copyInto(TemplateArgumentListInfo &List) const; + static std::size_t sizeFor(const TemplateArgumentListInfo &List); }; /// DeclRefExpr - [C99 6.5.1p2] - A reference to a declared variable, function, @@ -423,31 +428,24 @@ class DeclRefExpr : public Expr { DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD); + const TemplateArgumentListInfo *TemplateArgs, + QualType T); protected: - // FIXME: Eventually, this constructor will go away and all subclasses - // will have to provide the type- and value-dependent flags. - DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : - Expr(SC, t), DecoratedD(d, 0), Loc(l) {} + /// \brief Computes the type- and value-dependence flags for this + /// declaration reference expression. + void computeDependence(); - DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD, - bool VD) : - Expr(SC, t, TD, VD), DecoratedD(d, 0), Loc(l) {} + DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) : + Expr(SC, t, false, false), DecoratedD(d, 0), Loc(l) { + computeDependence(); + } public: - // FIXME: Eventually, this constructor will go away and all clients - // will have to provide the type- and value-dependent flags. DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l) : - Expr(DeclRefExprClass, t), DecoratedD(d, 0), Loc(l) {} - - DeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, bool VD) : - Expr(DeclRefExprClass, t, TD, VD), DecoratedD(d, 0), Loc(l) {} + Expr(DeclRefExprClass, t, false, false), DecoratedD(d, 0), Loc(l) { + computeDependence(); + } /// \brief Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) @@ -458,19 +456,8 @@ public: SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - QualType T, bool TD, bool VD); - - static DeclRefExpr *Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - NamedDecl *D, - SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD); + QualType T, + const TemplateArgumentListInfo *TemplateArgs = 0); NamedDecl *getDecl() { return DecoratedD.getPointer(); } const NamedDecl *getDecl() const { return DecoratedD.getPointer(); } @@ -508,6 +495,13 @@ public: bool hasExplicitTemplateArgumentList() const { return DecoratedD.getInt() & HasExplicitTemplateArgumentListFlag; } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. @@ -546,8 +540,7 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == DeclRefExprClass || - T->getStmtClass() == CXXConditionDeclExprClass; + return T->getStmtClass() == DeclRefExprClass; } static bool classof(const DeclRefExpr *) { return true; } @@ -1313,9 +1306,7 @@ class MemberExpr : public Expr { MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, SourceLocation langle, - const TemplateArgumentLoc *targs, unsigned numtargs, - SourceLocation rangle, QualType ty); + const TemplateArgumentListInfo *targs, QualType ty); public: MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l, @@ -1334,11 +1325,7 @@ public: NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, - unsigned numtargs, - SourceLocation rangle, + const TemplateArgumentListInfo *targs, QualType ty); void setBase(Expr *E) { Base = E; } @@ -1378,10 +1365,17 @@ public: /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f. - bool hasExplicitTemplateArgumentList() { + bool hasExplicitTemplateArgumentList() const { return HasExplicitTemplateArgumentList; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } + /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { @@ -1579,7 +1573,11 @@ public: CK_FloatingToIntegral, /// CK_FloatingCast - Casting between floating types of different size. - CK_FloatingCast + CK_FloatingCast, + + /// CK_MemberPointerToBoolean - Member pointer to boolean + CK_MemberPointerToBoolean + }; private: diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 9e6fd4f..23844ce 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -17,6 +17,7 @@ #include "clang/Basic/TypeTraits.h" #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" namespace clang { @@ -24,6 +25,7 @@ namespace clang { class CXXDestructorDecl; class CXXMethodDecl; class CXXTemporary; + class TemplateArgumentListInfo; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -669,40 +671,6 @@ public: virtual child_iterator child_end(); }; -/// CXXConditionDeclExpr - Condition declaration of a if/switch/while/for -/// statement, e.g: "if (int x = f()) {...}". -/// The main difference with DeclRefExpr is that CXXConditionDeclExpr owns the -/// decl that it references. -/// -class CXXConditionDeclExpr : public DeclRefExpr { -public: - CXXConditionDeclExpr(SourceLocation startLoc, - SourceLocation eqLoc, VarDecl *var) - : DeclRefExpr(CXXConditionDeclExprClass, var, - var->getType().getNonReferenceType(), startLoc, - var->getType()->isDependentType(), - /*FIXME:integral constant?*/ - var->getType()->isDependentType()) {} - - SourceLocation getStartLoc() const { return getLocation(); } - - VarDecl *getVarDecl() { return cast(getDecl()); } - const VarDecl *getVarDecl() const { return cast(getDecl()); } - - virtual SourceRange getSourceRange() const { - return SourceRange(getStartLoc(), getVarDecl()->getInit()->getLocEnd()); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXConditionDeclExprClass; - } - static bool classof(const CXXConditionDeclExpr *) { return true; } - - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; - /// CXXNewExpr - A new expression for memory allocation and constructor calls, /// e.g: "new CXXNewExpr(foo)". class CXXNewExpr : public Expr { @@ -975,52 +943,6 @@ public: virtual child_iterator child_end(); }; -/// \brief Represents the name of a function that has not been -/// resolved to any declaration. -/// -/// Unresolved function names occur when a function name is -/// encountered prior to an open parentheses ('(') in a C++ function -/// call, and the function name itself did not resolve to a -/// declaration. These function names can only be resolved when they -/// form the postfix-expression of a function call, so that -/// argument-dependent lookup finds declarations corresponding to -/// these functions. - -/// @code -/// template void f(T x) { -/// g(x); // g is an unresolved function name (that is also a dependent name) -/// } -/// @endcode -class UnresolvedFunctionNameExpr : public Expr { - /// The name that was present in the source - DeclarationName Name; - - /// The location of this name in the source code - SourceLocation Loc; - -public: - UnresolvedFunctionNameExpr(DeclarationName N, QualType T, SourceLocation L) - : Expr(UnresolvedFunctionNameExprClass, T, false, false), Name(N), Loc(L) { } - - /// \brief Retrieves the name that occurred in the source code. - DeclarationName getName() const { return Name; } - - /// getLocation - Retrieves the location in the source code where - /// the name occurred. - SourceLocation getLocation() const { return Loc; } - - virtual SourceRange getSourceRange() const { return SourceRange(Loc); } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == UnresolvedFunctionNameExprClass; - } - static bool classof(const UnresolvedFunctionNameExpr *) { return true; } - - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); -}; - /// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the /// implementation of TR1/C++0x type trait templates. /// Example: @@ -1063,21 +985,177 @@ public: virtual child_iterator child_end(); }; +/// \brief A reference to a name which we were able to look up during +/// parsing but could not resolve to a specific declaration. This +/// arises in several ways: +/// * we might be waiting for argument-dependent lookup +/// * the name might resolve to an overloaded function +/// and eventually: +/// * the lookup might have included a function template +/// These never include UnresolvedUsingValueDecls, which are always +/// class members and therefore appear only in +/// UnresolvedMemberLookupExprs. +class UnresolvedLookupExpr : public Expr { + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. + UnresolvedSet Results; + + /// The name declared. + DeclarationName Name; + + /// The qualifier given, if any. + NestedNameSpecifier *Qualifier; + + /// The source range of the nested name specifier. + SourceRange QualifierRange; + + /// The location of the name. + SourceLocation NameLoc; + + /// True if these lookup results should be extended by + /// argument-dependent lookup if this is the operand of a function + /// call. + bool RequiresADL; + + /// True if these lookup results are overloaded. This is pretty + /// trivially rederivable if we urgently need to kill this field. + bool Overloaded; + + /// True if the name looked up had explicit template arguments. + /// This requires all the results to be function templates. + bool HasExplicitTemplateArgs; + + UnresolvedLookupExpr(QualType T, bool Dependent, + NestedNameSpecifier *Qualifier, SourceRange QRange, + DeclarationName Name, SourceLocation NameLoc, + bool RequiresADL, bool Overloaded, bool HasTemplateArgs) + : Expr(UnresolvedLookupExprClass, T, Dependent, Dependent), + Name(Name), Qualifier(Qualifier), QualifierRange(QRange), + NameLoc(NameLoc), RequiresADL(RequiresADL), Overloaded(Overloaded), + HasExplicitTemplateArgs(HasTemplateArgs) + {} + +public: + static UnresolvedLookupExpr *Create(ASTContext &C, + bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool ADL, bool Overloaded) { + return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + Dependent, Qualifier, QualifierRange, + Name, NameLoc, ADL, Overloaded, false); + } + + static UnresolvedLookupExpr *Create(ASTContext &C, + bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool ADL, + const TemplateArgumentListInfo &Args); + + /// Computes whether an unresolved lookup on the given declarations + /// and optional template arguments is type- and value-dependent. + static bool ComputeDependence(NamedDecl * const *Begin, + NamedDecl * const *End, + const TemplateArgumentListInfo *Args); + + void addDecl(NamedDecl *Decl) { + Results.addDecl(Decl); + } + + typedef UnresolvedSet::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + /// True if this declaration should be extended by + /// argument-dependent lookup. + bool requiresADL() const { return RequiresADL; } + + /// True if this lookup is overloaded. + bool isOverloaded() const { return Overloaded; } + + /// Fetches the name looked up. + DeclarationName getName() const { return Name; } + + /// Gets the location of the name. + SourceLocation getNameLoc() const { return NameLoc; } + + /// Fetches the nested-name qualifier, if one was given. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// Fetches the range of the nested-name qualifier. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } + + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. + + /// Gets a reference to the explicit template argument list. + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast(this + 1); + } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs().LAngleLoc; + } + + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs().RAngleLoc; + } + + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } + + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } + + virtual SourceRange getSourceRange() const { + SourceRange Range(NameLoc); + if (Qualifier) Range.setBegin(QualifierRange.getBegin()); + if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); + return Range; + } + + virtual StmtIterator child_begin(); + virtual StmtIterator child_end(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass; + } + static bool classof(const UnresolvedLookupExpr *) { return true; } +}; + /// \brief A qualified reference to a name whose declaration cannot /// yet be resolved. /// -/// UnresolvedDeclRefExpr is similar to eclRefExpr in that +/// DependentScopeDeclRefExpr is similar to DeclRefExpr in that /// it expresses a reference to a declaration such as /// X::value. The difference, however, is that an -/// UnresolvedDeclRefExpr node is used only within C++ templates when +/// DependentScopeDeclRefExpr node is used only within C++ templates when /// the qualification (e.g., X::) refers to a dependent type. In /// this case, X::value cannot resolve to a declaration because the /// declaration will differ from on instantiation of X to the -/// next. Therefore, UnresolvedDeclRefExpr keeps track of the +/// next. Therefore, DependentScopeDeclRefExpr keeps track of the /// qualifier (X::) and the name of the entity being referenced /// ("value"). Such expressions will instantiate to a DeclRefExpr once the /// declaration can be found. -class UnresolvedDeclRefExpr : public Expr { +class DependentScopeDeclRefExpr : public Expr { /// The name of the entity we will be referencing. DeclarationName Name; @@ -1090,19 +1168,30 @@ class UnresolvedDeclRefExpr : public Expr { /// \brief The nested-name-specifier that qualifies this unresolved /// declaration name. - NestedNameSpecifier *NNS; + NestedNameSpecifier *Qualifier; - /// \brief Whether this expr is an address of (&) operand. - /// FIXME: Stash this bit into NNS! - bool IsAddressOfOperand; + /// \brief Whether the name includes explicit template arguments. + bool HasExplicitTemplateArgs; + + DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + bool HasExplicitTemplateArgs) + : Expr(DependentScopeDeclRefExprClass, T, true, true), + Name(Name), Loc(NameLoc), + QualifierRange(QualifierRange), Qualifier(Qualifier), + HasExplicitTemplateArgs(HasExplicitTemplateArgs) + {} public: - UnresolvedDeclRefExpr(DeclarationName N, QualType T, SourceLocation L, - SourceRange R, NestedNameSpecifier *NNS, - bool IsAddressOfOperand) - : Expr(UnresolvedDeclRefExprClass, T, true, true), - Name(N), Loc(L), QualifierRange(R), NNS(NNS), - IsAddressOfOperand(IsAddressOfOperand) { } + static DependentScopeDeclRefExpr *Create(ASTContext &C, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs = 0); /// \brief Retrieve the name that this expression refers to. DeclarationName getDeclName() const { return Name; } @@ -1115,116 +1204,57 @@ public: /// \brief Retrieve the nested-name-specifier that qualifies this /// declaration. - NestedNameSpecifier *getQualifier() const { return NNS; } - - /// \brief Retrieve whether this is an address of (&) operand. - - bool isAddressOfOperand() const { return IsAddressOfOperand; } - virtual SourceRange getSourceRange() const { - return SourceRange(QualifierRange.getBegin(), getLocation()); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == UnresolvedDeclRefExprClass; - } - static bool classof(const UnresolvedDeclRefExpr *) { return true; } - - virtual StmtIterator child_begin(); - virtual StmtIterator child_end(); -}; - -/// \brief An expression that refers to a C++ template-id, such as -/// @c isa. -class TemplateIdRefExpr : public Expr { - /// \brief If this template-id was qualified-id, e.g., @c std::sort, - /// this nested name specifier contains the @c std::. - NestedNameSpecifier *Qualifier; - - /// \brief If this template-id was a qualified-id, e.g., @c std::sort, - /// this covers the source code range of the @c std::. - SourceRange QualifierRange; - - /// \brief The actual template to which this template-id refers. - TemplateName Template; - - /// \brief The source location of the template name. - SourceLocation TemplateNameLoc; - - /// \brief The source location of the left angle bracket ('<'); - SourceLocation LAngleLoc; - - /// \brief The source location of the right angle bracket ('>'); - SourceLocation RAngleLoc; - - /// \brief The number of template arguments in TemplateArgs. - unsigned NumTemplateArgs; - - TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); - - virtual void DoDestroy(ASTContext &Context); - -public: - static TemplateIdRefExpr * - Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, SourceLocation RAngleLoc); - - /// \brief Retrieve the nested name specifier used to qualify the name of - /// this template-id, e.g., the "std::sort" in @c std::sort, or NULL - /// if this template-id was an unqualified-id. NestedNameSpecifier *getQualifier() const { return Qualifier; } - /// \brief Retrieve the source range describing the nested name specifier - /// used to qualified the name of this template-id, if the name was qualified. - SourceRange getQualifierRange() const { return QualifierRange; } + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } - /// \brief Retrieve the name of the template referenced, e.g., "sort" in - /// @c std::sort; - TemplateName getTemplateName() const { return Template; } + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. - /// \brief Retrieve the location of the name of the template referenced, e.g., - /// the location of "sort" in @c std::sort. - SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; } + /// Gets a reference to the explicit template argument list. + const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast(this + 1); + } - /// \brief Retrieve the location of the left angle bracket following the - /// template name ('<'). - SourceLocation getLAngleLoc() const { return LAngleLoc; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs().LAngleLoc; + } - /// \brief Retrieve the template arguments provided as part of this - /// template-id. - const TemplateArgumentLoc *getTemplateArgs() const { - return reinterpret_cast(this + 1); + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs().RAngleLoc; } - /// \brief Retrieve the number of template arguments provided as part of this - /// template-id. - unsigned getNumTemplateArgs() const { return NumTemplateArgs; } + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } - /// \brief Retrieve the location of the right angle bracket following the - /// template arguments ('>'). - SourceLocation getRAngleLoc() const { return RAngleLoc; } + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } virtual SourceRange getSourceRange() const { - return SourceRange(Qualifier? QualifierRange.getBegin() : TemplateNameLoc, - RAngleLoc); + SourceRange Range(QualifierRange.getBegin(), getLocation()); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + return Range; } - // Iterators - virtual child_iterator child_begin(); - virtual child_iterator child_end(); - static bool classof(const Stmt *T) { - return T->getStmtClass() == TemplateIdRefExprClass; + return T->getStmtClass() == DependentScopeDeclRefExprClass; } - static bool classof(const TemplateIdRefExpr *) { return true; } + static bool classof(const DependentScopeDeclRefExpr *) { return true; } + + virtual StmtIterator child_begin(); + virtual StmtIterator child_end(); }; class CXXExprWithTemporaries : public Expr { @@ -1377,10 +1407,10 @@ public: virtual child_iterator child_end(); }; -/// \brief Represents a C++ member access expression where the actual member -/// referenced could not be resolved, e.g., because the base expression or the -/// member name was dependent. -class CXXUnresolvedMemberExpr : public Expr { +/// \brief Represents a C++ member access expression where the actual +/// member referenced could not be resolved because the base +/// expression or the member name was dependent. +class CXXDependentScopeMemberExpr : public Expr { /// \brief The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Stmt *Base; @@ -1408,7 +1438,7 @@ class CXXUnresolvedMemberExpr : public Expr { /// /// FIXME: This member, along with the Qualifier and QualifierRange, could /// be stuck into a structure that is optionally allocated at the end of - /// the CXXUnresolvedMemberExpr, to save space in the common case. + /// the CXXDependentScopeMemberExpr, to save space in the common case. NamedDecl *FirstQualifierFoundInScope; /// \brief The member to which this member expression refers, which @@ -1431,11 +1461,11 @@ class CXXUnresolvedMemberExpr : public Expr { /// \brief Retrieve the explicit template argument list that followed the /// member template name, if any. const ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() const { - return const_cast(this) + return const_cast(this) ->getExplicitTemplateArgumentList(); } - CXXUnresolvedMemberExpr(ASTContext &C, + CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1443,14 +1473,10 @@ class CXXUnresolvedMemberExpr : public Expr { NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo *TemplateArgs); public: - CXXUnresolvedMemberExpr(ASTContext &C, + CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1458,14 +1484,14 @@ public: NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc) - : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { } - static CXXUnresolvedMemberExpr * + static CXXDependentScopeMemberExpr * Create(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, @@ -1474,11 +1500,7 @@ public: NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo *TemplateArgs); /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. @@ -1529,10 +1551,17 @@ public: /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f. - bool hasExplicitTemplateArgumentList() { + bool hasExplicitTemplateArgumentList() const { return HasExplicitTemplateArgumentList; } + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgumentList()) + getExplicitTemplateArgumentList()->copyInto(List); + } + /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { @@ -1579,9 +1608,182 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXUnresolvedMemberExprClass; + return T->getStmtClass() == CXXDependentScopeMemberExprClass; + } + static bool classof(const CXXDependentScopeMemberExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// \brief Represents a C++ member access expression for which lookup +/// produced a set of overloaded functions. These are replaced with +/// MemberExprs in the final AST. +class UnresolvedMemberExpr : public Expr { + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. + UnresolvedSet Results; + + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. + Stmt *Base; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether the lookup results contain an unresolved using + /// declaration. + bool HasUnresolvedUsing : 1; + + /// \brief Whether this member expression has explicitly-specified template + /// arguments. + bool HasExplicitTemplateArgs : 1; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifier *Qualifier; + + /// \brief The source range covering the nested name specifier. + SourceRange QualifierRange; + + /// \brief The member to which this member expression refers, which + /// can be a name or an overloaded operator. + DeclarationName MemberName; + + /// \brief The location of the member name. + SourceLocation MemberLoc; + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + ExplicitTemplateArgumentList *getExplicitTemplateArgs() { + assert(HasExplicitTemplateArgs); + return reinterpret_cast(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const { + return const_cast(this)->getExplicitTemplateArgs(); + } + + UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + +public: + static UnresolvedMemberExpr * + Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + + /// Adds a declaration to the unresolved set. By assumption, all of + /// these happen at initialization time and properties like + /// 'Dependent' and 'HasUnresolvedUsing' take them into account. + void addDecl(NamedDecl *Decl) { + Results.addDecl(Decl); + } + + typedef UnresolvedSet::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + unsigned getNumDecls() const { return Results.size(); } + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { return cast(Base); } + void setBase(Expr *E) { Base = E; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Retrieve the source range covering the nested-name-specifier + /// that qualifies the member name. + SourceRange getQualifierRange() const { return QualifierRange; } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMemberName() const { return MemberName; } + void setMemberName(DeclarationName N) { MemberName = N; } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f. + bool hasExplicitTemplateArgs() const { + return HasExplicitTemplateArgs; + } + + /// \brief Copies the template arguments into the given structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs()->copyInto(List); + } + + /// \brief Retrieve the location of the left angle bracket following + /// the member name ('<'). + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + return getExplicitTemplateArgs()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as + /// part of this template-id. + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket + /// following the template arguments ('>'). + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs()->RAngleLoc; + } + + virtual SourceRange getSourceRange() const { + SourceRange Range = Base->getSourceRange(); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberLoc); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedMemberExprClass; } - static bool classof(const CXXUnresolvedMemberExpr *) { return true; } + static bool classof(const UnresolvedMemberExpr *) { return true; } // Iterators virtual child_iterator child_begin(); diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index 9b1c640..5d2973e 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -47,6 +47,59 @@ class ASTRecordLayout { // FieldCount - Number of fields. unsigned FieldCount; +public: + /// PrimaryBaseInfo - Contains info about a primary base. + struct PrimaryBaseInfo { + PrimaryBaseInfo() {} + + PrimaryBaseInfo(const CXXRecordDecl *Base, bool IsVirtual) + : Value(Base, IsVirtual) {} + + /// Value - Points to the primary base. The single-bit value + /// will be non-zero when the primary base is virtual. + llvm::PointerIntPair Value; + + /// getBase - Returns the primary base. + const CXXRecordDecl *getBase() const { return Value.getPointer(); } + + /// isVirtual - Returns whether the primary base is virtual or not. + bool isVirtual() const { return Value.getInt(); } + + friend bool operator==(const PrimaryBaseInfo &X, const PrimaryBaseInfo &Y) { + return X.Value == Y.Value; + } + }; + + /// primary_base_info_iterator - An iterator for iterating the primary base + /// class chain. + class primary_base_info_iterator { + /// Current - The current base class info. + PrimaryBaseInfo Current; + + public: + primary_base_info_iterator() {} + primary_base_info_iterator(PrimaryBaseInfo Info) : Current(Info) {} + + const PrimaryBaseInfo &operator*() const { return Current; } + + primary_base_info_iterator& operator++() { + const CXXRecordDecl *RD = Current.getBase(); + Current = RD->getASTContext().getASTRecordLayout(RD).getPrimaryBaseInfo(); + return *this; + } + + friend bool operator==(const primary_base_info_iterator &X, + const primary_base_info_iterator &Y) { + return X.Current == Y.Current; + } + friend bool operator!=(const primary_base_info_iterator &X, + const primary_base_info_iterator &Y) { + return !(X == Y); + } + }; + +private: + /// CXXRecordLayoutInfo - Contains C++ specific layout information. struct CXXRecordLayoutInfo { /// NonVirtualSize - The non-virtual size (in bits) of an object, which is /// the size of the object without virtual bases. @@ -56,11 +109,9 @@ class ASTRecordLayout { /// which is the alignment of the object without virtual bases. uint64_t NonVirtualAlign; - /// PrimaryBase - The primary base for our vtable. - const CXXRecordDecl *PrimaryBase; - /// PrimaryBase - Wether or not the primary base was a virtual base. - bool PrimaryBaseWasVirtual; - + /// PrimaryBase - The primary base info for this record. + PrimaryBaseInfo PrimaryBase; + /// BaseOffsets - Contains a map from base classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap BaseOffsets; @@ -68,6 +119,13 @@ class ASTRecordLayout { /// VBaseOffsets - Contains a map from vbase classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) llvm::DenseMap VBaseOffsets; + + /// KeyFunction - The key function, according to the Itanium C++ ABI, + /// section 5.2.3: + /// + /// ...the first non-pure virtual function that is not inline at the point + /// of class definition. + const CXXMethodDecl *KeyFunction; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -92,11 +150,12 @@ class ASTRecordLayout { ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize, const uint64_t *fieldoffsets, unsigned fieldcount, uint64_t nonvirtualsize, unsigned nonvirtualalign, - const CXXRecordDecl *PB, bool PBVirtual, + const PrimaryBaseInfo &PrimaryBase, const std::pair *bases, unsigned numbases, const std::pair *vbases, - unsigned numvbases) + unsigned numvbases, + const CXXMethodDecl *KeyFunction) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { if (FieldCount > 0) { @@ -105,14 +164,14 @@ class ASTRecordLayout { FieldOffsets[i] = fieldoffsets[i]; } - CXXInfo->PrimaryBase = PB; - CXXInfo->PrimaryBaseWasVirtual = PBVirtual; + CXXInfo->PrimaryBase = PrimaryBase; CXXInfo->NonVirtualSize = nonvirtualsize; CXXInfo->NonVirtualAlign = nonvirtualalign; for (unsigned i = 0; i != numbases; ++i) CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; for (unsigned i = 0; i != numvbases; ++i) CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; + CXXInfo->KeyFunction = KeyFunction; } ~ASTRecordLayout() { @@ -162,17 +221,21 @@ public: return CXXInfo->NonVirtualAlign; } - /// getPrimaryBase - Get the primary base. - const CXXRecordDecl *getPrimaryBase() const { + /// getPrimaryBaseInfo - Get the primary base info. + const PrimaryBaseInfo &getPrimaryBaseInfo() const { assert(CXXInfo && "Record layout does not have C++ specific info!"); return CXXInfo->PrimaryBase; } - /// getPrimaryBaseWasVirtual - Indicates if the primary base was virtual. - bool getPrimaryBaseWasVirtual() const { - assert(CXXInfo && "Record layout does not have C++ specific info!"); - return CXXInfo->PrimaryBaseWasVirtual; + // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. + const CXXRecordDecl *getPrimaryBase() const { + return getPrimaryBaseInfo().getBase(); + } + + // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. + bool getPrimaryBaseWasVirtual() const { + return getPrimaryBaseInfo().isVirtual(); } /// getBaseClassOffset - Get the offset, in bits, for the given base class. @@ -190,6 +253,25 @@ public: return CXXInfo->VBaseOffsets[VBase]; } + + /// getKeyFunction - Get the key function. + const CXXMethodDecl *getKeyFunction() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->KeyFunction; + } + + primary_base_info_iterator primary_base_begin() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return primary_base_info_iterator(getPrimaryBaseInfo()); + } + + primary_base_info_iterator primary_base_end() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return primary_base_info_iterator(); + } }; } // end namespace clang diff --git a/include/clang/AST/Redeclarable.h b/include/clang/AST/Redeclarable.h index 8679323..01f4b29 100644 --- a/include/clang/AST/Redeclarable.h +++ b/include/clang/AST/Redeclarable.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_AST_REDECLARABLE_H #include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" #include namespace clang { @@ -92,6 +93,11 @@ public: } /// \brief Returns the most recent (re)declaration of this declaration. + decl_type *getMostRecentDeclaration() { + return getFirstDeclaration()->RedeclLink.getNext(); + } + + /// \brief Returns the most recent (re)declaration of this declaration. const decl_type *getMostRecentDeclaration() const { return getFirstDeclaration()->RedeclLink.getNext(); } @@ -102,8 +108,11 @@ public: decl_type *First; if (PrevDecl) { - // Point to previous. - RedeclLink = PreviousDeclLink(PrevDecl); + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + RedeclLink = PreviousDeclLink(llvm::cast( + PrevDecl->getMostRecentDeclaration())); First = PrevDecl->getFirstDeclaration(); assert(First->RedeclLink.NextIsLatest() && "Expected first"); } else { diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 411f215e..d6f6a83 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -171,6 +171,14 @@ public: } virtual ~Stmt() {} +#ifndef NDEBUG + /// \brief True if this statement's refcount is in a valid state. + /// Should be used only in assertions. + bool isRetained() const { + return (RefCount >= 1); + } +#endif + /// \brief Destroy the current statement and its children. void Destroy(ASTContext &Ctx) { assert(RefCount >= 1); @@ -203,7 +211,7 @@ public: // global temp stats (until we have a per-module visitor) static void addStmtClass(const StmtClass s); - static bool CollectingStats(bool enable=false); + static bool CollectingStats(bool Enable = false); static void PrintStats(); /// dump - This does a local dump of the specified AST fragment. It dumps the @@ -604,22 +612,36 @@ public: class IfStmt : public Stmt { enum { COND, THEN, ELSE, END_EXPR }; Stmt* SubExprs[END_EXPR]; + + /// \brief If non-NULL, the declaration in the "if" statement. + VarDecl *Var; + SourceLocation IfLoc; SourceLocation ElseLoc; + public: - IfStmt(SourceLocation IL, Expr *cond, Stmt *then, + IfStmt(SourceLocation IL, VarDecl *Var, Expr *cond, Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0) - : Stmt(IfStmtClass) { + : Stmt(IfStmtClass), Var(Var), IfLoc(IL), ElseLoc(EL) { SubExprs[COND] = reinterpret_cast(cond); SubExprs[THEN] = then; SubExprs[ELSE] = elsev; - IfLoc = IL; - ElseLoc = EL; } /// \brief Build an empty if/then/else statement explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "if" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// if (int x = foo()) { + /// printf("x is %d", x); + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(E); } const Stmt *getThen() const { return SubExprs[THEN]; } @@ -658,6 +680,7 @@ public: class SwitchStmt : public Stmt { enum { COND, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; + VarDecl *Var; // This points to a linked list of case and default statements. SwitchCase *FirstCase; SourceLocation SwitchLoc; @@ -666,14 +689,28 @@ protected: virtual void DoDestroy(ASTContext &Ctx); public: - SwitchStmt(Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { - SubExprs[COND] = reinterpret_cast(cond); - SubExprs[BODY] = NULL; - } + SwitchStmt(VarDecl *Var, Expr *cond) + : Stmt(SwitchStmtClass), Var(Var), FirstCase(0) + { + SubExprs[COND] = reinterpret_cast(cond); + SubExprs[BODY] = NULL; + } /// \brief Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]);} const Stmt *getBody() const { return SubExprs[BODY]; } const SwitchCase *getSwitchCaseList() const { return FirstCase; } @@ -721,10 +758,13 @@ public: /// class WhileStmt : public Stmt { enum { COND, BODY, END_EXPR }; + VarDecl *Var; Stmt* SubExprs[END_EXPR]; SourceLocation WhileLoc; public: - WhileStmt(Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) { + WhileStmt(VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) + : Stmt(WhileStmtClass), Var(Var) + { SubExprs[COND] = reinterpret_cast(cond); SubExprs[BODY] = body; WhileLoc = WL; @@ -733,6 +773,17 @@ public: /// \brief Build an empty while statement. explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + /// \brief Retrieve the variable declared in this "while" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// while (int x = random()) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]);} void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(E); } @@ -812,26 +863,38 @@ public: class ForStmt : public Stmt { enum { INIT, COND, INC, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + VarDecl *CondVar; SourceLocation ForLoc; SourceLocation LParenLoc, RParenLoc; public: - ForStmt(Stmt *Init, Expr *Cond, Expr *Inc, Stmt *Body, SourceLocation FL, - SourceLocation LP, SourceLocation RP) - : Stmt(ForStmtClass) { + ForStmt(Stmt *Init, Expr *Cond, VarDecl *CondVar, Expr *Inc, Stmt *Body, + SourceLocation FL, SourceLocation LP, SourceLocation RP) + : Stmt(ForStmtClass), CondVar(CondVar), ForLoc(FL), LParenLoc(LP), + RParenLoc(RP) + { SubExprs[INIT] = Init; SubExprs[COND] = reinterpret_cast(Cond); SubExprs[INC] = reinterpret_cast(Inc); SubExprs[BODY] = Body; - ForLoc = FL; - LParenLoc = LP; - RParenLoc = RP; } /// \brief Build an empty for statement. explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } Stmt *getInit() { return SubExprs[INIT]; } + + /// \brief Retrieve the variable declared in this "for" statement, if any. + /// + /// In the following example, "y" is the condition variable. + /// \code + /// for (int x = random(); int y = mangle(x); ++x) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return CondVar; } + void setConditionVariable(VarDecl *V) { CondVar = V; } + Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } Expr *getInc() { return reinterpret_cast(SubExprs[INC]); } Stmt *getBody() { return SubExprs[BODY]; } diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 28fe348..64eea24 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -42,9 +42,9 @@ public: } SourceLocation getCatchLoc() const { return CatchLoc; } - VarDecl *getExceptionDecl() { return ExceptionDecl; } - QualType getCaughtType(); - Stmt *getHandlerBlock() { return HandlerBlock; } + VarDecl *getExceptionDecl() const { return ExceptionDecl; } + QualType getCaughtType() const; + Stmt *getHandlerBlock() const { return HandlerBlock; } static bool classof(const Stmt *T) { return T->getStmtClass() == CXXCatchStmtClass; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 034029a..7102336 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -121,20 +121,19 @@ EXPR(CXXThisExpr , Expr) EXPR(CXXThrowExpr , Expr) EXPR(CXXDefaultArgExpr , Expr) EXPR(CXXZeroInitValueExpr , Expr) -EXPR(CXXConditionDeclExpr , DeclRefExpr) EXPR(CXXNewExpr , Expr) EXPR(CXXDeleteExpr , Expr) EXPR(CXXPseudoDestructorExpr, Expr) -EXPR(UnresolvedFunctionNameExpr , Expr) +EXPR(UnresolvedLookupExpr , Expr) EXPR(UnaryTypeTraitExpr , Expr) -EXPR(UnresolvedDeclRefExpr , Expr) -EXPR(TemplateIdRefExpr , Expr) +EXPR(DependentScopeDeclRefExpr , Expr) EXPR(CXXConstructExpr , Expr) EXPR(CXXBindTemporaryExpr , Expr) EXPR(CXXExprWithTemporaries , Expr) EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) EXPR(CXXUnresolvedConstructExpr, Expr) -EXPR(CXXUnresolvedMemberExpr, Expr) +EXPR(CXXDependentScopeMemberExpr, Expr) +EXPR(UnresolvedMemberExpr , Expr) // Obj-C Expressions. EXPR(ObjCStringLiteral , Expr) diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 6db0958..b46b3dc 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" #include "clang/AST/Type.h" #include "clang/AST/TemplateName.h" @@ -437,6 +438,41 @@ public: } }; +/// A convenient class for passing around template argument +/// information. Designed to be passed by reference. +class TemplateArgumentListInfo { + llvm::SmallVector Arguments; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + +public: + TemplateArgumentListInfo() {} + + TemplateArgumentListInfo(SourceLocation LAngleLoc, + SourceLocation RAngleLoc) + : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; } + void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; } + + unsigned size() const { return Arguments.size(); } + + const TemplateArgumentLoc *getArgumentArray() const { + return Arguments.data(); + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return Arguments[I]; + } + + void addArgument(const TemplateArgumentLoc &Loc) { + Arguments.push_back(Loc); + } +}; + } #endif diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index c28bafe..349487f 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -82,6 +82,7 @@ namespace clang { class StmtIteratorBase; class TemplateArgument; class TemplateArgumentLoc; + class TemplateArgumentListInfo; class QualifiedNameType; struct PrintingPolicy; @@ -859,6 +860,7 @@ public: bool isObjCQualifiedClassType() const; // Class bool isObjCIdType() const; // id bool isObjCClassType() const; // Class + bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t @@ -1000,7 +1002,8 @@ public: UndeducedAuto, // In C++0x, this represents the type of an auto variable // that has not been deduced yet. ObjCId, // This represents the ObjC 'id' type. - ObjCClass // This represents the ObjC 'Class' type. + ObjCClass, // This represents the ObjC 'Class' type. + ObjCSel // This represents the ObjC 'SEL' type. }; private: Kind TypeKind; @@ -1457,21 +1460,27 @@ public: /// DependentSizedArrayType - This type represents an array type in /// C++ whose size is a value-dependent expression. For example: -/// @code +/// +/// \code /// template /// class array { /// T data[Size]; /// }; -/// @endcode +/// \endcode +/// /// For these types, we won't actually know what the array bound is /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { ASTContext &Context; - /// SizeExpr - An assignment expression that will instantiate to the + /// \brief An assignment expression that will instantiate to the /// size of the array. + /// + /// The expression itself might be NULL, in which case the array + /// type will have its size deduced from an initializer. Stmt *SizeExpr; + /// Brackets - The left and right array brackets. SourceRange Brackets; @@ -2272,6 +2281,8 @@ public: static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); + static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &); + /// \brief Print a template argument list, including the '<' and '>' /// enclosing the template arguments. static std::string PrintTemplateArgumentList(const TemplateArgument *Args, @@ -2282,6 +2293,9 @@ public: unsigned NumArgs, const PrintingPolicy &Policy); + static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &, + const PrintingPolicy &Policy); + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } @@ -2534,6 +2548,7 @@ public: return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCClass) && !Protocols.size(); } + /// isObjCQualifiedIdType - true for "id

". bool isObjCQualifiedIdType() const { return getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && @@ -2881,8 +2896,13 @@ inline bool Type::isObjCClassType() const { return OPT->isObjCClassType(); return false; } +inline bool Type::isObjCSelType() const { + if (const PointerType *OPT = getAs()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} inline bool Type::isObjCBuiltinType() const { - return isObjCIdType() || isObjCClassType(); + return isObjCIdType() || isObjCClassType() || isObjCSelType(); } inline bool Type::isTemplateTypeParmType() const { return isa(CanonicalType); diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 8674943..0077a85 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -23,6 +23,7 @@ namespace clang { class Stmt; class DeclRefExpr; class SourceManager; +class AnalysisContext; struct LiveVariables_ValueTypes { @@ -39,8 +40,9 @@ struct LiveVariables_ValueTypes { struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { ObserverTy* Observer; ValTy AlwaysLive; + AnalysisContext *AC; - AnalysisDataTy() : Observer(NULL) {} + AnalysisDataTy() : Observer(NULL), AC(NULL) {} }; //===-----------------------------------------------------===// @@ -66,7 +68,7 @@ class LiveVariables : public DataflowValues #include +#include #include -#include +#include namespace clang { - -class Stmt; + class Decl; -class Preprocessor; - +class SourceManager; +class Stmt; + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// class PathDiagnostic; - -class Stmt; -class Decl; -class Preprocessor; class PathDiagnosticClient : public DiagnosticClient { public: diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 9b58f74..8b1a329 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -19,6 +19,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" namespace clang { @@ -38,17 +39,26 @@ class AnalysisContext { CFG *cfg; LiveVariables *liveness; ParentMap *PM; - + llvm::DenseMap *ReferencedBlockVars; + llvm::BumpPtrAllocator A; public: - AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {} + AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0), + ReferencedBlockVars(0) {} + ~AnalysisContext(); + ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() { return D; } Stmt *getBody(); CFG *getCFG(); ParentMap &getParentMap(); LiveVariables *getLiveVariables(); + typedef const VarDecl * const * referenced_decls_iterator; + + std::pair + getReferencedBlockVars(const BlockDecl *BD); + /// Return the ImplicitParamDecl* associated with 'self' if this /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. const ImplicitParamDecl *getSelfDecl() const; diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index f429735..58c8018 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -309,32 +309,33 @@ public: void EmitReport(BugReport *R); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange R) { EmitBasicReport(BugName, BugStr, Loc, &R, 1); } - void EmitBasicReport(const char* BugName, const char* Category, - const char* BugStr, SourceLocation Loc, SourceRange R) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category, + llvm::StringRef BugStr, SourceLocation Loc, + SourceRange R) { EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); } @@ -432,7 +433,7 @@ class DiagBugReport : public RangedBugReport { std::list Strs; FullSourceLoc L; public: - DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) : RangedBugReport(D, desc, 0), L(l) {} virtual ~DiagBugReport() {} diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h index 8303dee..4f1523a 100644 --- a/include/clang/Analysis/PathSensitive/BugType.h +++ b/include/clang/Analysis/PathSensitive/BugType.h @@ -34,13 +34,13 @@ private: friend class BugReporter; bool SuppressonSink; public: - BugType(const char *name, const char* cat) + BugType(llvm::StringRef name, llvm::StringRef cat) : Name(name), Category(cat), SuppressonSink(false) {} virtual ~BugType(); // FIXME: Should these be made strings as well? - const std::string& getName() const { return Name; } - const std::string& getCategory() const { return Category; } + llvm::StringRef getName() const { return Name; } + llvm::StringRef getCategory() const { return Category; } /// isSuppressOnSink - Returns true if bug reports associated with this bug /// type should be suppressed if the end node of the report is post-dominated @@ -60,33 +60,15 @@ public: }; class BuiltinBug : public BugType { - GRExprEngine *Eng; -protected: const std::string desc; public: BuiltinBug(const char *name, const char *description) - : BugType(name, "Logic error"), Eng(0), desc(description) {} + : BugType(name, "Logic error"), desc(description) {} BuiltinBug(const char *name) - : BugType(name, "Logic error"), Eng(0), desc(name) {} + : BugType(name, "Logic error"), desc(name) {} - BuiltinBug(GRExprEngine *eng, const char* n, const char* d) - : BugType(n, "Logic error"), Eng(eng), desc(d) {} - - BuiltinBug(GRExprEngine *eng, const char* n) - : BugType(n, "Logic error"), Eng(eng), desc(n) {} - - const std::string &getDescription() const { return desc; } - - virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {} - - void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, *Eng); } - - virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) {} - - template void Emit(BugReporter& BR, ITER I, ITER E); + llvm::StringRef getDescription() const { return desc; } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index b7ed20f..91a4b6d 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -40,24 +40,35 @@ class CheckerContext { SaveAndRestore OldPointKind; SaveOr OldHasGen; const GRState *state; - + const Stmt *statement; + const unsigned size; + bool DoneEvaluating; // FIXME: This is not a permanent API change. public: CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, GRExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, - const GRState *st = 0) + const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), OldSink(B.BuildSinks), OldTag(B.Tag, tag), OldPointKind(B.PointKind, K), OldHasGen(B.HasGeneratedNode), - state(st) {} + state(st), statement(stmt), size(Dst.size()), + DoneEvaluating(false) {} - ~CheckerContext() { - if (!B.BuildSinks && !B.HasGeneratedNode) - Dst.Add(Pred); + ~CheckerContext(); + + // FIXME: This were added to support CallAndMessageChecker to indicating + // to GRExprEngine to "stop evaluating" a message expression under certain + // cases. This is *not* meant to be a permanent API change, and was added + // to aid in the transition of removing logic for checks from GRExprEngine. + void setDoneEvaluating() { + DoneEvaluating = true; } - + bool isDoneEvaluating() const { + return DoneEvaluating; + } + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } @@ -83,27 +94,70 @@ public: return getBugReporter().getSourceManager(); } - ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { - return GenerateNode(S, getState(), markAsSink); + ValueManager &getValueManager() { + return Eng.getValueManager(); } - ExplodedNode *GenerateNode(const Stmt* S, const GRState *state, - bool markAsSink = false) { - ExplodedNode *node = B.generateNode(S, state, Pred); + ExplodedNode *GenerateNode(bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); + if (N && autoTransition) + Dst.Add(N); + return N; + } + + ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, + bool autoTransition = true) { + assert(state); + ExplodedNode *N = GenerateNodeImpl(stmt, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - if (markAsSink && node) - node->markAsSink(); + ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - return node; + ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { + return GenerateNodeImpl(stmt, state ? state : getState(), true); + } + + ExplodedNode *GenerateSink(const GRState *state = 0) { + assert(statement && "Only transitions with statements currently supported"); + return GenerateNodeImpl(statement, state ? state : getState(), true); } void addTransition(ExplodedNode *node) { Dst.Add(node); } + + void addTransition(const GRState *state) { + assert(state); + if (state != getState() || + (state && state != B.GetState(Pred))) + GenerateNode(state, true); + else + Dst.Add(Pred); + } void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } + +private: + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, Pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } + }; class Checker { @@ -111,18 +165,19 @@ private: friend class GRExprEngine; // FIXME: Remove the 'tag' option. - void GR_Visit(ExplodedNodeSet &Dst, + bool GR_Visit(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, void *tag, bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, S); if (isPrevisit) _PreVisit(C, S); else _PostVisit(C, S); + return C.isDoneEvaluating(); } // FIXME: Remove the 'tag' option. @@ -134,7 +189,7 @@ private: bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, StoreE); assert(isPrevisit && "Only previsit supported for now."); PreVisitBind(C, AssignE, StoreE, location, val); } @@ -149,7 +204,7 @@ private: void *tag, bool isLoad) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, state); + ProgramPoint::PreStoreKind, S, state); VisitLocation(C, S, location); } @@ -157,12 +212,12 @@ private: GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, Pred->getState()); + ProgramPoint::PostPurgeDeadSymbolsKind, S); EvalDeadSymbols(C, S, SymReaper); } public: - virtual ~Checker() {} + virtual ~Checker(); virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} @@ -172,6 +227,10 @@ public: SymbolReaper &SymReaper) {} virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) {} + + virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, + GRExprEngine &Eng, + Stmt *Condition, void *tag) {} }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def index 090a5d3..4144d1a 100644 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.def +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def @@ -11,7 +11,14 @@ // //===---------------------------------------------------------------------===// -#ifdef PREVISIT +#ifndef PREVISIT +#define PREVISIT(NODE) +#endif + +#ifndef POSTVISIT +#define POSTVISIT(NODE) +#endif + PREVISIT(ArraySubscriptExpr) PREVISIT(BinaryOperator) PREVISIT(CallExpr) @@ -19,11 +26,10 @@ PREVISIT(CastExpr) PREVISIT(DeclStmt) PREVISIT(ObjCMessageExpr) PREVISIT(ReturnStmt) -#undef PREVISIT -#endif -#ifdef POSTVISIT POSTVISIT(CallExpr) -#undef POSTVISIT -#endif +POSTVISIT(BlockExpr) +POSTVISIT(BinaryOperator) +#undef PREVISIT +#undef POSTVISIT diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h deleted file mode 100644 index 13437eb..0000000 --- a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h +++ /dev/null @@ -1,33 +0,0 @@ -//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that -// checks for assigning undefined values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_UNDEFASSIGNMENTCHECKER -#define LLVM_CLANG_UNDEFASSIGNMENTCHECKER - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" - -namespace clang { -class UndefinedAssignmentChecker - : public CheckerVisitor { - BugType *BT; -public: - UndefinedAssignmentChecker() : BT(0) {} - static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); -}; -} -#endif - diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index a7bbdf9..76cab1d 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -352,10 +352,16 @@ public: typedef ImplTy::iterator iterator; typedef ImplTy::const_iterator const_iterator; - inline unsigned size() const { return Impl.size(); } - inline bool empty() const { return Impl.empty(); } - - inline void clear() { Impl.clear(); } + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } inline iterator begin() { return Impl.begin(); } inline iterator end() { return Impl.end(); } diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index 02e0b027..b78cc6a 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -215,7 +215,7 @@ public: void setAuditor(GRAuditor* A) { Auditor = A; } const GRState* GetState(ExplodedNode* Pred) const { - if ((ExplodedNode*) Pred == getBasePredecessor()) + if (Pred == getBasePredecessor()) return CleanedState; else return Pred->getState(); @@ -405,6 +405,8 @@ class GREndPathNodeBuilder { GRCoreEngine& Eng; CFGBlock& B; ExplodedNode* Pred; + +public: bool HasGeneratedNode; public: diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 1b6d0bd..a7302c0 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -88,55 +88,6 @@ class GRExprEngine : public GRSubEngine { GRBugReporter BR; public: - typedef llvm::SmallPtrSet ErrorNodes; - typedef llvm::DenseMap UndefArgsTy; - - /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' definitely being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetExplicit; - - /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' possibly being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetImplicit; - - /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' definitely being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; - - /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' possibly being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; - - /// UndefBranches - Nodes in the ExplodedGraph that result from - /// taking a branch based on an undefined value. - ErrorNodes UndefBranches; - - /// UndefStores - Sinks in the ExplodedGraph that result from - /// making a store to an undefined lvalue. - ErrorNodes UndefStores; - - /// NoReturnCalls - Sinks in the ExplodedGraph that result from - // calling a function with the attribute "noreturn". - ErrorNodes NoReturnCalls; - - /// UndefResults - Nodes in the ExplodedGraph where the operands are defined - /// by the result is not. Excludes divide-by-zero errors. - ErrorNodes UndefResults; - - /// UndefReceiver - Nodes in the ExplodedGraph resulting from message - /// ObjC message expressions where the receiver is undefined (uninitialized). - ErrorNodes UndefReceivers; - - /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from - /// message expressions where a pass-by-value argument has an undefined - /// value. - UndefArgsTy MsgExprUndefArgs; - -public: GRExprEngine(AnalysisManager &mgr); ~GRExprEngine(); @@ -178,8 +129,6 @@ public: ExplodedGraph& getGraph() { return G; } const ExplodedGraph& getGraph() const { return G; } - void RegisterInternalChecks(); - template void registerCheck(CHECKER *check) { unsigned entry = Checkers.size(); @@ -195,58 +144,6 @@ public: return static_cast(lookupChecker(CHECKER::getTag())); } - bool isNoReturnCall(const ExplodedNode* N) const { - return N->isSink() && NoReturnCalls.count(const_cast(N)) != 0; - } - - typedef ErrorNodes::iterator undef_branch_iterator; - undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } - undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } - - typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { - return NilReceiverStructRetExplicit.begin(); - } - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { - return NilReceiverStructRetExplicit.end(); - } - - typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_begin() { - return NilReceiverLargerThanVoidPtrRetExplicit.begin(); - } - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_end() { - return NilReceiverLargerThanVoidPtrRetExplicit.end(); - } - - typedef ErrorNodes::iterator undef_result_iterator; - undef_result_iterator undef_results_begin() { return UndefResults.begin(); } - undef_result_iterator undef_results_end() { return UndefResults.end(); } - - typedef UndefArgsTy::iterator undef_arg_iterator; - undef_arg_iterator msg_expr_undef_arg_begin() { - return MsgExprUndefArgs.begin(); - } - undef_arg_iterator msg_expr_undef_arg_end() { - return MsgExprUndefArgs.end(); - } - - typedef ErrorNodes::iterator undef_receivers_iterator; - - undef_receivers_iterator undef_receivers_begin() { - return UndefReceivers.begin(); - } - - undef_receivers_iterator undef_receivers_end() { - return UndefReceivers.end(); - } - void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); void AddCheck(GRSimpleAPICheck* A); @@ -312,7 +209,7 @@ public: protected: /// CheckerVisit - Dispatcher for performing checker-specific logic /// at specific statements. - void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + bool CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, @@ -345,6 +242,9 @@ protected: AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, @@ -361,33 +261,38 @@ protected: unsigned ParamIdx = 0); /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, + ExplodedNodeSet& Dst); - void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue); + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitObjCForCollectionStmt - Transfer function logic for /// ObjCForCollectionStmt. diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index ef0c36c..d8bc241 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -33,7 +33,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include @@ -264,8 +263,21 @@ public: const llvm::APSInt *getSymVal(SymbolRef sym); bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; template CB scanReachableSymbols(SVal val) const; + template CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). @@ -726,7 +738,21 @@ CB GRState::scanReachableSymbols(SVal val) const { scanReachableSymbols(val, cb); return cb; } + +template +CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} +template +CB GRState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 06d0d97..ed96497 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -35,6 +35,7 @@ namespace clang { class MemRegionManager; class MemSpaceRegion; class LocationContext; +class VarRegion; //===----------------------------------------------------------------------===// // Base region classes. @@ -42,13 +43,16 @@ class LocationContext; /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; public: enum Kind { MemSpaceRegionKind, SymbolicRegionKind, AllocaRegionKind, // Typed regions. BEG_TYPED_REGIONS, - CodeTextRegionKind, + FunctionTextRegionKind, + BlockTextRegionKind, + BlockDataRegionKind, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, // Decl Regions. @@ -237,45 +241,123 @@ public: } }; -/// CodeTextRegion - A region that represents code texts of a function. It wraps -/// two kinds of code texts: real function and symbolic function. Real function -/// is a function declared in the program. Symbolic function is a function -/// pointer that we don't know which function it points to. -class CodeTextRegion : public TypedRegion { - const FunctionDecl *FD; +class CodeTextRegion : public TypedRegion { +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} public: - - CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg) - : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {} - QualType getValueType(ASTContext &C) const { // Do not get the object type of a CodeTextRegion. assert(0); return QualType(); } + + bool isBoundable() const { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const FunctionDecl *FD; +public: + FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} + QualType getLocationType(ASTContext &C) const { return C.getPointerType(FD->getType()); } - + const FunctionDecl *getDecl() const { return FD; } - - bool isBoundable() const { return false; } - + virtual void dumpToStream(llvm::raw_ostream& os) const; - + void Profile(llvm::FoldingSetNodeID& ID) const; - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, const MemRegion*); - + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + const BlockDecl *BD; + CanQualType locTy; +public: + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), locTy(lTy) {} + + QualType getLocationType(ASTContext &C) const { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const MemRegion*); + static bool classof(const MemRegion* R) { - return R->getKind() == CodeTextRegionKind; + return R->getKind() == BlockTextRegionKind; } }; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +/// BlockDataRegion - A region that represents code texts of blocks (closures). +class BlockDataRegion : public SubRegion { + const BlockTextRegion *BC; + const LocationContext *LC; + void *ReferencedVars; +public: + BlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc, + const MemRegion *sreg) + : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} + + const BlockTextRegion *getCodeRegion() const { return BC; } + + typedef const MemRegion * const * referenced_vars_iterator; + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockTextRegion *BC, + const LocationContext *LC, const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); +}; /// SymbolicRegion - A special, "non-concrete" region. Unlike other region /// clases, SymbolicRegion represents a region that serves as an alias for @@ -577,9 +659,11 @@ public: : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), unknown(0), code(0) {} - ~MemRegionManager() {} + ~MemRegionManager(); ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } /// getStackRegion - Retrieve the memory region associated with the /// current stack frame. @@ -656,7 +740,10 @@ public: ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD); + FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy); + BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc); template RegionTy* getRegion(const A1 a1); @@ -667,6 +754,10 @@ public: template RegionTy* getRegion(const A1 a1, const A2 a2); + template + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + bool isGlobalsRegion(const MemRegion* R) { assert(R); return R == globals; @@ -745,6 +836,25 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { return R; } + +template +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} //===----------------------------------------------------------------------===// // Traits for constructing regions. @@ -801,18 +911,21 @@ template <> struct MemRegionManagerTrait { } }; -template<> struct MemRegionManagerTrait { +template<> struct MemRegionManagerTrait { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, const FunctionDecl*) { return MRMgr.getCodeRegion(); } +}; +template<> struct MemRegionManagerTrait { + typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - SymbolRef, QualType) { + const BlockDecl*, CanQualType) { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index 8d162a6..ef4e069 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -114,6 +114,9 @@ public: const TypedRegion *R); DefinedSVal getFunctionPointer(const FunctionDecl *FD); + + DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, + const LocationContext *LC); NonLoc makeCompoundVal(QualType T, llvm::ImmutableList Vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 2af9580..bbf42ee 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -250,8 +250,8 @@ BUILTIN(__builtin_ia32_pmaddwd128, "V8sV8sV8s", "") BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") BUILTIN(__builtin_ia32_mwait, "vUiUi", "") BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") -BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLii", "") -BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLis", "") +BUILTIN(__builtin_ia32_palignr128, "V2LLiV2LLiV2LLic", "") +BUILTIN(__builtin_ia32_palignr, "V1LLiV1LLiV1LLic", "") BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index e2f1104..3f7d114 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -57,6 +57,9 @@ def err_drv_invalid_mfloat_abi : Error< "invalid float ABI '%0'">; def err_drv_I_dash_not_supported : Error< "'%0' not supported, please use -iquote instead">; +def err_drv_unknown_argument : Error<"unknown argument: '%0'">; +def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; +def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; def warn_drv_input_file_unused : Warning< "%0: '%1' input unused when '%2' is present">; diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index e9b351f..cbc287c 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -17,6 +17,8 @@ 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_code_complete_file : Error<"cannot locate code-completion file %0">, DefaultFatal; +def err_fe_stdout_binary : Error<"unable to change standard output to binary">, + DefaultFatal; def err_fe_dependency_file_requires_MT : Error< "-dependency-file requires at least one -MT option">; def err_fe_incompatible_options : Error< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 93c655b..c1c833c 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -78,16 +78,19 @@ def : DiagGroup<"synth">; // Preprocessor warnings. def : DiagGroup<"builtin-macro-redefined">; -// Just silence warnings about common forms of -Wstrict-aliasing for now. +// Just silence warnings about -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; def : DiagGroup<"strict-aliasing=1">; def : DiagGroup<"strict-aliasing=2">; def : DiagGroup<"strict-aliasing">; -// Just silence warnings about common forms of -Wstrict-aliasing for now. +// Just silence warnings about -Wstrict-overflow for now. def : DiagGroup<"strict-overflow=0">; def : DiagGroup<"strict-overflow=1">; def : DiagGroup<"strict-overflow=2">; +def : DiagGroup<"strict-overflow=3">; +def : DiagGroup<"strict-overflow=4">; +def : DiagGroup<"strict-overflow=5">; def : DiagGroup<"strict-overflow">; def InvalidOffsetof : DiagGroup<"invalid-offsetof">; diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 7f3f4ea..39123d9 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -170,6 +170,8 @@ def ext_pp_counter : Extension< def err_pp_invalid_directive : Error<"invalid preprocessing directive">; def err_pp_hash_error : Error<"#error%0">; def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def err_pp_error_opening_file : Error< + "error opening file '%0'">, DefaultFatal; def err_pp_empty_filename : Error<"empty filename">; def err_pp_include_too_deep : Error<"#include nested too deeply">; def err_pp_expects_filename : Error<"expected \"FILENAME\" or ">; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 3a8c5bf..4310704 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -44,7 +44,8 @@ def ext_c99_variable_decl_in_for_loop : Extension< def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">; def ext_enumerator_list_comma : Extension< - "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific feature">; + "commas at the end of enumerator lists are a %select{C99|C++0x}0-specific " + "feature">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">; @@ -75,6 +76,7 @@ def err_expected_ident_lbrace : Error<"expected identifier or '{'">; def err_expected_lbrace : Error<"expected '{'">; def err_expected_lparen : Error<"expected '('">; def err_expected_rparen : Error<"expected ')'">; +def err_expected_lsquare : Error<"expected '['">; def err_expected_rsquare : Error<"expected ']'">; def err_expected_rbrace : Error<"expected '}'">; def err_expected_greater : Error<"expected '>'">; @@ -240,11 +242,18 @@ def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading def err_operator_missing_type_specifier : Error< "missing type specifier after 'operator'">; +def err_operator_string_not_empty : Error< + "string literal after 'operator' must be '\"\"'">; // Classes. def err_anon_type_definition : Error< "declaration of anonymous %0 must be a definition">; +def err_cxx0x_attribute_forbids_arguments : Error< + "C++0x attribute '%0' cannot have an argument list">; +def err_cxx0x_attribute_requires_arguments : Error< + "C++0x attribute '%0' must have an argument list">; +def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; /// C++ Templates def err_expected_template : Error<"expected template">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a864d8a..a0e03fe 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -443,8 +443,9 @@ def err_implicit_object_parameter_init : Error< def note_field_decl : Note<"member is declared here">; def note_previous_class_decl : Note< "%0 declared here">; -def note_ctor_synthesized_at : Note< - "implicit default constructor for %0 first required here">; +def note_member_synthesized_at : Note< + "implicit default %select{constructor|copy constructor|" + "copy assignment operator|destructor}0 for %1 first required here">; def err_missing_default_ctor : Error< "%select{|implicit default }0constructor for %1 must explicitly initialize " "the %select{base class|member}2 %3 which does not have a default " @@ -552,6 +553,15 @@ def err_auto_not_allowed : Error< def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; +// C++0x attributes +def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; + +// C++0x [[final]] +def err_final_function_overridden : Error< + "declaration of %0 overrides a 'final' function">; +def err_final_base : Error< + "derivation from 'final' %0">; + // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< "Objective-C declarations may only appear in global scope">; @@ -638,8 +648,16 @@ def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|parameter or Objective-C method |" - "function, method or block}1 types">; + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}1 types">; +def err_attribute_wrong_decl_type : Error< + "%0 attribute only applies to %select{function|union|" + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter|class|virtual method" + "|member}1 types">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; @@ -865,7 +883,7 @@ def err_addr_ovl_ambiguous : Error< def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def note_template_param_here : Note<"template parameter is declared here">; -def note_template_export_unsupported : Note< +def warn_template_export_unsupported : Warning< "exported templates are unsupported">; def err_template_outside_namespace_or_class_scope : Error< "templates can only be declared in namespace or class scope">; @@ -902,7 +920,15 @@ def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; - +def err_template_parameter_default_in_function_template : Error< + "a template parameter of a function template cannot have a default argument " + "in C++98">; +def err_template_parameter_default_template_member : Error< + "cannot add a default template argument to the definition of a member of a " + "class template">; +def err_template_parameter_default_friend_template : Error< + "default template argument not permitted on a friend template">; + def err_template_variable : Error<"variable %0 declared as a template">; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; @@ -1037,6 +1063,11 @@ def err_template_param_list_matches_nontemplate : Error< def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; +def warn_template_spec_extra_headers : Warning< + "extraneous template parameter list in template specialization">; +def note_explicit_template_spec_does_not_need_header : Note< + "'template<>' header not required for explicitly-specialized class %0 " + "declared here">; def err_template_qualified_declarator_no_match : Error< "nested name specifier '%0' for declaration does not refer into a class, " "class template or class template partial specialization">; @@ -1197,6 +1228,10 @@ def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; def err_template_kw_refers_to_function_template : Error< "%0 following the 'template' keyword refers to a function template">; +def err_template_kw_refers_to_class_template : Error< + "'%0%1' instantiated to a class template, not a function template">; +def note_referenced_class_template : Error< + "class template declared here">; // C++0x Variadic Templates def err_template_param_pack_default_arg : Error< @@ -2050,6 +2085,8 @@ def err_base_init_direct_and_virtual : Error< "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'">; def err_in_class_initializer_non_integral_type : Error< "in-class initializer has non-integral, non-enumeration type %0">; @@ -2275,6 +2312,15 @@ def err_typecheck_statement_requires_integer : Error< "statement requires expression of integer type (%0 invalid)">; def err_multiple_default_labels_defined : Error< "multiple default labels in one switch">; +def err_switch_multiple_conversions : Error< + "multiple conversions from switch condition type %0 to an integral or " + "enumeration type">; +def note_switch_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1">; +def err_switch_explicit_conversion : Error< + "switch condition type %0 requires explicit conversion to %1">; +def err_switch_incomplete_class_type : Error< + "switch condition has incomplete class type %0">; def warn_empty_if_body : Warning< "if statement has empty body">, InGroup; def err_va_start_used_in_non_variadic_function : Error< diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index e06dfbb..5393950 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -496,6 +496,7 @@ public: #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ CXXOperator##Name, #include "clang/Basic/OperatorKinds.def" + CXXLiteralOperator, CXXUsingDirective, NUM_EXTRA_KINDS }; @@ -503,10 +504,10 @@ public: /// ExtraKindOrNumArgs - Either the kind of C++ special name or /// operator-id (if the value is one of the CXX* enumerators of /// ExtraKind), in which case the DeclarationNameExtra is also a - /// CXXSpecialName (for CXXConstructor, CXXDestructor, or - /// CXXConversionFunction) or CXXOperatorIdName, it may be also - /// name common to C++ using-directives (CXXUsingDirective), otherwise - /// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// CXXSpecialName, (for CXXConstructor, CXXDestructor, or + /// CXXConversionFunction) CXXOperatorIdName, or CXXLiteralOperatorName, + /// it may be also name common to C++ using-directives (CXXUsingDirective), + /// otherwise it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of /// arguments in the Objective-C selector, in which case the /// DeclarationNameExtra is also a MultiKeywordSelector. unsigned ExtraKindOrNumArgs; diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 99c100d..a16a271 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_LANGOPTIONS_H #define LLVM_CLANG_LANGOPTIONS_H +#include + namespace clang { /// LangOptions - This class keeps track of the various options that can be @@ -101,15 +103,10 @@ private: // on making enums signed. Set/Query this // value using accessors. - /// The user provided name for the "main file", if non-null. This is - /// useful in situations where the input file name does not match - /// the original input file, for example with -save-temps. - const char *MainFileName; - public: unsigned InstantiationDepth; // Maximum template instantiation depth. - const char *ObjCConstantStringClass; + std::string ObjCConstantStringClass; enum GCMode { NonGC, GCOnly, HybridGC }; enum StackProtectorMode { SSPOff, SSPOn, SSPReq }; @@ -124,7 +121,6 @@ public: GNUMode = ImplicitInt = Digraphs = 0; HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = 0; - ObjCConstantStringClass = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; CXXOperatorNames = PascalStrings = WritableStrings = 0; Exceptions = Freestanding = NoBuiltin = 0; @@ -164,8 +160,6 @@ public: CharIsSigned = 1; ShortWChar = 0; - - MainFileName = 0; } GCMode getGCMode() const { return (GCMode) GC; } @@ -178,9 +172,6 @@ public: StackProtector = static_cast(m); } - const char *getMainFileName() const { return MainFileName; } - void setMainFileName(const char *Name) { MainFileName = Name; } - VisibilityMode getVisibilityMode() const { return (VisibilityMode) SymbolVisibility; } diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h index 6b60f2e..9b50e8d 100644 --- a/include/clang/Basic/OnDiskHashTable.h +++ b/include/clang/Basic/OnDiskHashTable.h @@ -15,7 +15,6 @@ #define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include "llvm/System/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 695f51d..49eaafe 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -80,7 +80,7 @@ public: }; protected: IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, - WIntType, Char16Type, Char32Type, Int64Type; + WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType; public: IntType getSizeType() const { return SizeType; } IntType getIntMaxType() const { return IntMaxType; } @@ -94,6 +94,7 @@ public: IntType getChar16Type() const { return Char16Type; } IntType getChar32Type() const { return Char32Type; } IntType getInt64Type() const { return Int64Type; } + IntType getSigAtomicType() const { return SigAtomicType; } /// getTypeWidth - Return the width (in bits) of the specified integer type diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 239712c..9942233 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -17,6 +17,9 @@ #ifndef TOK #define TOK(X) #endif +#ifndef PUNCTUATOR +#define PUNCTUATOR(X,Y) TOK(X) +#endif #ifndef KEYWORD #define KEYWORD(X,Y) TOK(kw_ ## X) #endif @@ -113,64 +116,63 @@ TOK(wide_string_literal) // L"foo" TOK(angle_string_literal)// // C99 6.4.6: Punctuators. -TOK(l_square) // [ -TOK(r_square) // ] -TOK(l_paren) // ( -TOK(r_paren) // ) -TOK(l_brace) // { -TOK(r_brace) // } -TOK(period) // . -TOK(ellipsis) // ... -TOK(amp) // & -TOK(ampamp) // && -TOK(ampequal) // &= -TOK(star) // * -TOK(starequal) // *= -TOK(plus) // + -TOK(plusplus) // ++ -TOK(plusequal) // += -TOK(minus) // - -TOK(arrow) // -> -TOK(minusminus) // -- -TOK(minusequal) // -= -TOK(tilde) // ~ -TOK(exclaim) // ! -TOK(exclaimequal) // != -TOK(slash) // / -TOK(slashequal) // /= -TOK(percent) // % -TOK(percentequal) // %= -TOK(less) // < -TOK(lessless) // << -TOK(lessequal) // <= -TOK(lesslessequal) // <<= -TOK(greater) // > -TOK(greatergreater) // >> -TOK(greaterequal) // >= -TOK(greatergreaterequal) // >>= -TOK(caret) // ^ -TOK(caretequal) // ^= -TOK(pipe) // | -TOK(pipepipe) // || -TOK(pipeequal) // |= -TOK(question) // ? -TOK(colon) // : -TOK(semi) // ; -TOK(equal) // = -TOK(equalequal) // == -TOK(comma) // , -TOK(hash) // # -TOK(hashhash) // ## -TOK(hashat) // #@ +PUNCTUATOR(l_square, "[") +PUNCTUATOR(r_square, "]") +PUNCTUATOR(l_paren, "(") +PUNCTUATOR(r_paren, ")") +PUNCTUATOR(l_brace, "{") +PUNCTUATOR(r_brace, "}") +PUNCTUATOR(period, ".") +PUNCTUATOR(ellipsis, "...") +PUNCTUATOR(amp, "&") +PUNCTUATOR(ampamp, "&&") +PUNCTUATOR(ampequal, "&=") +PUNCTUATOR(star, "*") +PUNCTUATOR(starequal, "*=") +PUNCTUATOR(plus, "+") +PUNCTUATOR(plusplus, "++") +PUNCTUATOR(plusequal, "+=") +PUNCTUATOR(minus, "-") +PUNCTUATOR(arrow, "->") +PUNCTUATOR(minusminus, "--") +PUNCTUATOR(minusequal, "-=") +PUNCTUATOR(tilde, "~") +PUNCTUATOR(exclaim, "!") +PUNCTUATOR(exclaimequal, "!=") +PUNCTUATOR(slash, "/") +PUNCTUATOR(slashequal, "/=") +PUNCTUATOR(percent, "%") +PUNCTUATOR(percentequal, "%=") +PUNCTUATOR(less, "<") +PUNCTUATOR(lessless, "<<") +PUNCTUATOR(lessequal, "<=") +PUNCTUATOR(lesslessequal, "<<=") +PUNCTUATOR(greater, ">") +PUNCTUATOR(greatergreater, ">>") +PUNCTUATOR(greaterequal, ">=") +PUNCTUATOR(greatergreaterequal, ">>=") +PUNCTUATOR(caret, "^") +PUNCTUATOR(caretequal, "^=") +PUNCTUATOR(pipe, "|") +PUNCTUATOR(pipepipe, "||") +PUNCTUATOR(pipeequal, "|=") +PUNCTUATOR(question, "?") +PUNCTUATOR(colon, ":") +PUNCTUATOR(semi, ";") +PUNCTUATOR(equal, "=") +PUNCTUATOR(equalequal, "==") +PUNCTUATOR(comma, ",") +PUNCTUATOR(hash, "#") +PUNCTUATOR(hashhash, "##") +PUNCTUATOR(hashat, "#@") // C++ Support -TOK(periodstar) // .* -TOK(arrowstar) // ->* -TOK(coloncolon) // :: +PUNCTUATOR(periodstar, ".*") +PUNCTUATOR(arrowstar, "->*") +PUNCTUATOR(coloncolon, "::") // Objective C support. -TOK(at) // @ - +PUNCTUATOR(at, "@") // C99 6.4.1: Keywords. These turn into kw_* tokens. // Flags allowed: @@ -415,4 +417,5 @@ ANNOTATION(template_id) // annotation for a C++ template-id that names a #undef PPKEYWORD #undef ALIAS #undef KEYWORD +#undef PUNCTUATOR #undef TOK diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h index 02679cd..c8fb37b 100644 --- a/include/clang/CodeGen/CodeGenOptions.h +++ b/include/clang/CodeGen/CodeGenOptions.h @@ -29,7 +29,9 @@ public: OnlyAlwaysInlining // Only run the always inlining pass. }; + unsigned AsmVerbose : 1; /// -dA, -fverbose-asm. 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 /// getting .bc files that correspond to the /// internal state before optimizations are @@ -38,35 +40,63 @@ public: 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 OptimizationLevel : 3; /// The -O[0-4] option specified. unsigned OptimizeSize : 1; /// If -Os is specified. - unsigned SimplifyLibCalls : 1; /// Should standard library calls be treated - /// specially. + unsigned SoftFloat : 1; /// -soft-float. unsigned TimePasses : 1; /// Set when -ftime-report is enabled. unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization /// selection. unsigned UnrollLoops : 1; /// Control whether loops are unrolled. + unsigned UnwindTables : 1; /// Emit unwind tables. unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. - /// Inlining - The kind of inlining to perform. + /// The code model to use (-mcmodel). + std::string CodeModel; + + /// Enable additional debugging information. + std::string DebugPass; + + /// The ABI to use for passing floating point arguments. + std::string FloatABI; + + /// The float precision limit to use, if non-empty. + std::string LimitFloatPrecision; + + /// The kind of inlining to perform. InliningMethod Inlining; + /// The user provided name for the "main file", if non-empty. This is useful + /// in situations where the input file name does not match the original input + /// file, for example with -save-temps. + std::string MainFileName; + + /// The name of the relocation model to use. + std::string RelocationModel; + public: CodeGenOptions() { + AsmVerbose = 0; + DebugInfo = 0; + DisableFPElim = 0; + DisableLLVMOpts = 0; + DisableRedZone = 0; + MergeAllConstants = 1; + NoCommon = 0; + NoImplicitFloat = 0; + NoZeroInitializedInBSS = 0; OptimizationLevel = 0; OptimizeSize = 0; - DebugInfo = 0; + UnrollLoops = 0; + SoftFloat = 0; + TimePasses = 0; UnitAtATime = 1; - SimplifyLibCalls = UnrollLoops = 0; + UnwindTables = 0; VerifyModule = 1; - TimePasses = 0; - NoCommon = 0; + Inlining = NoInlining; - DisableRedZone = 0; - NoImplicitFloat = 0; - MergeAllConstants = 1; - DisableLLVMOpts = 0; + RelocationModel = "pic"; } }; diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index 5263108..ab1abff 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -25,8 +25,67 @@ namespace llvm { namespace clang { namespace driver { class Arg; + class ArgList; class Option; + /// arg_iterator - Iterates through arguments stored inside an ArgList. + class arg_iterator { + /// The current argument. + llvm::SmallVectorImpl::const_iterator Current; + + /// The argument list we are iterating over. + const ArgList &Args; + + /// Optional filters on the arguments which will be match. Most clients + /// should never want to iterate over arguments without filters, so we won't + /// bother to factor this into two separate iterator implementations. + // + // FIXME: Make efficient; the idea is to provide efficient iteration over + // all arguments which match a particular id and then just provide an + // iterator combinator which takes multiple iterators which can be + // efficiently compared and returns them in order. + OptSpecifier Id0, Id1, Id2; + + void SkipToNextArg(); + + public: + typedef const Arg* value_type; + typedef const Arg* reference; + typedef const Arg* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + arg_iterator(llvm::SmallVectorImpl::const_iterator it, + const ArgList &_Args, OptSpecifier _Id0 = 0U, + OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U) + : Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) { + SkipToNextArg(); + } + + operator const Arg*() { return *Current; } + reference operator*() const { return *Current; } + pointer operator->() const { return *Current; } + + arg_iterator &operator++() { + ++Current; + SkipToNextArg(); + return *this; + } + + arg_iterator operator++(int) { + arg_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(arg_iterator LHS, arg_iterator RHS) { + return LHS.Current == RHS.Current; + } + friend bool operator!=(arg_iterator LHS, arg_iterator RHS) { + return !(LHS == RHS); + } + }; + /// ArgList - Ordered collection of driver arguments. /// /// The ArgList class manages a list of Arg instances as well as @@ -62,6 +121,10 @@ namespace driver { unsigned size() const { return Args.size(); } + /// @} + /// @name Arg Iteration + /// @{ + iterator begin() { return Args.begin(); } iterator end() { return Args.end(); } @@ -74,6 +137,18 @@ namespace driver { const_reverse_iterator rbegin() const { return Args.rbegin(); } const_reverse_iterator rend() const { return Args.rend(); } + arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U, + OptSpecifier Id2 = 0U) const { + return arg_iterator(Args.begin(), *this, Id0, Id1, Id2); + } + arg_iterator filtered_end() const { + return arg_iterator(Args.end(), *this); + } + + /// @} + /// @name Arg Access + /// @{ + /// hasArg - Does the arg list contain any option matching \arg Id. /// /// \arg Claim Whether the argument should be claimed, if it exists. @@ -115,17 +190,13 @@ namespace driver { void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const; /// AddAllArgs - Render all arguments matching the given ids. - void AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const; void AddAllArgs(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const; - void AddAllArgs(ArgStringList &Output, OptSpecifier Id0, OptSpecifier Id1, - OptSpecifier Id2) const; + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; /// AddAllArgValues - Render the argument values of all arguments /// matching the given ids. - void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const; void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const; + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; /// AddAllArgsTranslated - Render all the arguments matching the /// given ids, but forced to separate args and using the provided diff --git a/include/clang/Driver/CC1Options.h b/include/clang/Driver/CC1Options.h index 057022c..4a8bbe5 100644 --- a/include/clang/Driver/CC1Options.h +++ b/include/clang/Driver/CC1Options.h @@ -17,8 +17,6 @@ namespace driver { namespace cc1options { enum ID { OPT_INVALID = 0, // This is not an option ID. - OPT_INPUT, // Reserved ID for input option. - OPT_UNKNOWN, // Reserved ID for unknown option. #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) OPT_##ID, #include "clang/Driver/CC1Options.inc" diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index ef8d847..b34fe03 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -14,13 +14,400 @@ // Include the common option parsing interfaces. include "OptParser.td" +//===----------------------------------------------------------------------===// // Target Options +//===----------------------------------------------------------------------===// def target_abi : Separate<"-target-abi">, HelpText<"Target a particular ABI type">; -def target_cpu : Separate<"-mcpu">, - HelpText<"Target a specific cpu type (-mcpu=help for details)">; -def target_features : Separate<"-target-feature">, +def mcpu : Separate<"-mcpu">, + HelpText<"Target a specific cpu type ('-mcpu help' for details)">; +def target_feature : Separate<"-target-feature">, HelpText<"Target specific attributes">; -def target_triple : Separate<"-triple">, +def triple : Separate<"-triple">, HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; +def triple_EQ : Joined<"-triple=">, Alias; + +//===----------------------------------------------------------------------===// +// Analyzer Options +//===----------------------------------------------------------------------===// + +def analysis_CFGDump : Flag<"-cfg-dump">, + HelpText<"Display Control-Flow Graphs">; +def analysis_CFGView : Flag<"-cfg-view">, + HelpText<"View Control-Flow Graphs using GraphViz">; +def analysis_DisplayLiveVariables : Flag<"-dump-live-variables">, + HelpText<"Print results of live variable analysis">; +def analysis_SecuritySyntacticChecks : Flag<"-warn-security-syntactic">, + HelpText<"Perform quick security checks that require no data flow">; +def analysis_WarnDeadStores : Flag<"-warn-dead-stores">, + HelpText<"Warn about stores to dead variables">; +def analysis_WarnUninitVals : Flag<"-warn-uninit-values">, + HelpText<"Warn about uses of uninitialized variables">; +def analysis_WarnObjCMethSigs : Flag<"-warn-objc-methodsigs">, + HelpText<"Warn about Objective-C method signatures with type incompatibilities">; +def analysis_WarnObjCDealloc : Flag<"-warn-objc-missing-dealloc">, + HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">; +def analysis_WarnObjCUnusedIvars : Flag<"-warn-objc-unused-ivars">, + HelpText<"Warn about private ivars that are never used">; +def analysis_CheckerCFRef : Flag<"-checker-cfref">, + HelpText<"Run the [Core] Foundation reference count checker">; +def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">, + HelpText<"Warn about unintended use of sizeof() on pointer expressions">; +def analysis_InlineCall : Flag<"-inline-call">, + HelpText<"Experimental transfer function inling callees when its definition is available.">; + +def analyzer_store : Separate<"-analyzer-store">, + HelpText<"Source Code Analysis - Abstract Memory Store Models">; +def analyzer_store_EQ : Joined<"-analyzer-store=">, Alias; + +def analyzer_constraints : Separate<"-analyzer-constraints">, + HelpText<"Source Code Analysis - Symbolic Constraint Engines">; +def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">, + Alias; + +def analyzer_output : Separate<"-analyzer-output">, + HelpText<"Source Code Analysis - Output Options">; +def analyzer_output_EQ : Joined<"-analyzer-output=">, + Alias; + +def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, + HelpText<"Force the static analyzer to analyze functions defined in header files">; +def analyzer_display_progress : Flag<"-analyzer-display-progress">, + HelpText<"Emit verbose output about the analyzer's progress">; +def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">, + HelpText<"Use experimental path-sensitive checks">; +def analyzer_experimental_internal_checks : + Flag<"-analyzer-experimental-internal-checks">, + HelpText<"Use new default path-sensitive checks currently in testing">; +def analyze_function : Separate<"-analyze-function">, + HelpText<"Run analysis on specific function">; +def analyze_function_EQ : Joined<"-analyze-function=">, Alias; +def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">, + HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; +def analyzer_no_purge_dead : Flag<"-analyzer-no-purge-dead">, + HelpText<"Don't remove dead symbols, bindings, and constraints before processing a statement">; +def trim_egraph : Flag<"-trim-egraph">, + HelpText<"Only show error-related paths in the analysis graph">; +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">; + +//===----------------------------------------------------------------------===// +// CodeGen Options +//===----------------------------------------------------------------------===// + +def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, + HelpText<"Don't run LLVM optimization passes">; +def disable_red_zone : Flag<"-disable-red-zone">, + HelpText<"Do not emit code that uses the red zone.">; +def g : Flag<"-g">, HelpText<"Generate source level debug information">; +def fno_common : Flag<"-fno-common">, + HelpText<"Compile common globals like normal definitions">; +def no_implicit_float : Flag<"-no-implicit-float">, + HelpText<"Don't generate implicit floating point instructions (x86-only)">; +def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, + HelpText<"Disallow merging of constants.">; +def masm_verbose : Flag<"-masm-verbose">, + HelpText<"Generate verbose assembly output">; +def mcode_model : Separate<"-mcode-model">, + HelpText<"The code model to use">; +def mdebug_pass : Separate<"-mdebug-pass">, + HelpText<"Enable additional debug output">; +def mdisable_fp_elim : Flag<"-mdisable-fp-elim">, + HelpText<"Disable frame pointer elimination optimization">; +def mfloat_abi : Flag<"-mfloat-abi">, + HelpText<"The float ABI to use">; +def mlimit_float_precision : Separate<"-mlimit-float-precision">, + HelpText<"Limit float precision to the given value">; +def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, + HelpText<"Do not put zero initialized data in the BSS">; +def msoft_float : Separate<"-msoft-float">, + HelpText<"Use software floating point">; +def mrelocation_model : Separate<"-mrelocation-model">, + HelpText<"The relocation model to use">; +def munwind_tables : Flag<"-munwind-tables">, + HelpText<"Generate unwinding tables for all functions">; +def O : Joined<"-O">, HelpText<"Optimization level">; +def Os : Flag<"-Os">, HelpText<"Optimize for size">; + +//===----------------------------------------------------------------------===// +// Dependency Output Options +//===----------------------------------------------------------------------===// + +def dependency_file : Separate<"-dependency-file">, + HelpText<"Filename (or -) to write dependency output to">; +def sys_header_deps : Flag<"-sys-header-deps">, + HelpText<"Include system headers in dependency output">; +def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; +def MP : Flag<"-MP">, + HelpText<"Create phony target for each dependency (other than main file)">; + +//===----------------------------------------------------------------------===// +// Diagnostic Options +//===----------------------------------------------------------------------===// + +def dump_build_information : Separate<"-dump-build-information">, + MetaVarName<"filename">, + HelpText<"output a dump of some build information to a file">; +def fno_show_column : Flag<"-fno-show-column">, + HelpText<"Do not include column number on diagnostics">; +def fno_show_source_location : Flag<"-fno-show-source-location">, + HelpText<"Do not include source location information with diagnostics">; +def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, + HelpText<"Do not include source line and caret with diagnostics">; +def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, + HelpText<"Do not include fixit information in diagnostics">; +def w : Flag<"-w">, HelpText<"Suppress all warnings">; +def pedantic : Flag<"-pedantic">; +def pedantic_errors : Flag<"-pedantic-errors">; + +// This gets all -W options, including -Werror, -W[no-]system-headers, etc. The +// driver has stripped off -Wa,foo etc. The driver has also translated -W to +// -Wextra, so we don't need to worry about it. +def W : Joined<"-W">; + +def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, + HelpText<"Print source range spans in numeric form">; +def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, + HelpText<"Print diagnostic name with mappable diagnostics">; +def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"N">, + HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; +def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, + HelpText<"Use colors in diagnostics">; +def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">, + HelpText<"Silence ObjC rewriting warnings">; +def verify : Flag<"-verify">, + HelpText<"Verify emitted diagnostics and warnings">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +def code_completion_at : Separate<"-code-completion-at">, + MetaVarName<"file:line:column">, + HelpText<"Dump code-completion information at a location">; +def code_completion_at_EQ : Joined<"-code-completion-at=">, + Alias; +def no_code_completion_debug_printer : Flag<"-no-code-completion-debug-printer">, + HelpText<"Don't the \"debug\" code-completion print">; +def code_completion_macros : Flag<"-code-completion-macros">, + HelpText<"Include macros in code-completion results">; +def disable_free : Flag<"-disable-free">, + HelpText<"Disable freeing of memory on exit">; +def empty_input_only : Flag<"-empty-input-only">, + HelpText<"Force running on an empty input file">; +def x : Separate<"-x">, HelpText<"Input language type">; +def cxx_inheritance_view : Separate<"-cxx-inheritance-view">, + MetaVarName<"class name">, + HelpText<"View C++ inheritance for a specified class">; +def fixit_at : Separate<"-fixit-at">, MetaVarName<"source-location">, + HelpText<"Perform Fix-It modifications at the given source location">; +def o : Separate<"-o">, MetaVarName<"path">, HelpText<"Specify output file">; +def plugin : Separate<"-plugin">, + HelpText<"Use the named plugin action (use \"help\" to list available options)">; + +def Action_Group : OptionGroup<"">; +let Group = Action_Group in { + +def Eonly : Flag<"-Eonly">, + HelpText<"Just run preprocessor, no output (for timings)">; +def E : Flag<"-E">, + HelpText<"Run preprocessor, emit preprocessed file">; +def dump_raw_tokens : Flag<"-dump-raw-tokens">, + HelpText<"Lex file in raw mode and dump raw tokens">; +def analyze : Flag<"-analyze">, + HelpText<"Run static analysis engine">; +def dump_tokens : Flag<"-dump-tokens">, + HelpText<"Run preprocessor, dump internal rep of tokens">; +def parse_noop : Flag<"-parse-noop">, + HelpText<"Run parser with noop callbacks (for timings)">; +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 parse_print_callbacks : Flag<"-parse-print-callbacks">, + HelpText<"Run parser and print each callback invoked">; +def emit_html : Flag<"-emit-html">, + HelpText<"Output input source as HTML">; +def ast_print : Flag<"-ast-print">, + HelpText<"Build ASTs and then pretty-print them">; +def ast_print_xml : Flag<"-ast-print-xml">, + HelpText<"Build ASTs and then print them in XML format">; +def ast_dump : Flag<"-ast-dump">, + HelpText<"Build ASTs and then debug dump them">; +def ast_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">, + HelpText<"Generate pre-compiled header file">; +def S : Flag<"-S">, + HelpText<"Emit native assembly code">; +def emit_llvm : Flag<"-emit-llvm">, + HelpText<"Build ASTs then convert to LLVM, emit .ll file">; +def emit_llvm_bc : Flag<"-emit-llvm-bc">, + HelpText<"Build ASTs then convert to LLVM, emit .bc file">; +def emit_llvm_only : Flag<"-emit-llvm-only">, + HelpText<"Build ASTs and convert to LLVM, discarding output">; +def rewrite_test : Flag<"-rewrite-test">, + HelpText<"Rewriter playground">; +def rewrite_objc : Flag<"-rewrite-objc">, + HelpText<"Rewrite ObjC into C (code rewriter example)">; +def rewrite_macros : Flag<"-rewrite-macros">, + HelpText<"Expand macros without full preprocessing">; +def rewrite_blocks : Flag<"-rewrite-blocks">, + HelpText<"Rewrite Blocks to C">; + +} + +def relocatable_pch : Flag<"-relocatable-pch">, + HelpText<"Whether to build a relocatable precompiled header">; +def print_stats : Flag<"-print-stats">, + HelpText<"Print performance metrics and statistics">; +def ftime_report : Flag<"-ftime-report">, + HelpText<"Print the amount of time each phase of compilation takes">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +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 fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, + HelpText<"Allow '$' in identifiers">; +def femit_all_decls : Flag<"-femit-all-decls">, + HelpText<"Emit all declarations, even if unused">; +def fblocks : Flag<"-fblocks">, + HelpText<"enable the 'blocks' language feature">; +def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; +def fexceptions : Flag<"-fexceptions">, + HelpText<"Enable support for exception handling">; +def ffreestanding : Flag<"-ffreestanding">, + HelpText<"Assert that the compilation takes place in a freestanding environment">; +def fgnu_runtime : Flag<"-fgnu-runtime">, + HelpText<"Generate output compatible with the standard GNU Objective-C runtime">; +def std_EQ : Joined<"-std=">, + HelpText<"Language standard to compile for">; +def fms_extensions : Flag<"-fms-extensions">, + HelpText<"Accept some non-standard constructs used in Microsoft header files ">; +def main_file_name : Separate<"-main-file-name">, + HelpText<"Main file name to use for debug info">; +def fno_elide_constructors : Flag<"-fno-elide-constructors">, + HelpText<"Disable C++ copy constructor elision">; +def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, + HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">; +def fno_math_errno : Flag<"-fno-math-errno">, + HelpText<"Don't require math functions to respect errno">; +def fno_signed_char : Flag<"-fno-signed-char">, + HelpText<"Char is unsigned">; +def fno_operator_names : Flag<"-fno-operator-names">, + HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; +def fconstant_string_class : Separate<"-fconstant-string-class">, + MetaVarName<"class name">, + HelpText<"Specify the class to use for constant Objective-C string objects.">; +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 print_ivar_layout : Flag<"-print-ivar-layout">, + HelpText<"Enable Objective-C Ivar layout bitmap print trace">; +def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, + HelpText<"enable objective-c's nonfragile abi">; +def ftrapv : Flag<"-ftrapv">, + HelpText<"Trap on integer overflow">; +def pic_level : Separate<"-pic-level">, + HelpText<"-Value for __PIC__">; +def pthread : Flag<"-pthread">, + HelpText<"Support POSIX threads in generated code">; +def fpascal_strings : Flag<"-fpascal-strings">, + HelpText<"Recognize and construct Pascal-style string literals">; +def fno_rtti : Flag<"-fno-rtti">, + HelpText<"Disable generation of rtti information">; +def fshort_wchar : Flag<"-fshort-wchar">, + HelpText<"Force wchar_t to be a short unsigned int">; +def static_define : Flag<"-static-define">, + HelpText<"Should __STATIC__ be defined">; +def stack_protector : Separate<"-stack-protector">, + HelpText<"Enable stack protectors">; +def fvisibility : Separate<"-fvisibility">, + HelpText<"Default symbol visibility">; +def ftemplate_depth : Separate<"-ftemplate-depth">, + HelpText<"Maximum depth of recursive template instantiation">; +def trigraphs : Flag<"-trigraphs">, + HelpText<"Process trigraph sequences">; +def fwritable_strings : Flag<"-fwritable-strings">, + HelpText<"Store string literals as writable data">; + +//===----------------------------------------------------------------------===// +// Header Search Options +//===----------------------------------------------------------------------===// + +def nostdinc : Flag<"-nostdinc">, + HelpText<"Disable standard #include directories">; +def nobuiltininc : Flag<"-nobuiltininc">, + HelpText<"Disable builtin #include directories">; +def F : JoinedOrSeparate<"-F">, MetaVarName<"directory">, + HelpText<"Add directory to framework include search path">; +def I : JoinedOrSeparate<"-I">, MetaVarName<"directory">, + HelpText<"Add directory to include search path">; +def idirafter : Separate<"-idirafter">, MetaVarName<"directory">, + HelpText<"Add directory to AFTER include search path">; +def iquote : Separate<"-iquote">, MetaVarName<"directory">, + HelpText<"Add directory to QUOTE include search path">; +def isystem : Separate<"-isystem">, MetaVarName<"directory">, + HelpText<"Add directory to SYSTEM include search path">; +def iprefix : Separate<"-iprefix">, MetaVarName<"prefix">, + HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">; +def iwithprefix : Separate<"-iwithprefix">, MetaVarName<"dir">, + HelpText<"Set directory to SYSTEM include search path with prefix">; +def iwithprefixbefore : Separate<"-iwithprefixbefore">, MetaVarName<"dir">, + HelpText<"Set directory to include search path with prefix">; +def isysroot : Separate<"-isysroot">, MetaVarName<"dir">, + HelpText<"Set the system root directory (usually /)">; +def v : Flag<"-v">, HelpText<"Enable verbose output">; + +//===----------------------------------------------------------------------===// +// Preprocessor Options +//===----------------------------------------------------------------------===// + +def D : JoinedOrSeparate<"-D">, MetaVarName<"macro">, + HelpText<"Predefine the specified macro">; +def include_ : Separate<"-include">, MetaVarName<"file">, EnumName<"include">, + HelpText<"Include file before parsing">; +def imacros : Separate<"-imacros">, MetaVarName<"file">, + HelpText<"Include macros from file before parsing">; +def include_pch : Separate<"-include-pch">, MetaVarName<"file">, + HelpText<"Include precompiled header file">; +def include_pth : Separate<"-include-pth">, MetaVarName<"file">, + HelpText<"Include file before parsing">; +def token_cache : Separate<"-token-cache">, MetaVarName<"path">, + HelpText<"Use specified token cache file">; +def U : JoinedOrSeparate<"-U">, MetaVarName<"macro">, + HelpText<"Undefine the specified macro">; +def undef : Flag<"-undef">, MetaVarName<"macro">, + HelpText<"undef all system defines">; + +//===----------------------------------------------------------------------===// +// Preprocessed Output Options +//===----------------------------------------------------------------------===// + +def P : Flag<"-P">, + HelpText<"Disable linemarker output in -E mode">; +def C : Flag<"-C">, + HelpText<"Enable comment output in -E mode">; +def CC : Flag<"-CC">, + HelpText<"Enable comment output in -E mode, even from macro expansions">; +def dM : Flag<"-dM">, + HelpText<"Print macro definitions in -E mode instead of normal output">; +def dD : Flag<"-dD">, + HelpText<"Print macro definitions in -E mode in addition to normal output">; diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile index c0f2cc7..18f3e58 100644 --- a/include/clang/Driver/Makefile +++ b/include/clang/Driver/Makefile @@ -5,11 +5,11 @@ TABLEGEN_INC_FILES_COMMON = 1 include $(LEVEL)/Makefile.common -$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(ObjDir)/.dir +$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang Driver Option tables with tblgen" $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< -$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(ObjDir)/.dir +$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(TBLGEN) $(ObjDir)/.dir $(Echo) "Building Clang CC1 Option tables with tblgen" $(Verb) $(TableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< diff --git a/include/clang/Driver/OptParser.td b/include/clang/Driver/OptParser.td index 70b59c6..f5b6980 100644 --- a/include/clang/Driver/OptParser.td +++ b/include/clang/Driver/OptParser.td @@ -14,14 +14,20 @@ // Define the kinds of options. -class OptionKind { +class OptionKind { string Name = name; // The kind precedence, kinds with lower precedence are matched first. int Precedence = predecence; + // Indicate a sentinel option. + bit Sentinel = sentinel; } // An option group. def KIND_GROUP : OptionKind<"Group">; +// The input option kind. +def KIND_INPUT : OptionKind<"Input", 1, 1>; +// The unknown option kind. +def KIND_UNKNOWN : OptionKind<"Unknown", 2, 1>; // A flag with no values. def KIND_FLAG : OptionKind<"Flag">; // An option which prefixes its (single) value. @@ -114,3 +120,10 @@ class Flags flags> { list Flags = flags; } class Group { OptionGroup Group = group; } class HelpText { string HelpText = text; } class MetaVarName { string MetaVarName = name; } + +// Predefined options. + +// FIXME: Have generator validate that these appear in correct position (and +// aren't duplicated). +def INPUT : Option<"", KIND_INPUT>, Flags<[DriverOption]>; +def UNKNOWN : Option<"", KIND_UNKNOWN>; diff --git a/include/clang/Driver/OptSpecifier.h b/include/clang/Driver/OptSpecifier.h index c38b36c..bb1cd17 100644 --- a/include/clang/Driver/OptSpecifier.h +++ b/include/clang/Driver/OptSpecifier.h @@ -22,9 +22,12 @@ namespace driver { explicit OptSpecifier(bool); // DO NOT IMPLEMENT public: + OptSpecifier() : ID(0) {} /*implicit*/ OptSpecifier(unsigned _ID) : ID(_ID) {} /*implicit*/ OptSpecifier(const Option *Opt); + bool isValid() const { return ID != 0; } + unsigned getID() const { return ID; } bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); } diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h index b05d5af..ac312cd 100644 --- a/include/clang/Driver/Options.h +++ b/include/clang/Driver/Options.h @@ -17,8 +17,6 @@ namespace driver { namespace options { enum ID { OPT_INVALID = 0, // This is not an option ID. - OPT_INPUT, // Reserved ID for input option. - OPT_UNKNOWN, // Reserved ID for unknown option. #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) OPT_##ID, #include "clang/Driver/Options.inc" diff --git a/include/clang/Frontend/ASTConsumers.h b/include/clang/Frontend/ASTConsumers.h index 0e7d55e..26efa97 100644 --- a/include/clang/Frontend/ASTConsumers.h +++ b/include/clang/Frontend/ASTConsumers.h @@ -83,6 +83,7 @@ ASTConsumer *CreateBackendConsumer(BackendAction Action, const LangOptions &Features, const CodeGenOptions &CodeGenOpts, const TargetOptions &TargetOpts, + bool TimePasses, const std::string &ModuleID, llvm::raw_ostream *OS, llvm::LLVMContext& C); diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 7dfabba..04dc5ed 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -22,16 +22,17 @@ #include namespace clang { - class FileManager; - class FileEntry; - class SourceManager; - class Diagnostic; - class TextDiagnosticBuffer; - class HeaderSearch; - class TargetInfo; - class Preprocessor; - class ASTContext; - class Decl; +class ASTContext; +class CompilerInvocation; +class Decl; +class Diagnostic; +class FileEntry; +class FileManager; +class HeaderSearch; +class Preprocessor; +class SourceManager; +class TargetInfo; +class TextDiagnosticBuffer; using namespace idx; @@ -92,21 +93,35 @@ public: /// /// \param Filename - The PCH file to load. /// - /// \param diagClient - The diagnostics client to use. Specify NULL + /// \param DiagClient - The diagnostics client to use. Specify NULL /// to use a default client that emits warnings/errors to standard error. /// The ASTUnit objects takes ownership of this object. /// - /// \param FileMgr - The FileManager to use. - /// /// \param ErrMsg - Error message to report if the PCH file could not be /// loaded. /// /// \returns - The initialized ASTUnit or null if the PCH failed to load. static ASTUnit *LoadFromPCHFile(const std::string &Filename, std::string *ErrMsg = 0, - DiagnosticClient *diagClient = NULL, + DiagnosticClient *DiagClient = NULL, bool OnlyLocalDecls = false, bool UseBumpAllocator = false); + + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a + /// CompilerInvocation object. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. + /// + /// \param Diags - The diagnostics engine to use for reporting errors. + // + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCompilerInvocation(const CompilerInvocation &CI, + Diagnostic &Diags, + bool OnlyLocalDecls = false, + bool UseBumpAllocator = false); + }; } // namespace clang diff --git a/include/clang/Frontend/AnalysisConsumer.h b/include/clang/Frontend/AnalysisConsumer.h index 7a32433..24fed6e 100644 --- a/include/clang/Frontend/AnalysisConsumer.h +++ b/include/clang/Frontend/AnalysisConsumer.h @@ -77,7 +77,7 @@ public: AnalyzeAll = 0; AnalyzerDisplayProgress = 0; EagerlyAssume = 0; - PurgeDead = 0; + PurgeDead = 1; TrimGraph = 0; VisualizeEGDot = 0; VisualizeEGUbi = 0; diff --git a/include/clang/Frontend/CommandLineSourceLoc.h b/include/clang/Frontend/CommandLineSourceLoc.h index d5a0598..bea468b 100644 --- a/include/clang/Frontend/CommandLineSourceLoc.h +++ b/include/clang/Frontend/CommandLineSourceLoc.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H #include "llvm/Support/CommandLine.h" -#include +#include "llvm/Support/raw_ostream.h" namespace clang { @@ -25,6 +25,23 @@ struct ParsedSourceLocation { std::string FileName; unsigned Line; unsigned Column; + +public: + /// Construct a parsed source location from a string; the Filename is empty on + /// error. + static ParsedSourceLocation FromString(llvm::StringRef Str) { + ParsedSourceLocation PSL; + std::pair ColSplit = Str.rsplit(':'); + std::pair LineSplit = + ColSplit.first.rsplit(':'); + + // If both tail splits were valid integers, return success. + if (!ColSplit.second.getAsInteger(10, PSL.Column) && + !LineSplit.second.getAsInteger(10, PSL.Line)) + PSL.FileName = LineSplit.first; + + return PSL; + } }; } @@ -48,35 +65,13 @@ namespace llvm { clang::ParsedSourceLocation &Val) { using namespace clang; - const char *ExpectedFormat - = "source location must be of the form filename:line:column"; - StringRef::size_type SecondColon = ArgValue.rfind(':'); - if (SecondColon == std::string::npos) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - - unsigned Column; - if (ArgValue.substr(SecondColon + 1).getAsInteger(10, Column)) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - ArgValue = ArgValue.substr(0, SecondColon); - - StringRef::size_type FirstColon = ArgValue.rfind(':'); - if (FirstColon == std::string::npos) { - std::fprintf(stderr, "%s\n", ExpectedFormat); - return true; - } - unsigned Line; - if (ArgValue.substr(FirstColon + 1).getAsInteger(10, Line)) { - std::fprintf(stderr, "%s\n", ExpectedFormat); + Val = ParsedSourceLocation::FromString(ArgValue); + if (Val.FileName.empty()) { + errs() << "error: " + << "source location must be of the form filename:line:column\n"; return true; } - Val.FileName = ArgValue.substr(0, FirstColon); - Val.Line = Line; - Val.Column = Column; return false; } } diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index ed28050..d7e7d99 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -21,6 +21,7 @@ namespace llvm { class LLVMContext; class raw_ostream; class raw_fd_ostream; +class Timer; } namespace clang { @@ -89,6 +90,9 @@ class CompilerInstance { /// The code completion consumer. llvm::OwningPtr CompletionConsumer; + /// The frontend timer + llvm::OwningPtr FrontendTimer; + /// The list of active output files. std::list< std::pair > OutputFiles; @@ -367,6 +371,17 @@ public: void setCodeCompletionConsumer(CodeCompleteConsumer *Value); /// } + /// @name Frontend timer + /// { + + bool hasFrontendTimer() const { return FrontendTimer != 0; } + + llvm::Timer &getFrontendTimer() const { + assert(FrontendTimer && "Compiler instance has no frontend timer!"); + return *FrontendTimer; + } + + /// } /// @name Output Files /// { @@ -462,6 +477,9 @@ public: bool UseDebugPrinter, bool ShowMacros, llvm::raw_ostream &OS); + /// Create the frontend timer and replace any existing one with it. + void createFrontendTimer(); + /// Create the default output file (from the invocation's options) and add it /// to the list of tracked output files. llvm::raw_fd_ostream * diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index 9d068c5..e7c51aa 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -31,6 +31,8 @@ namespace llvm { namespace clang { +class Diagnostic; + /// CompilerInvocation - Helper class for holding the data necessary to invoke /// the compiler. /// @@ -77,12 +79,18 @@ public: /// CreateFromArgs - Create a compiler invocation from a list of input /// options. /// - /// FIXME: Documenting error behavior. - /// /// \param Res [out] - The resulting invocation. - /// \param Args - The input argument strings. - static void CreateFromArgs(CompilerInvocation &Res, - const llvm::SmallVectorImpl &Args); + /// \param ArgBegin - The first element in the argument vector. + /// \param ArgEnd - The last element in the argument vector. + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + /// \param Diags - The diagnostic engine to use for errors. + static void CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, + const char **ArgEnd, const char *Argv0, + void *MainAddr, + Diagnostic &Diags); /// toArgs - Convert the CompilerInvocation to a list of strings suitable for /// passing to CreateFromArgs. diff --git a/include/clang/Frontend/DeclXML.def b/include/clang/Frontend/DeclXML.def index 8b80d1d..c750492 100644 --- a/include/clang/Frontend/DeclXML.def +++ b/include/clang/Frontend/DeclXML.def @@ -7,46 +7,46 @@ // //===----------------------------------------------------------------------===// // -// This file defines the XML statement database structure as written in -// sub-nodes of the XML document. +// This file defines the XML statement database structure as written in +// sub-nodes of the XML document. // The semantics of the attributes and enums are mostly self-documenting // by looking at the appropriate internally used functions and values. // The following macros are used: // -// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete -// statement of class CLASS where CLASS is a class name used internally by clang. -// After a NODE_XML the definition of all (optional) attributes of that statement +// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete +// statement of class CLASS where CLASS is a class name used internally by clang. +// After a NODE_XML the definition of all (optional) attributes of that statement // node and possible sub-nodes follows. // // END_NODE_XML - Closes the attribute definition of the current node. // -// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a -// string, which value uniquely identify that statement. Other nodes may refer +// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a +// string, which value uniquely identify that statement. Other nodes may refer // by reference attributes to this value (currently used only for Label). // // TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an // expression by a "type" attribute. FN is internally used by clang. -// -// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally +// +// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally // used by clang. A boolean attribute have the values "0" or "1". // -// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves -// a special handling. See the appropriate documentations. +// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves +// a special handling. See the appropriate documentations. // // ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of // a statement in the source file(s). // -// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. -// Optional attributes are omitted for boolean types, if the value is false, -// for integral types, if the value is null and for strings, +// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. +// Optional attributes are omitted for boolean types, if the value is false, +// for integral types, if the value is null and for strings, // if the value is the empty string. FN is internally used by clang. // // ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value -// is an enumeration defined with ENUM_XML macros immediately following after -// that macro. An optional attribute is ommited, if the particular enum is the +// is an enumeration defined with ENUM_XML macros immediately following after +// that macro. An optional attribute is ommited, if the particular enum is the // empty string. FN is internally used by clang. -// -// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is +// +// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is // internally used by clang. // // END_ENUM_XML - Closes the enumeration definition of the current attribute. @@ -55,7 +55,7 @@ // // SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes. // -// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or +// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or // its sub-classes. // //===----------------------------------------------------------------------===// @@ -114,8 +114,8 @@ NODE_XML(CXXMethodDecl, "CXXMethodDecl") TYPE_ATTRIBUTE_XML(getType()->getAs()->getResultType()) ATTRIBUTE_XML(getType()->getAs(), "function_type") ATTRIBUTE_OPT_XML(isInlineSpecified(), "inline") - ATTRIBUTE_OPT_XML(isStatic(), "static") - ATTRIBUTE_OPT_XML(isVirtual(), "virtual") + ATTRIBUTE_OPT_XML(isStatic(), "static") + ATTRIBUTE_OPT_XML(isVirtual(), "virtual") ATTRIBUTE_XML(getNumParams(), "num_args") SUB_NODE_SEQUENCE_XML(ParmVarDecl) //SUB_NODE_OPT_XML("Body") @@ -124,7 +124,7 @@ END_NODE_XML //NODE_XML("Body") // SUB_NODE_XML(Stmt) //END_NODE_XML - + NODE_XML(NamespaceDecl, "Namespace") ID_ATTRIBUTE_XML ATTRIBUTE_FILE_LOCATION_XML @@ -152,7 +152,7 @@ NODE_XML(RecordDecl, "Record") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") ATTRIBUTE_OPT_XML(isDefinition() == false, "forward") - ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates + ATTRIBUTE_XML(getTypeForDecl(), "type") // refers to the type this decl creates SUB_NODE_SEQUENCE_XML(FieldDecl) END_NODE_XML @@ -162,7 +162,7 @@ NODE_XML(EnumDecl, "Enum") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") ATTRIBUTE_OPT_XML(isDefinition() == false, "forward") - ATTRIBUTE_SPECIAL_XML(getIntegerType(), "type") // is NULL in pure declarations thus deserves special handling + ATTRIBUTE_SPECIAL_XML(getIntegerType(), "type") // is NULL in pure declarations thus deserves special handling SUB_NODE_SEQUENCE_XML(EnumConstantDecl) // only present in definition END_NODE_XML @@ -209,7 +209,7 @@ NODE_XML(VarDecl, "Var") ENUM_XML(VarDecl::Static, "static") ENUM_XML(VarDecl::PrivateExtern, "__private_extern__") END_ENUM_XML - SUB_NODE_OPT_XML(Expr) // init expr + SUB_NODE_OPT_XML(Expr) // init expr END_NODE_XML NODE_XML(ParmVarDecl, "ParmVar") @@ -218,7 +218,7 @@ NODE_XML(ParmVarDecl, "ParmVar") ATTRIBUTE_XML(getDeclContext(), "context") ATTRIBUTE_XML(getNameAsString(), "name") TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_OPT_XML(Expr) // default argument expression + SUB_NODE_OPT_XML(Expr) // default argument expression END_NODE_XML NODE_XML(LinkageSpecDecl, "LinkageSpec") @@ -234,7 +234,7 @@ END_NODE_XML //===----------------------------------------------------------------------===// #undef NODE_XML -#undef ID_ATTRIBUTE_XML +#undef ID_ATTRIBUTE_XML #undef TYPE_ATTRIBUTE_XML #undef ATTRIBUTE_XML #undef ATTRIBUTE_SPECIAL_XML @@ -243,8 +243,8 @@ END_NODE_XML #undef ATTRIBUTE_ENUM_OPT_XML #undef ATTRIBUTE_FILE_LOCATION_XML #undef ENUM_XML -#undef END_ENUM_XML -#undef END_NODE_XML +#undef END_ENUM_XML +#undef END_NODE_XML #undef SUB_NODE_XML #undef SUB_NODE_SEQUENCE_XML #undef SUB_NODE_OPT_XML diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h index 469ea53..3042767 100644 --- a/include/clang/Frontend/FrontendAction.h +++ b/include/clang/Frontend/FrontendAction.h @@ -14,10 +14,6 @@ #include "llvm/ADT/OwningPtr.h" #include -namespace llvm { -class Timer; -} - namespace clang { class ASTUnit; class ASTConsumer; @@ -29,7 +25,6 @@ class FrontendAction { std::string CurrentFile; llvm::OwningPtr CurrentASTUnit; CompilerInstance *Instance; - llvm::Timer *CurrentTimer; protected: /// @name Implementation Action Interface @@ -112,18 +107,6 @@ public: void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0); /// @} - /// @name Timing Utilities - /// @{ - - llvm::Timer *getCurrentTimer() const { - return CurrentTimer; - } - - void setCurrentTimer(llvm::Timer *Value) { - CurrentTimer = Value; - } - - /// @} /// @name Supported Modes /// @{ diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 197a2a0..c1ec8e7 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -107,7 +107,7 @@ public: public: FrontendOptions() { - DebugCodeCompletionPrinter = 0; + DebugCodeCompletionPrinter = 1; DisableFree = 0; EmptyInputOnly = 0; ProgramAction = frontend::ParseSyntaxOnly; diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h new file mode 100644 index 0000000..441d34f --- /dev/null +++ b/include/clang/Frontend/LangStandard.h @@ -0,0 +1,83 @@ +//===--- LangStandard.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H +#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H + +#include "llvm/ADT/StringRef.h" + +namespace clang { + +namespace frontend { + +enum LangFeatures { + BCPLComment = (1 << 0), + C99 = (1 << 1), + CPlusPlus = (1 << 2), + CPlusPlus0x = (1 << 3), + Digraphs = (1 << 4), + GNUMode = (1 << 5), + HexFloat = (1 << 6), + ImplicitInt = (1 << 7) +}; + +} + +/// LangStandard - Information about the properties of a particular language +/// standard. +struct LangStandard { + enum Kind { +#define LANGSTANDARD(id, name, desc, features) \ + lang_##id, +#include "clang/Frontend/LangStandards.def" + lang_unspecified + }; + + const char *ShortName; + const char *Description; + unsigned Flags; + +public: + /// getName - Get the name of this standard. + const char *getName() const { return ShortName; } + + /// getDescription - Get the description of this standard. + const char *getDescription() const { return Description; } + + /// hasBCPLComments - Language supports '//' comments. + bool hasBCPLComments() const { return Flags & frontend::BCPLComment; } + + /// isC99 - Language is a superset of C99. + bool isC99() const { return Flags & frontend::C99; } + + /// isCPlusPlus - Language is a C++ variant. + bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } + + /// isCPlusPlus0x - Language is a C++0x variant. + bool isCPlusPlus0x() const { return Flags & frontend::CPlusPlus0x; } + + /// hasDigraphs - Language supports digraphs. + bool hasDigraphs() const { return Flags & frontend::Digraphs; } + + /// isGNUMode - Language includes GNU extensions. + bool isGNUMode() const { return Flags & frontend::GNUMode; } + + /// hasHexFloats - Language supports hexadecimal float constants. + bool hasHexFloats() const { return Flags & frontend::HexFloat; } + + /// hasImplicitInt - Language allows variables to be typed as int implicitly. + bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; } + + static const LangStandard &getLangStandardForKind(Kind K); + static const LangStandard *getLangStandardForName(llvm::StringRef Name); +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def new file mode 100644 index 0000000..52aa463 --- /dev/null +++ b/include/clang/Frontend/LangStandards.def @@ -0,0 +1,83 @@ +//===-- LangStandards.def - Language Standard Data --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LANGSTANDARD +#error "LANGSTANDARD must be defined before including this file" +#endif + +/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// +/// \param IDENT - The name of the standard as a C++ identifier. +/// \param NAME - The name of the standard. +/// \param DESC - A short description of the standard. +/// \param FEATURES - The standard features as flags, these are enums from the +/// clang::frontend namespace, which is assumed to be be available. + +// C89-ish modes. +LANGSTANDARD(c89, "c89", + "ISO C 1990", + ImplicitInt) +LANGSTANDARD(c90, "c90", + "ISO C 1990", + ImplicitInt) +LANGSTANDARD(iso9899_1990, "iso9899:1990", + "ISO C 1990", + ImplicitInt) + +LANGSTANDARD(c94, "iso9899:199409", + "ISO C 1990 with amendment 1", + Digraphs | ImplicitInt) + +LANGSTANDARD(gnu89, "gnu89", + "ISO C 1990 with GNU extensions", + BCPLComment | Digraphs | GNUMode | ImplicitInt) + +// C99-ish modes +LANGSTANDARD(c99, "c99", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(c9x, "c9x", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_1999, + "iso9899:1999", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_199x, + "iso9899:199x", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) + +LANGSTANDARD(gnu99, "gnu99", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat | Digraphs) +LANGSTANDARD(gnu9x, "gnu9x", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat) + +// C++ modes +LANGSTANDARD(cxx98, "c++98", + "ISO C++ 1998 with amendments", + BCPLComment | CPlusPlus | Digraphs) +LANGSTANDARD(gnucxx98, "gnu++98", + "ISO C++ 1998 with " "amendments and GNU extensions", + BCPLComment | CPlusPlus | Digraphs | GNUMode) + +LANGSTANDARD(cxx0x, "c++0x", + "Upcoming ISO C++ 200x with amendments", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs) +LANGSTANDARD(gnucxx0x, "gnu++0x", + "Upcoming ISO C++ 200x with amendments and GNU extensions", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode) + +// OpenCL + +LANGSTANDARD(opencl, "cl", + "OpenCL 1.0", + BCPLComment | C99 | Digraphs | HexFloat) + +#undef LANGSTANDARD diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index b2bb9a1..98463c3 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -336,7 +336,9 @@ namespace clang { /// \brief The ObjC 'id' type. PREDEF_TYPE_OBJC_ID = 26, /// \brief The ObjC 'Class' type. - PREDEF_TYPE_OBJC_CLASS = 27 + PREDEF_TYPE_OBJC_CLASS = 27, + /// \brief The ObjC 'SEL' type. + PREDEF_TYPE_OBJC_SEL = 28 }; /// \brief The number of predefined type IDs that are reserved for @@ -438,7 +440,9 @@ namespace clang { /// \brief Block descriptor type for Blocks CodeGen SPECIAL_TYPE_BLOCK_DESCRIPTOR = 12, /// \brief Block extedned descriptor type for Blocks CodeGen - SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13 + SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR = 13, + /// \brief Objective-C "SEL" redefinition type + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 14 }; /// \brief Record codes for each kind of declaration. diff --git a/include/clang/Frontend/PathDiagnosticClients.h b/include/clang/Frontend/PathDiagnosticClients.h index 98831ba..f8d2eeb 100644 --- a/include/clang/Frontend/PathDiagnosticClients.h +++ b/include/clang/Frontend/PathDiagnosticClients.h @@ -14,9 +14,7 @@ #ifndef LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLIENTS_H #define LLVM_CLANG_FRONTEND_PATH_DIAGNOSTIC_CLiENTS_H -#include #include -#include "llvm/ADT/SmallVector.h" namespace clang { diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def index fd79cf0..2f0da9e 100644 --- a/include/clang/Frontend/StmtXML.def +++ b/include/clang/Frontend/StmtXML.def @@ -7,46 +7,46 @@ // //===----------------------------------------------------------------------===// // -// This file defines the XML statement database structure as written in -// sub-nodes of the XML document. +// This file defines the XML statement database structure as written in +// sub-nodes of the XML document. // The semantics of the attributes and enums are mostly self-documenting // by looking at the appropriate internally used functions and values. // The following macros are used: // -// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete -// statement of class CLASS where CLASS is a class name used internally by clang. -// After a NODE_XML the definition of all (optional) attributes of that statement +// NODE_XML( CLASS, NAME ) - A node of name NAME denotes a concrete +// statement of class CLASS where CLASS is a class name used internally by clang. +// After a NODE_XML the definition of all (optional) attributes of that statement // node and possible sub-nodes follows. // // END_NODE_XML - Closes the attribute definition of the current node. // -// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a -// string, which value uniquely identify that statement. Other nodes may refer +// ID_ATTRIBUTE_XML - Some statement nodes have an "id" attribute containing a +// string, which value uniquely identify that statement. Other nodes may refer // by reference attributes to this value (currently used only for Label). // // TYPE_ATTRIBUTE_XML( FN ) - Type nodes refer to the result type id of an // expression by a "type" attribute. FN is internally used by clang. -// -// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally +// +// ATTRIBUTE_XML( FN, NAME ) - An attribute named NAME. FN is internally // used by clang. A boolean attribute have the values "0" or "1". // -// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves -// a special handling. See the appropriate documentations. +// ATTRIBUTE_SPECIAL_XML( FN, NAME ) - An attribute named NAME which deserves +// a special handling. See the appropriate documentations. // // ATTRIBUTE_FILE_LOCATION_XML - A bunch of attributes denoting the location of // a statement in the source file(s). // -// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. -// Optional attributes are omitted for boolean types, if the value is false, -// for integral types, if the value is null and for strings, +// ATTRIBUTE_OPT_XML( FN, NAME ) - An optional attribute named NAME. +// Optional attributes are omitted for boolean types, if the value is false, +// for integral types, if the value is null and for strings, // if the value is the empty string. FN is internally used by clang. // // ATTRIBUTE_ENUM[_OPT]_XML( FN, NAME ) - An attribute named NAME. The value -// is an enumeration defined with ENUM_XML macros immediately following after -// that macro. An optional attribute is ommited, if the particular enum is the +// is an enumeration defined with ENUM_XML macros immediately following after +// that macro. An optional attribute is ommited, if the particular enum is the // empty string. FN is internally used by clang. -// -// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is +// +// ENUM_XML( VALUE, NAME ) - An enumeration element named NAME. VALUE is // internally used by clang. // // END_ENUM_XML - Closes the enumeration definition of the current attribute. @@ -55,7 +55,7 @@ // // SUB_NODE_OPT_XML( CLASS ) - An optional sub-node of class CLASS or its sub-classes. // -// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or +// SUB_NODE_SEQUENCE_XML( CLASS ) - Zero or more sub-nodes of class CLASS or // its sub-classes. // //===----------------------------------------------------------------------===// @@ -94,21 +94,21 @@ END_NODE_XML NODE_XML(CaseStmt, "CaseStmt") // case expr: body; ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body SUB_NODE_XML(Expr) // expr SUB_NODE_XML(Expr) // rhs expr in gc extension: case expr .. expr: body; END_NODE_XML NODE_XML(DefaultStmt, "DefaultStmt") // default: body; ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body END_NODE_XML NODE_XML(LabelStmt, "LabelStmt") // Label: body; ID_ATTRIBUTE_XML ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getName(), "name") // string - SUB_NODE_XML(Stmt) // body + SUB_NODE_XML(Stmt) // body END_NODE_XML NODE_XML(IfStmt, "IfStmt") // if (cond) stmt1; else stmt2; @@ -173,23 +173,23 @@ NODE_XML(AsmStmt, "AsmStmt") // GNU inline-assembly sta // FIXME END_NODE_XML -NODE_XML(DeclStmt, "DeclStmt") // a declaration statement +NODE_XML(DeclStmt, "DeclStmt") // a declaration statement ATTRIBUTE_FILE_LOCATION_XML - SUB_NODE_SEQUENCE_XML(Decl) + SUB_NODE_SEQUENCE_XML(Decl) END_NODE_XML // C++ statements NODE_XML(CXXTryStmt, "CXXTryStmt") // try CompoundStmt CXXCatchStmt1 CXXCatchStmt2 .. ATTRIBUTE_FILE_LOCATION_XML ATTRIBUTE_XML(getNumHandlers(), "num_handlers") - SUB_NODE_XML(CompoundStmt) - SUB_NODE_SEQUENCE_XML(CXXCatchStmt) + SUB_NODE_XML(CompoundStmt) + SUB_NODE_SEQUENCE_XML(CXXCatchStmt) END_NODE_XML NODE_XML(CXXCatchStmt, "CXXCatchStmt") // catch (decl) Stmt ATTRIBUTE_FILE_LOCATION_XML SUB_NODE_XML(VarDecl) - SUB_NODE_XML(Stmt) + SUB_NODE_XML(Stmt) END_NODE_XML // Expressions @@ -234,7 +234,7 @@ NODE_XML(StringLiteral, "StringLiteral") ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) ATTRIBUTE_SPECIAL_XML(getStrData(), "value") // string, special handling for escaping needed - ATTRIBUTE_OPT_XML(isWide(), "is_wide") // boolean + ATTRIBUTE_OPT_XML(isWide(), "is_wide") // boolean END_NODE_XML NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op @@ -251,7 +251,7 @@ NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op ENUM_XML(UnaryOperator::Minus, "minus") ENUM_XML(UnaryOperator::Not, "not") // bitwise not ENUM_XML(UnaryOperator::LNot, "lnot") // boolean not - ENUM_XML(UnaryOperator::Real, "__real") + ENUM_XML(UnaryOperator::Real, "__real") ENUM_XML(UnaryOperator::Imag, "__imag") ENUM_XML(UnaryOperator::Extension, "__extension__") ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof") @@ -314,7 +314,7 @@ END_NODE_XML NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr") // sizeof(expr) or alignof(expr) ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_XML(isSizeOf(), "is_sizeof") + ATTRIBUTE_XML(isSizeOf(), "is_sizeof") ATTRIBUTE_XML(isArgumentType(), "is_type") // "1" if expr denotes a type ATTRIBUTE_SPECIAL_XML(getArgumentType(), "type_ref") // optional, denotes the type of expr, if is_type=="1", special handling needed since getArgumentType() could assert SUB_NODE_OPT_XML(Expr) // expr, if is_type=="0" @@ -346,29 +346,29 @@ END_NODE_XML NODE_XML(CStyleCastExpr, "CStyleCastExpr") // (type)expr ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) + TYPE_ATTRIBUTE_XML(getType()) ATTRIBUTE_XML(getTypeAsWritten(), "type_ref") // denotes the type as written in the source code SUB_NODE_XML(Expr) // expr END_NODE_XML NODE_XML(ImplicitCastExpr, "ImplicitCastExpr") ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_XML(Expr) + TYPE_ATTRIBUTE_XML(getType()) + SUB_NODE_XML(Expr) END_NODE_XML -NODE_XML(CompoundLiteralExpr, "CompoundLiteralExpr") // [C99 6.5.2.5] +NODE_XML(CompoundLiteralExpr, "CompoundLiteralExpr") // [C99 6.5.2.5] SUB_NODE_XML(Expr) // init END_NODE_XML NODE_XML(ExtVectorElementExpr, "ExtVectorElementExpr") - SUB_NODE_XML(Expr) // base + SUB_NODE_XML(Expr) // base END_NODE_XML NODE_XML(InitListExpr, "InitListExpr") // struct foo x = { expr1, { expr2, expr3 } }; ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_OPT_XML(getInitializedFieldInUnion(), "field_ref") // if a union is initialized, this refers to the initialized union field id + ATTRIBUTE_OPT_XML(getInitializedFieldInUnion(), "field_ref") // if a union is initialized, this refers to the initialized union field id ATTRIBUTE_XML(getNumInits(), "num_inits") // unsigned SUB_NODE_SEQUENCE_XML(Expr) // expr1..exprN END_NODE_XML @@ -412,8 +412,8 @@ END_NODE_XML NODE_XML(TypesCompatibleExpr, "TypesCompatibleExpr") // GNU builtin-in function __builtin_types_compatible_p ATTRIBUTE_FILE_LOCATION_XML TYPE_ATTRIBUTE_XML(getType()) - ATTRIBUTE_XML(getArgType1(), "type1_ref") // id of type1 - ATTRIBUTE_XML(getArgType2(), "type2_ref") // id of type2 + ATTRIBUTE_XML(getArgType1(), "type1_ref") // id of type1 + ATTRIBUTE_XML(getArgType2(), "type2_ref") // id of type2 END_NODE_XML NODE_XML(ChooseExpr, "ChooseExpr") // GNU builtin-in function __builtin_choose_expr(expr1, expr2, expr3) @@ -495,16 +495,9 @@ NODE_XML(CXXDefaultArgExpr, "CXXDefaultArgExpr") ATTRIBUTE_XML(getParam(), "ref") // id of the parameter declaration (the expression is a subnode of the declaration) END_NODE_XML -NODE_XML(CXXConditionDeclExpr, "CXXConditionDeclExpr") - ATTRIBUTE_FILE_LOCATION_XML - TYPE_ATTRIBUTE_XML(getType()) - SUB_NODE_XML(VarDecl) // a CXXConditionDeclExpr owns the declaration -END_NODE_XML - - //===----------------------------------------------------------------------===// #undef NODE_XML -#undef ID_ATTRIBUTE_XML +#undef ID_ATTRIBUTE_XML #undef TYPE_ATTRIBUTE_XML #undef ATTRIBUTE_XML #undef ATTRIBUTE_SPECIAL_XML @@ -513,8 +506,8 @@ END_NODE_XML #undef ATTRIBUTE_ENUM_OPT_XML #undef ATTRIBUTE_FILE_LOCATION_XML #undef ENUM_XML -#undef END_ENUM_XML -#undef END_NODE_XML +#undef END_ENUM_XML +#undef END_NODE_XML #undef SUB_NODE_XML #undef SUB_NODE_SEQUENCE_XML #undef SUB_NODE_OPT_XML diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h index 4e907e1..380a1dd 100644 --- a/include/clang/Frontend/TextDiagnosticBuffer.h +++ b/include/clang/Frontend/TextDiagnosticBuffer.h @@ -41,6 +41,10 @@ public: virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info); + + /// FlushDiagnostics - Flush the buffered diagnostics to an given + /// diagnostic engine. + void FlushDiagnostics(Diagnostic &Diags) const; }; } // end namspace clang diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index c2db4d3..52bf194 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -78,7 +78,7 @@ public: /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. - Lexer(FileID FID, Preprocessor &PP); + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, Preprocessor &PP); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text @@ -89,7 +89,8 @@ public: /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. - Lexer(FileID FID, const SourceManager &SM, const LangOptions &Features); + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, + const SourceManager &SM, const LangOptions &Features); /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for /// _Pragma expansion. This has a variety of magic semantics that this method diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 1c0036e..edd34b7 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -329,9 +329,9 @@ public: void EnterMainSourceFile(); /// EnterSourceFile - Add a source file to the top of the include stack and - /// start lexing tokens from it instead of the current buffer. If isMainFile - /// is true, this is the main file for the translation unit. - void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); + /// start lexing tokens from it instead of the current buffer. Return true + /// on failure. + bool EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir); /// 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/Parse/Action.h b/include/clang/Parse/Action.h index 3d3232b..fc56cc6 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -203,11 +203,15 @@ public: /// this occurs when deriving from "std::vector::allocator_type", where T /// is a template parameter. /// + /// \param ObjectType if we're checking whether an identifier is a type + /// within a C++ member access expression, this will be the type of the + /// /// \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, - bool isClassName = false) = 0; + bool isClassName = false, + TypeTy *ObjectType = 0) = 0; /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If @@ -668,6 +672,9 @@ public: return StmtEmpty(); } + virtual void ActOnForEachDeclStmt(DeclGroupPtrTy Decl) { + } + virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) { return OwningStmtResult(*this, Expr->release()); } @@ -698,14 +705,39 @@ public: return StmtEmpty(); } + /// \brief Parsed an "if" statement. + /// + /// \param IfLoc the location of the "if" keyword. + /// + /// \param CondVal if the "if" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "if" condition was parsed as a condition variable, + /// the condition variable itself. + /// + /// \param ThenVal the "then" statement. + /// + /// \param ElseLoc the location of the "else" keyword. + /// + /// \param ElseVal the "else" statement. virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + FullExprArg CondVal, + DeclPtrTy CondVar, + StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { return StmtEmpty(); } - virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) { + /// \brief Parsed the start of a "switch" statement. + /// + /// \param Cond if the "switch" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "switch" condition was parsed as a condition + /// variable, the condition variable itself. + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + DeclPtrTy CondVar) { return StmtEmpty(); } @@ -714,8 +746,18 @@ public: return StmtEmpty(); } + /// \brief Parsed a "while" statement. + /// + /// \param Cond if the "while" condition was parsed as an expression, + /// the expression itself. + /// + /// \param CondVar if the "while" condition was parsed as a condition + /// variable, the condition variable itself. + /// + /// \param Body the body of the "while" loop. virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, StmtArg Body) { + FullExprArg Cond, DeclPtrTy CondVar, + StmtArg Body) { return StmtEmpty(); } virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, @@ -725,13 +767,36 @@ public: SourceLocation CondRParen) { return StmtEmpty(); } + + /// \brief Parsed a "for" statement. + /// + /// \param ForLoc the location of the "for" keyword. + /// + /// \param LParenLoc the location of the left parentheses. + /// + /// \param First the statement used to initialize the for loop. + /// + /// \param Second the condition to be checked during each iteration, if + /// that condition was parsed as an expression. + /// + /// \param SecondArg the condition variable to be checked during each + /// iterator, if that condition was parsed as a variable declaration. + /// + /// \param Third the expression that will be evaluated to "increment" any + /// values prior to the next iteration. + /// + /// \param RParenLoc the location of the right parentheses. + /// + /// \param Body the body of the "body" loop. virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - ExprArg Third, SourceLocation RParenLoc, + StmtArg First, FullExprArg Second, + DeclPtrTy SecondVar, FullExprArg Third, + SourceLocation RParenLoc, StmtArg Body) { return StmtEmpty(); } + virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, SourceLocation LParenLoc, StmtArg First, ExprArg Second, @@ -852,23 +917,12 @@ public: /// \brief The parser is entering a new expression evaluation context. /// /// \param NewContext is the new expression evaluation context. - /// - /// \returns the previous expression evaluation context. - virtual ExpressionEvaluationContext - PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { - return PotentiallyEvaluated; - } + virtual void + PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { } - /// \brief The parser is existing an expression evaluation context. - /// - /// \param OldContext the expression evaluation context that the parser is - /// leaving. - /// - /// \param NewContext the expression evaluation context that the parser is - /// returning to. + /// \brief The parser is exiting an expression evaluation context. virtual void - PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext) { } + PopExpressionEvaluationContext() { } // Primary Expressions. @@ -927,9 +981,10 @@ public: return move(Val); // Default impl returns operand. } - virtual OwningExprResult ActOnParenListExpr(SourceLocation L, + virtual OwningExprResult ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val) { + MultiExprArg Val, + TypeTy *TypeOfCast=0) { return ExprEmpty(); } @@ -1041,6 +1096,10 @@ public: return ExprEmpty(); } + virtual bool TypeIsVectorType(TypeTy *Ty) { + return false; + } + virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, ExprArg LHS, ExprArg RHS) { @@ -1371,15 +1430,22 @@ public: return ExprEmpty(); } - /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a - /// C++ if/switch/while/for statement. - /// e.g: "if (int x = f()) {...}" - virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, - SourceLocation StartLoc, - Declarator &D, - SourceLocation EqualLoc, - ExprArg AssignExprVal) { - return ExprEmpty(); + /// \brief Parsed a condition declaration in a C++ if, switch, or while + /// statement. + /// + /// This callback will be invoked after parsing the declaration of "x" in + /// + /// \code + /// if (int x = f()) { + /// // ... + /// } + /// \endcode + /// + /// \param S the scope of the if, switch, or while statement. + /// + /// \param D the declarator that that describes the variable being declared. + virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { + return DeclResult(); } /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the @@ -1470,6 +1536,7 @@ public: MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, + bool IsDefinition, bool Deleted = false) { return DeclPtrTy(); } @@ -1678,10 +1745,14 @@ public: /// \param ObjectType if this dependent template name occurs in the /// context of a member access expression, the type of the object being /// accessed. + /// + /// \param EnteringContext whether we are entering the context of this + /// template. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, - TypeTy *ObjectType) { + TypeTy *ObjectType, + bool EnteringContext) { return TemplateTy(); } @@ -2515,7 +2586,8 @@ public: /// does not name an identifier. virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName = false); + bool isClassName = false, + TypeTy *ObjectType = 0); /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. @@ -2578,21 +2650,15 @@ class EnterExpressionEvaluationContext { /// \brief The action object. Action &Actions; - /// \brief The previous expression evaluation context. - Action::ExpressionEvaluationContext PrevContext; - - /// \brief The current expression evaluation context. - Action::ExpressionEvaluationContext CurContext; - public: EnterExpressionEvaluationContext(Action &Actions, Action::ExpressionEvaluationContext NewContext) - : Actions(Actions), CurContext(NewContext) { - PrevContext = Actions.PushExpressionEvaluationContext(NewContext); + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext); } ~EnterExpressionEvaluationContext() { - Actions.PopExpressionEvaluationContext(CurContext, PrevContext); + Actions.PopExpressionEvaluationContext(); } }; diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 81bb300..ecaa6ae 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -33,19 +33,22 @@ namespace clang { class AttributeList { IdentifierInfo *AttrName; SourceLocation AttrLoc; + IdentifierInfo *ScopeName; + SourceLocation ScopeLoc; IdentifierInfo *ParmName; SourceLocation ParmLoc; ActionBase::ExprTy **Args; unsigned NumArgs; AttributeList *Next; - bool DeclspecAttribute; + bool DeclspecAttribute, CXX0XAttribute; AttributeList(const AttributeList &); // DO NOT IMPLEMENT void operator=(const AttributeList &); // DO NOT IMPLEMENT public: AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc, + IdentifierInfo *ScopeName, SourceLocation ScopeLoc, IdentifierInfo *ParmName, SourceLocation ParmLoc, ActionBase::ExprTy **args, unsigned numargs, - AttributeList *Next, bool declspec = false); + AttributeList *Next, bool declspec = false, bool cxx0x = false); ~AttributeList(); enum Kind { // Please keep this list alphabetized. @@ -56,7 +59,9 @@ public: AT_always_inline, AT_analyzer_noreturn, AT_annotate, + AT_base_check, AT_blocks, + AT_carries_dependency, AT_cdecl, AT_cleanup, AT_const, @@ -67,9 +72,11 @@ public: AT_dllimport, AT_ext_vector_type, AT_fastcall, + AT_final, AT_format, AT_format_arg, AT_gnu_inline, + AT_hiding, AT_malloc, AT_mode, AT_nodebug, @@ -80,6 +87,7 @@ public: AT_nothrow, AT_nsobject, AT_objc_exception, + AT_override, AT_cf_returns_retained, // Clang-specific. AT_ns_returns_retained, // Clang-specific. AT_objc_gc, @@ -106,8 +114,15 @@ public: IdentifierInfo *getName() const { return AttrName; } SourceLocation getLoc() const { return AttrLoc; } + + bool hasScope() const { return ScopeName; } + IdentifierInfo *getScopeName() const { return ScopeName; } + SourceLocation getScopeLoc() const { return ScopeLoc; } + IdentifierInfo *getParameterName() const { return ParmName; } + bool isDeclspecAttribute() const { return DeclspecAttribute; } + bool isCXX0XAttribute() const { return CXX0XAttribute; } Kind getKind() const { return getKind(getName()); } static Kind getKind(const IdentifierInfo *Name); @@ -181,6 +196,22 @@ inline AttributeList* addAttributeLists (AttributeList *Left, return Left; } +/// CXX0XAttributeList - A wrapper around a C++0x attribute list. +/// Stores, in addition to the list proper, whether or not an actual list was +/// (as opposed to an empty list, which may be ill-formed in some places) and +/// the source range of the list. +struct CXX0XAttributeList { + AttributeList *AttrList; + SourceRange Range; + bool HasAttr; + CXX0XAttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) + : AttrList(attrList), Range(range), HasAttr (hasAttr) { + } + CXX0XAttributeList () + : AttrList(0), Range(), HasAttr(false) { + } +}; + } // end namespace clang #endif diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 7e7d0b3..fe899b3 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -484,6 +484,8 @@ public: IK_OperatorFunctionId, /// \brief A conversion function name, e.g., operator int. IK_ConversionFunctionId, + /// \brief A user-defined literal name, e.g., operator "" _i. + IK_LiteralOperatorId, /// \brief A constructor name. IK_ConstructorName, /// \brief A destructor name. @@ -495,7 +497,8 @@ public: /// \brief Anonymous union that holds extra data associated with the /// parsed unqualified-id. union { - /// \brief When Kind == IK_Identifier, the parsed identifier. + /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind + /// == IK_UserLiteralId, the identifier suffix. IdentifierInfo *Identifier; /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator @@ -607,6 +610,22 @@ public: EndLocation = EndLoc; ConversionFunctionId = Ty; } + + /// \brief Specific that this unqualified-id was parsed as a + /// literal-operator-id. + /// + /// \param Id the parsed identifier. + /// + /// \param OpLoc the location of the 'operator' keyword. + /// + /// \param IdLoc the location of the identifier. + void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, + SourceLocation IdLoc) { + Kind = IK_LiteralOperatorId; + Identifier = const_cast(Id); + StartLocation = OpLoc; + EndLocation = IdLoc; + } /// \brief Specify that this unqualified-id was parsed as a constructor name. /// diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f7cccca..81a80eb 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -24,6 +24,7 @@ namespace clang { class AttributeList; + struct CXX0XAttributeList; class PragmaHandler; class Scope; class DiagnosticBuilder; @@ -753,10 +754,10 @@ private: //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. - DeclGroupPtrTy ParseExternalDeclaration(); + DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr); bool isDeclarationAfterDeclarator(); bool isStartOfFunctionDefinition(); - DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr, AccessSpecifier AS = AS_none); DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, @@ -832,10 +833,10 @@ private: OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - bool parseParenAsExprList); + TypeTy *TypeOfCast); OwningExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, - bool parseParenAsExprList = false); + TypeTy *TypeOfCast = 0); OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS); OwningExprResult ParseSizeofAlignofExpression(); OwningExprResult ParseBuiltinPrimaryExpression(); @@ -865,7 +866,7 @@ private: }; OwningExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool parseAsExprList, + TypeTy *TypeOfCast, TypeTy *&CastTy, SourceLocation &RParenLoc); @@ -933,8 +934,8 @@ private: SourceLocation Start); //===--------------------------------------------------------------------===// - // C++ if/switch/while/for condition expression. - OwningExprResult ParseCXXCondition(); + // C++ if/switch/while condition expression. + bool ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult); //===--------------------------------------------------------------------===// // C++ types @@ -994,24 +995,23 @@ private: return ParseStatementOrDeclaration(true); } OwningStmtResult ParseStatementOrDeclaration(bool OnlyStatement = false); - OwningStmtResult ParseLabeledStatement(); - OwningStmtResult ParseCaseStatement(); - OwningStmtResult ParseDefaultStatement(); - OwningStmtResult ParseCompoundStatement(bool isStmtExpr = false); + OwningStmtResult ParseLabeledStatement(AttributeList *Attr); + OwningStmtResult ParseCaseStatement(AttributeList *Attr); + OwningStmtResult ParseDefaultStatement(AttributeList *Attr); + OwningStmtResult ParseCompoundStatement(AttributeList *Attr, + bool isStmtExpr = false); OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false); - bool ParseParenExprOrCondition(OwningExprResult &CondExp, - bool OnlyAllowCondition = false, - SourceLocation *LParenLoc = 0, - SourceLocation *RParenLoc = 0); - OwningStmtResult ParseIfStatement(); - OwningStmtResult ParseSwitchStatement(); - OwningStmtResult ParseWhileStatement(); - OwningStmtResult ParseDoStatement(); - OwningStmtResult ParseForStatement(); - OwningStmtResult ParseGotoStatement(); - OwningStmtResult ParseContinueStatement(); - OwningStmtResult ParseBreakStatement(); - OwningStmtResult ParseReturnStatement(); + bool ParseParenExprOrCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult); + OwningStmtResult ParseIfStatement(AttributeList *Attr); + OwningStmtResult ParseSwitchStatement(AttributeList *Attr); + OwningStmtResult ParseWhileStatement(AttributeList *Attr); + OwningStmtResult ParseDoStatement(AttributeList *Attr); + OwningStmtResult ParseForStatement(AttributeList *Attr); + OwningStmtResult ParseGotoStatement(AttributeList *Attr); + OwningStmtResult ParseContinueStatement(AttributeList *Attr); + OwningStmtResult ParseBreakStatement(AttributeList *Attr); + OwningStmtResult ParseReturnStatement(AttributeList *Attr); OwningStmtResult ParseAsmStatement(bool &msAsm); OwningStmtResult FuzzyParseMicrosoftAsmStatement(); bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, @@ -1021,7 +1021,7 @@ private: //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks - OwningStmtResult ParseCXXTryBlock(); + OwningStmtResult ParseCXXTryBlock(AttributeList *Attr); OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); OwningStmtResult ParseCXXCatchBlock(); @@ -1045,9 +1045,11 @@ private: DSC_class // class context, enables 'friend' }; - DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd, + CXX0XAttributeList Attr); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd = 0); @@ -1217,11 +1219,14 @@ private: void ParseBlockId(); // EndLoc, if non-NULL, is filled with the location of the last token of // the attribute list. - AttributeList *ParseAttributes(SourceLocation *EndLoc = 0); + CXX0XAttributeList ParseCXX0XAttributes(SourceLocation *EndLoc = 0); + AttributeList *ParseGNUAttributes(SourceLocation *EndLoc = 0); AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0); AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0); void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); + + OwningExprResult ParseCXX0XAlignArgument(SourceLocation Start); /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is @@ -1265,7 +1270,8 @@ private: typedef void (Parser::*DirectDeclParseFunction)(Declarator&); void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); - void ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed = true); + void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, + bool CXX0XAttributesAllowed = true); void ParseDirectDeclarator(Declarator &D); void ParseParenDeclarator(Declarator &D); void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, @@ -1278,12 +1284,17 @@ private: //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] + bool isCXX0XAttributeSpecifier(bool FullLookahead = false, + tok::TokenKind *After = 0); + DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); DeclPtrTy ParseLinkage(unsigned Context); DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + CXX0XAttributeList Attrs); DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); @@ -1353,6 +1364,7 @@ private: SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, TemplateParameterList &TemplateParams); + bool isStartOfTemplateTypeParameter(); DeclPtrTy ParseTemplateParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTypeParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index ed74761..84c179f 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -209,7 +209,8 @@ public: void Serialize(llvm::raw_ostream &OS) const; /// \brief Deserialize a code-completion string from the given string. - static CodeCompletionString *Deserialize(llvm::StringRef &Str); + static CodeCompletionString *Deserialize(const char *&Str, + const char *StrEnd); }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, @@ -221,6 +222,10 @@ class CodeCompleteConsumer { protected: /// \brief Whether to include macros in the code-completion results. bool IncludeMacros; + + /// \brief Whether the output format for the code-completion consumer is + /// binary. + bool OutputIsBinary; public: /// \brief Captures a result of code completion. @@ -394,17 +399,20 @@ public: Sema &S) const; }; - CodeCompleteConsumer() : IncludeMacros(false) { } + CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { } - explicit CodeCompleteConsumer(bool IncludeMacros) - : IncludeMacros(IncludeMacros) { } + CodeCompleteConsumer(bool IncludeMacros, bool OutputIsBinary) + : IncludeMacros(IncludeMacros), OutputIsBinary(OutputIsBinary) { } /// \brief Whether the code-completion consumer wants to see macros. bool includeMacros() const { return IncludeMacros; } + + /// \brief Determine whether the output of this consumer is binary. + bool isOutputBinary() const { return OutputIsBinary; } /// \brief Deregisters and destroys this code-completion consumer. virtual ~CodeCompleteConsumer(); - + /// \name Code-completion callbacks //@{ /// \brief Process the finalized code-completion results. @@ -436,7 +444,7 @@ public: /// results to the given raw output stream. PrintingCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros, false), OS(OS) { } /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, @@ -458,7 +466,7 @@ public: /// results to the given raw output stream in a format readable to the CIndex /// library. CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS) - : CodeCompleteConsumer(IncludeMacros), OS(OS) { } + : CodeCompleteConsumer(IncludeMacros, true), OS(OS) { } /// \brief Prints the finalized code-completion results. virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index dc13e7f..6c9ecf0 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -48,6 +48,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { ObjCIdRedefinitionType = QualType(); ObjCClassRedefinitionType = QualType(); + ObjCSelRedefinitionType = QualType(); if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); InitBuiltinTypes(); @@ -220,10 +221,12 @@ void ASTContext::InitBuiltinTypes() { // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). ObjCIdTypedefType = QualType(); ObjCClassTypedefType = QualType(); + ObjCSelTypedefType = QualType(); - // Builtin types for 'id' and 'Class'. + // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); + InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); ObjCConstantStringType = QualType(); @@ -517,18 +520,23 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { /// getDeclAlignInBytes - Return a conservative estimate of the alignment of the /// specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. -unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { +/// If @p RefAsPointee, references are treated like their underlying type +/// (for alignof), else they're treated like pointers (for CodeGen). +unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { unsigned Align = Target.getCharWidth(); if (const AlignedAttr* AA = D->getAttr()) - Align = std::max(Align, AA->getAlignment()); + Align = std::max(Align, AA->getMaxAlignment()); if (const ValueDecl *VD = dyn_cast(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - Align = Target.getPointerAlign(AS); - } else if (!T->isIncompleteType() && !T->isFunctionType()) { + if (RefAsPointee) + T = RT->getPointeeType(); + else + T = getPointerType(RT->getPointeeType()); + } + if (!T->isIncompleteType() && !T->isFunctionType()) { // Incomplete or function types default to 1. while (isa(T) || isa(T)) T = cast(T)->getElementType(); @@ -687,19 +695,21 @@ ASTContext::getTypeInfo(const Type *T) { Align = Target.getPointerAlign(AS); break; } + case Type::LValueReference: + case Type::RValueReference: { + // alignof and sizeof should never enter this code path here, so we go + // the pointer route. + unsigned AS = cast(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } case Type::Pointer: { unsigned AS = cast(T)->getPointeeType().getAddressSpace(); Width = Target.getPointerWidth(AS); Align = Target.getPointerAlign(AS); break; } - case Type::LValueReference: - case Type::RValueReference: - // "When applied to a reference or a reference type, the result is the size - // of the referenced type." C++98 5.3.3p2: expr.sizeof. - // FIXME: This is wrong for struct layout: a reference in a struct has - // pointer size. - return getTypeInfo(cast(T)->getPointeeType()); case Type::MemberPointer: { // FIXME: This is ABI dependent. We use the Itanium C++ ABI. // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers @@ -761,7 +771,8 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Typedef: { const TypedefDecl *Typedef = cast(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr()) { - Align = Aligned->getAlignment(); + Align = std::max(Aligned->getMaxAlignment(), + getTypeAlign(Typedef->getUnderlyingType().getTypePtr())); Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr()); } else return getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); @@ -1460,16 +1471,24 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals, SourceRange Brackets) { - assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && + assert((!NumElts || NumElts->isTypeDependent() || + NumElts->isValueDependent()) && "Size must be type- or value-dependent!"); - llvm::FoldingSetNodeID ID; - DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, - EltTypeQuals, NumElts); - void *InsertPos = 0; - DependentSizedArrayType *Canon - = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentSizedArrayType *Canon = 0; + + if (NumElts) { + // Dependently-sized array types that do not have a specified + // number of elements will have their sizes deduced from an + // initializer. + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, + EltTypeQuals, NumElts); + + Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + } + DependentSizedArrayType *New; if (Canon) { // We already have a canonical version of this array type; use it as @@ -1483,7 +1502,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, New = new (*this, TypeAlignment) DependentSizedArrayType(*this, EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); - DependentSizedArrayTypes.InsertNode(New, InsertPos); + + if (NumElts) + DependentSizedArrayTypes.InsertNode(New, InsertPos); } else { QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, ASM, EltTypeQuals, @@ -1818,9 +1839,10 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, - const TemplateArgumentLoc *Args, - unsigned NumArgs, + const TemplateArgumentListInfo &Args, QualType Canon) { + unsigned NumArgs = Args.size(); + llvm::SmallVector ArgVec; ArgVec.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2320,6 +2342,22 @@ CanQualType ASTContext::getCanonicalType(QualType T) { VAT->getBracketsRange())); } +DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { + if (TemplateDecl *TD = Name.getAsTemplateDecl()) + return TD->getDeclName(); + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + if (DTN->isIdentifier()) { + return DeclarationNames.getIdentifier(DTN->getIdentifier()); + } else { + return DeclarationNames.getCXXOperatorName(DTN->getOperator()); + } + } + + assert(Name.getAsOverloadedFunctionDecl()); + return Name.getAsOverloadedFunctionDecl()->getDeclName(); +} + TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { // If this template name refers to a template, the canonical // template name merely stores the template itself. @@ -3374,9 +3412,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, false); return; } - + if (const PointerType *PT = T->getAs()) { + if (PT->isObjCSelType()) { + S += ':'; + return; + } QualType PointeeTy = PT->getPointeeType(); + bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -3407,10 +3450,6 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S.replace(S.end()-2, S.end(), replace); } } - if (isObjCSelType(PointeeTy)) { - S += ':'; - return; - } if (PointeeTy->isCharType()) { // char pointer types should be encoded as '*' unless it is a @@ -3633,21 +3672,7 @@ void ASTContext::setObjCIdType(QualType T) { } void ASTContext::setObjCSelType(QualType T) { - ObjCSelType = T; - - const TypedefType *TT = T->getAs(); - if (!TT) - return; - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAs(); - if (!ptr) - return; - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - if (!rec) - return; - SelStructType = rec; + ObjCSelTypedefType = T; } void ASTContext::setObjCProtoType(QualType QT) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bdc8047..572d76f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -211,6 +211,203 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, // NamedDecl Implementation //===----------------------------------------------------------------------===// +static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { + assert(D->getDeclContext()->getLookupContext()->isFileContext() && + "Not a name having namespace scope"); + ASTContext &Context = D->getASTContext(); + + // C++ [basic.link]p3: + // A name having namespace scope (3.3.6) has internal linkage if it + // is the name of + // - an object, reference, function or function template that is + // explicitly declared static; or, + // (This bullet corresponds to C99 6.2.2p3.) + if (const VarDecl *Var = dyn_cast(D)) { + // Explicitly declared static. + if (Var->getStorageClass() == VarDecl::Static) + return NamedDecl::InternalLinkage; + + // - an object or reference that is explicitly declared const + // and neither explicitly declared extern nor previously + // declared to have external linkage; or + // (there is no equivalent in C99) + if (Context.getLangOptions().CPlusPlus && + Var->getType().isConstant(Context) && + Var->getStorageClass() != VarDecl::Extern && + Var->getStorageClass() != VarDecl::PrivateExtern) { + bool FoundExtern = false; + for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); + PrevVar && !FoundExtern; + PrevVar = PrevVar->getPreviousDeclaration()) + if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage) + FoundExtern = true; + + if (!FoundExtern) + return NamedDecl::InternalLinkage; + } + } else if (isa(D) || isa(D)) { + const FunctionDecl *Function = 0; + if (const FunctionTemplateDecl *FunTmpl + = dyn_cast(D)) + Function = FunTmpl->getTemplatedDecl(); + else + Function = cast(D); + + // Explicitly declared static. + if (Function->getStorageClass() == FunctionDecl::Static) + return NamedDecl::InternalLinkage; + } else if (const FieldDecl *Field = dyn_cast(D)) { + // - a data member of an anonymous union. + if (cast(Field->getDeclContext())->isAnonymousStructOrUnion()) + return NamedDecl::InternalLinkage; + } + + // C++ [basic.link]p4: + + // A name having namespace scope has external linkage if it is the + // name of + // + // - an object or reference, unless it has internal linkage; or + if (const VarDecl *Var = dyn_cast(D)) { + if (!Context.getLangOptions().CPlusPlus && + (Var->getStorageClass() == VarDecl::Extern || + Var->getStorageClass() == VarDecl::PrivateExtern)) { + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { + if (NamedDecl::Linkage L = PrevVar->getLinkage()) + return L; + } + } + + // C99 6.2.2p5: + // If the declaration of an identifier for an object has file + // scope and no storage-class specifier, its linkage is + // external. + return NamedDecl::ExternalLinkage; + } + + // - a function, unless it has internal linkage; or + if (const FunctionDecl *Function = dyn_cast(D)) { + // C99 6.2.2p5: + // If the declaration of an identifier for a function has no + // storage-class specifier, its linkage is determined exactly + // as if it were declared with the storage-class specifier + // extern. + if (!Context.getLangOptions().CPlusPlus && + (Function->getStorageClass() == FunctionDecl::Extern || + Function->getStorageClass() == FunctionDecl::PrivateExtern || + Function->getStorageClass() == FunctionDecl::None)) { + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { + if (NamedDecl::Linkage L = PrevFunc->getLinkage()) + return L; + } + } + + return NamedDecl::ExternalLinkage; + } + + // - a named class (Clause 9), or an unnamed class defined in a + // typedef declaration in which the class has the typedef name + // for linkage purposes (7.1.3); or + // - a named enumeration (7.2), or an unnamed enumeration + // defined in a typedef declaration in which the enumeration + // has the typedef name for linkage purposes (7.1.3); or + if (const TagDecl *Tag = dyn_cast(D)) + if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) + return NamedDecl::ExternalLinkage; + + // - an enumerator belonging to an enumeration with external linkage; + if (isa(D)) + if (cast(D->getDeclContext())->getLinkage() + == NamedDecl::ExternalLinkage) + return NamedDecl::ExternalLinkage; + + // - a template, unless it is a function template that has + // internal linkage (Clause 14); + if (isa(D)) + return NamedDecl::ExternalLinkage; + + // - a namespace (7.3), unless it is declared within an unnamed + // namespace. + if (isa(D) && !D->isInAnonymousNamespace()) + return NamedDecl::ExternalLinkage; + + return NamedDecl::NoLinkage; +} + +NamedDecl::Linkage NamedDecl::getLinkage() const { + // Handle linkage for namespace-scope names. + if (getDeclContext()->getLookupContext()->isFileContext()) + if (Linkage L = getLinkageForNamespaceScopeDecl(this)) + return L; + + // C++ [basic.link]p5: + // In addition, a member function, static data member, a named + // class or enumeration of class scope, or an unnamed class or + // enumeration defined in a class-scope typedef declaration such + // that the class or enumeration has the typedef name for linkage + // purposes (7.1.3), has external linkage if the name of the class + // has external linkage. + if (getDeclContext()->isRecord() && + (isa(this) || isa(this) || + (isa(this) && + (getDeclName() || cast(this)->getTypedefForAnonDecl()))) && + cast(getDeclContext())->getLinkage() == ExternalLinkage) + return ExternalLinkage; + + // C++ [basic.link]p6: + // The name of a function declared in block scope and the name of + // an object declared by a block scope extern declaration have + // linkage. If there is a visible declaration of an entity with + // linkage having the same name and type, ignoring entities + // declared outside the innermost enclosing namespace scope, the + // block scope declaration declares that same entity and receives + // the linkage of the previous declaration. If there is more than + // one such matching entity, the program is ill-formed. Otherwise, + // if no matching entity is found, the block scope entity receives + // external linkage. + if (getLexicalDeclContext()->isFunctionOrMethod()) { + if (const FunctionDecl *Function = dyn_cast(this)) { + if (Function->getPreviousDeclaration()) + if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) + return L; + + return ExternalLinkage; + } + + if (const VarDecl *Var = dyn_cast(this)) + if (Var->getStorageClass() == VarDecl::Extern || + Var->getStorageClass() == VarDecl::PrivateExtern) { + if (Var->getPreviousDeclaration()) + if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) + return L; + + return ExternalLinkage; + } + } + + // C++ [basic.link]p6: + // Names not covered by these rules have no linkage. + return NoLinkage; +} + std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getLangOptions()); } @@ -300,13 +497,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - if (const VarDecl *VD = dyn_cast(this)) - return VD->hasExternalStorage() || VD->isFileVarDecl(); - - if (isa(this) && !isa(this)) - return true; - - return false; + return getLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDecl() { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 831f552..2dcd80b 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -55,8 +55,7 @@ const char *DeclContext::getDeclKindName() const { } bool Decl::CollectingStats(bool Enable) { - if (Enable) - StatSwitch = true; + if (Enable) StatSwitch = true; return StatSwitch; } @@ -119,7 +118,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { OS << Message; - if (NamedDecl *DN = dyn_cast_or_null(TheDecl)) + if (const NamedDecl *DN = dyn_cast_or_null(TheDecl)) OS << " '" << DN->getQualifiedNameAsString() << '\''; OS << '\n'; } @@ -130,9 +129,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { // Out-of-line virtual method providing a home for Decl. Decl::~Decl() { - if (isOutOfSemaDC()) - delete getMultipleDC(); - assert(!HasAttrs && "attributes should have been freed by Destroy"); } @@ -148,7 +144,7 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { return; if (isInSemaDC()) { - MultipleDC *MDC = new MultipleDC(); + MultipleDC *MDC = new (getASTContext()) MultipleDC(); MDC->SemanticDC = getDeclContext(); MDC->LexicalDC = DC; DeclCtx = MDC; @@ -343,9 +339,12 @@ void Decl::Destroy(ASTContext &C) { N = Tmp; } + if (isOutOfSemaDC()) + delete (C) getMultipleDC(); + this->~Decl(); C.Deallocate((void *)this); -#endif +#endif } Decl *Decl::castFromDeclContext (const DeclContext *D) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a21c93f..4001988 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -36,8 +36,6 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), - Conversions(DC, DeclarationName()), - VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -299,14 +297,11 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, void CXXRecordDecl::collectConversionFunctions( - llvm::SmallPtrSet& ConversionsTypeSet) + llvm::SmallPtrSet& ConversionsTypeSet) const { - OverloadedFunctionDecl *TopConversions = getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - TFunc = TopConversions->function_begin(), - TFuncEnd = TopConversions->function_end(); - TFunc != TFuncEnd; ++TFunc) { - NamedDecl *TopConv = TFunc->get(); + const UnresolvedSet *Cs = getConversionFunctions(); + for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + NamedDecl *TopConv = *I; CanQualType TConvType; if (FunctionTemplateDecl *TConversionTemplate = dyn_cast(TopConv)) @@ -336,14 +331,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs()) { - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Cs = cast(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - NamedDecl *Conv = Func->get(); + for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. CanQualType ConvType; @@ -405,8 +397,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -OverloadedFunctionDecl * -CXXRecordDecl::getVisibleConversionFunctions() { +const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) return &Conversions; @@ -425,26 +416,26 @@ void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - VisibleConversions.addOverload(ConvDecl); + VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - VisibleConversions.addOverload(ConvDecl); + VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - Conversions.addOverload(ConvDecl); + Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - Conversions.addOverload(ConvDecl); + Conversions.addDecl(ConvDecl); } CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { @@ -895,12 +886,21 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, - NamespaceDecl *Used, + NamedDecl *Used, DeclContext *CommonAncestor) { + if (NamespaceDecl *NS = dyn_cast_or_null(Used)) + Used = NS->getOriginalNamespace(); return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, Qualifier, IdentLoc, Used, CommonAncestor); } +NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { + if (NamespaceAliasDecl *NA = + dyn_cast_or_null(NominatedNamespace)) + return NA->getNamespace(); + return cast_or_null(NominatedNamespace); +} + NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation AliasLoc, @@ -909,6 +909,8 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, NestedNameSpecifier *Qualifier, SourceLocation IdentLoc, NamedDecl *Namespace) { + if (NamespaceDecl *NS = dyn_cast_or_null(Namespace)) + Namespace = NS->getOriginalNamespace(); return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, Qualifier, IdentLoc, Namespace); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 131de8b..a5982cf 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -18,19 +18,18 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor { + class DeclPrinter : public DeclVisitor { llvm::raw_ostream &Out; ASTContext &Context; PrintingPolicy Policy; unsigned Indentation; - llvm::raw_ostream& Indent(); + llvm::raw_ostream& Indent() { return Indent(Indentation); } + llvm::raw_ostream& Indent(unsigned Indentation); void ProcessDeclGroup(llvm::SmallVectorImpl& Decls); void Print(AccessSpecifier AS); @@ -154,8 +153,8 @@ void Decl::dump() const { print(llvm::errs()); } -llvm::raw_ostream& DeclPrinter::Indent() { - for (unsigned i = 0; i < Indentation; ++i) +llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) { + for (unsigned i = 0; i != Indentation; ++i) Out << " "; return Out; } @@ -205,6 +204,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { AccessSpecifier AS = D->getAccess(); if (AS != CurAS) { + if (Indent) + this->Indent(Indentation - Policy.Indentation); Print(AS); Out << ":\n"; CurAS = AS; @@ -502,7 +503,7 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespace()->getNameAsString(); + Out << D->getNominatedNamespaceAsWritten()->getNameAsString(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 0c14714..902339e 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -214,9 +214,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), - NTTP->getLocation(), - NTTP->getType()->isDependentType(), - /*Value-dependent=*/true); + NTTP->getLocation()); TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast(*Param); @@ -453,8 +451,9 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, - TemplateArgumentLoc *ArgInfos, unsigned N, + const TemplateArgumentListInfo &ArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl) { + unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; for (unsigned I = 0; I != N; ++I) ClonedArgs[I] = ArgInfos[I]; diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 1ff068c..3471657 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -50,6 +50,17 @@ public: void *FETokenInfo; }; +/// CXXLiberalOperatorName - Contains the actual identifier that makes up the +/// name. +/// +/// This identifier is stored here rather than directly in DeclarationName so as +/// to allow Objective-C selectors, which are about a million times more common, +/// to consume minimal memory. +class CXXLiteralOperatorIdName : public DeclarationNameExtra { +public: + IdentifierInfo *ID; +}; + bool operator<(DeclarationName LHS, DeclarationName RHS) { if (LHS.getNameKind() != RHS.getNameKind()) return LHS.getNameKind() < RHS.getNameKind(); @@ -89,6 +100,10 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { case DeclarationName::CXXOperatorName: return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator(); + + case DeclarationName::CXXLiteralOperatorName: + return LHS.getCXXLiteralIdentifier()->getName() < + RHS.getCXXLiteralIdentifier()->getName(); case DeclarationName::CXXUsingDirective: return false; @@ -143,6 +158,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; + case DeclarationNameExtra::CXXLiteralOperator: + return CXXLiteralOperatorName; + case DeclarationNameExtra::CXXUsingDirective: return CXXUsingDirective; @@ -208,6 +226,10 @@ std::string DeclarationName::getAsString() const { return Result; } + case CXXLiteralOperatorName: { + return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName()); + } + case CXXConversionFunctionName: { std::string Result = "operator "; QualType Type = getCXXNameType(); @@ -242,6 +264,13 @@ OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { } } +IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const { + if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName()) + return CXXLit->ID; + else + return 0; +} + Selector DeclarationName::getObjCSelector() const { switch (getNameKind()) { case ObjCZeroArgSelector: @@ -273,6 +302,9 @@ void *DeclarationName::getFETokenInfoAsVoid() const { case CXXOperatorName: return getAsCXXOperatorIdName()->FETokenInfo; + case CXXLiteralOperatorName: + return getCXXLiteralIdentifier()->getFETokenInfo(); + default: assert(false && "Declaration name has no FETokenInfo"); } @@ -295,6 +327,10 @@ void DeclarationName::setFETokenInfo(void *T) { getAsCXXOperatorIdName()->FETokenInfo = T; break; + case CXXLiteralOperatorName: + getCXXLiteralIdentifier()->setFETokenInfo(T); + break; + default: assert(false && "Declaration name has no FETokenInfo"); } @@ -390,6 +426,14 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { return DeclarationName(&CXXOperatorNames[(unsigned)Op]); } +DeclarationName +DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { + CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName; + LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; + LiteralName->ID = II; + return DeclarationName(LiteralName); +} + unsigned llvm::DenseMapInfo:: getHashValue(clang::DeclarationName N) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 90b50c6..624a620 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -31,49 +31,104 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// +void ExplicitTemplateArgumentList::initializeFrom( + const TemplateArgumentListInfo &Info) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); +} + +void ExplicitTemplateArgumentList::copyInto( + TemplateArgumentListInfo &Info) const { + Info.setLAngleLoc(LAngleLoc); + Info.setRAngleLoc(RAngleLoc); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + Info.addArgument(getTemplateArgs()[I]); +} + +std::size_t ExplicitTemplateArgumentList::sizeFor( + const TemplateArgumentListInfo &Info) { + return sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgumentLoc) * Info.size(); +} + +void DeclRefExpr::computeDependence() { + TypeDependent = false; + ValueDependent = false; + + NamedDecl *D = getDecl(); + + // (TD) C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // + // and + // + // (VD) C++ [temp.dep.constexpr]p2: + // An identifier is value-dependent if it is: + + // (TD) - an identifier that was declared with dependent type + // (VD) - a name declared with a dependent type, + if (getType()->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + } + // (TD) - a conversion-function-id that specifies a dependent type + else if (D->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + D->getDeclName().getCXXNameType()->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + } + // (TD) - a template-id that is dependent, + else if (hasExplicitTemplateArgumentList() && + TemplateSpecializationType::anyDependentTemplateArguments( + getTemplateArgs(), + getNumTemplateArgs())) { + TypeDependent = true; + ValueDependent = true; + } + // (VD) - the name of a non-type template parameter, + else if (isa(D)) + ValueDependent = true; + // (VD) - a constant with integral or enumeration type and is + // initialized with an expression that is value-dependent. + else if (VarDecl *Var = dyn_cast(D)) { + if (Var->getType()->isIntegralType() && + Var->getType().getCVRQualifiers() == Qualifiers::Const && + Var->getInit() && + Var->getInit()->isValueDependent()) + ValueDependent = true; + } + // (TD) - a nested-name-specifier or a qualified-id that names a + // member of an unknown specialization. + // (handled by DependentScopeDeclRefExpr) +} + DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD) - : Expr(DeclRefExprClass, T, TD, VD), + const TemplateArgumentListInfo *TemplateArgs, + QualType T) + : Expr(DeclRefExprClass, T, false, false), DecoratedD(D, (Qualifier? HasQualifierFlag : 0) | - (HasExplicitTemplateArgumentList? - HasExplicitTemplateArgumentListFlag : 0)), + (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), Loc(NameLoc) { + assert(!isa(D)); if (Qualifier) { NameQualifier *NQ = getNameQualifier(); NQ->NNS = Qualifier; NQ->Range = QualifierRange; } - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = LAngleLoc; - ETemplateArgs->RAngleLoc = RAngleLoc; - ETemplateArgs->NumTemplateArgs = NumExplicitTemplateArgs; - - TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < NumExplicitTemplateArgs; ++I) - new (TemplateArgs + I) TemplateArgumentLoc(ExplicitTemplateArgs[I]); - } -} + if (TemplateArgs) + getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - NamedDecl *D, - SourceLocation NameLoc, - QualType T, bool TD, bool VD) { - return Create(Context, Qualifier, QualifierRange, D, NameLoc, - false, SourceLocation(), 0, 0, SourceLocation(), - T, TD, VD); + computeDependence(); } DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, @@ -81,28 +136,18 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, SourceRange QualifierRange, NamedDecl *D, SourceLocation NameLoc, - bool HasExplicitTemplateArgumentList, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - QualType T, bool TD, bool VD) { + QualType T, + const TemplateArgumentListInfo *TemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (Qualifier != 0) Size += sizeof(NameQualifier); - if (HasExplicitTemplateArgumentList) - Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs; + if (TemplateArgs) + Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignof()); return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc, - HasExplicitTemplateArgumentList, - LAngleLoc, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - RAngleLoc, - T, TD, VD); + TemplateArgs, T); } SourceRange DeclRefExpr::getSourceRange() const { @@ -427,15 +472,13 @@ QualType CallExpr::getCallReturnType() const { MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, - SourceLocation l, bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, unsigned numtargs, - SourceLocation rangle, QualType ty) + SourceLocation l, const TemplateArgumentListInfo *targs, + QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent() || (qual && qual->isDependent()), base->isValueDependent() || (qual && qual->isDependent())), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) { + HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) { // Initialize the qualifier, if any. if (HasQualifier) { NameQualifier *NQ = getMemberQualifier(); @@ -444,17 +487,8 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, } // Initialize the explicit template argument list, if any. - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = langle; - ETemplateArgs->RAngleLoc = rangle; - ETemplateArgs->NumTemplateArgs = numtargs; - - TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < numtargs; ++I) - new (TemplateArgs + I) TemplateArgumentLoc(targs[I]); - } + if (targs) + getExplicitTemplateArgumentList()->initializeFrom(*targs); } MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, @@ -462,24 +496,18 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, - bool has_explicit, - SourceLocation langle, - const TemplateArgumentLoc *targs, - unsigned numtargs, - SourceLocation rangle, + const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); if (qual != 0) Size += sizeof(NameQualifier); - if (has_explicit) - Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * numtargs; + if (targs) + Size += ExplicitTemplateArgumentList::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignof()); return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, - has_explicit, langle, targs, numtargs, rangle, - ty); + targs, ty); } const char *CastExpr::getCastKindName() const { @@ -528,6 +556,8 @@ const char *CastExpr::getCastKindName() const { return "FloatingToIntegral"; case CastExpr::CK_FloatingCast: return "FloatingCast"; + case CastExpr::CK_MemberPointerToBoolean: + return "MemberPointerToBoolean"; } assert(0 && "Unhandled cast kind!"); @@ -640,12 +670,17 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) - : Expr(InitListExprClass, QualType(), - hasAnyTypeDependentArguments(initExprs, numInits), - hasAnyValueDependentArguments(initExprs, numInits)), + : Expr(InitListExprClass, QualType(), false, false), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), - UnionFieldInit(0), HadArrayRangeDesignator(false) { - + UnionFieldInit(0), HadArrayRangeDesignator(false) +{ + for (unsigned I = 0; I != numInits; ++I) { + if (initExprs[I]->isTypeDependent()) + TypeDependent = true; + if (initExprs[I]->isValueDependent()) + ValueDependent = true; + } + InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); } @@ -1091,10 +1126,10 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case PredefinedExprClass: return LV_Valid; + case UnresolvedLookupExprClass: + return LV_Valid; case CXXDefaultArgExprClass: return cast(this)->getExpr()->isLvalue(Ctx); - case CXXConditionDeclExprClass: - return LV_Valid; case CStyleCastExprClass: case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: @@ -1141,18 +1176,6 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; } - case TemplateIdRefExprClass: { - const TemplateIdRefExpr *TID = cast(this); - TemplateName Template = TID->getTemplateName(); - NamedDecl *ND = Template.getAsTemplateDecl(); - if (!ND) - ND = Template.getAsOverloadedFunctionDecl(); - if (ND && DeclCanBeLvalue(ND, Ctx)) - return LV_Valid; - - break; - } - default: break; } @@ -1491,19 +1514,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXNullPtrLiteralExprClass: case Expr::CXXThisExprClass: case Expr::CXXThrowExprClass: - case Expr::CXXConditionDeclExprClass: // FIXME: is this correct? case Expr::CXXNewExprClass: case Expr::CXXDeleteExprClass: case Expr::CXXPseudoDestructorExprClass: - case Expr::UnresolvedFunctionNameExprClass: - case Expr::UnresolvedDeclRefExprClass: - case Expr::TemplateIdRefExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::CXXExprWithTemporariesClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: - case Expr::CXXUnresolvedMemberExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCMessageExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 0ba4608..d1a0390 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -72,14 +72,6 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() { return child_iterator(); } -// CXXConditionDeclExpr -Stmt::child_iterator CXXConditionDeclExpr::child_begin() { - return getVarDecl(); -} -Stmt::child_iterator CXXConditionDeclExpr::child_end() { - return child_iterator(); -} - // CXXNewExpr CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, @@ -121,11 +113,45 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { return &Base + 1; } -// UnresolvedFunctionNameExpr -Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { +// UnresolvedLookupExpr +UnresolvedLookupExpr * +UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, DeclarationName Name, + SourceLocation NameLoc, bool ADL, + const TemplateArgumentListInfo &Args) +{ + void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + + ExplicitTemplateArgumentList::sizeFor(Args)); + UnresolvedLookupExpr *ULE + = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, + Dependent, Qualifier, QualifierRange, + Name, NameLoc, ADL, + /*Overload*/ true, + /*ExplicitTemplateArgs*/ true); + + reinterpret_cast(ULE+1)->initializeFrom(Args); + + return ULE; +} + +bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin, + NamedDecl * const *End, + const TemplateArgumentListInfo *Args) { + for (NamedDecl * const *I = Begin; I != End; ++I) + if ((*I)->getDeclContext()->isDependentContext()) + return true; + + if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args)) + return true; + + return false; +} + +Stmt::child_iterator UnresolvedLookupExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { +Stmt::child_iterator UnresolvedLookupExpr::child_end() { return child_iterator(); } // UnaryTypeTraitExpr @@ -136,72 +162,37 @@ Stmt::child_iterator UnaryTypeTraitExpr::child_end() { return child_iterator(); } -// UnresolvedDeclRefExpr -StmtIterator UnresolvedDeclRefExpr::child_begin() { - return child_iterator(); +// DependentScopeDeclRefExpr +DependentScopeDeclRefExpr * +DependentScopeDeclRefExpr::Create(ASTContext &C, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *Args) { + std::size_t size = sizeof(DependentScopeDeclRefExpr); + if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args); + void *Mem = C.Allocate(size); + + DependentScopeDeclRefExpr *DRE + = new (Mem) DependentScopeDeclRefExpr(C.DependentTy, + Qualifier, QualifierRange, + Name, NameLoc, + Args != 0); + + if (Args) + reinterpret_cast(DRE+1) + ->initializeFrom(*Args); + + return DRE; } -StmtIterator UnresolvedDeclRefExpr::child_end() { +StmtIterator DependentScopeDeclRefExpr::child_begin() { return child_iterator(); } -TemplateIdRefExpr::TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) - : Expr(TemplateIdRefExprClass, T, - (Template.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, NumTemplateArgs)), - (Template.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, NumTemplateArgs))), - Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), - TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), - RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { - TemplateArgumentLoc *StoredTemplateArgs - = reinterpret_cast (this+1); - for (unsigned I = 0; I != NumTemplateArgs; ++I) - new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); -} - -TemplateIdRefExpr * -TemplateIdRefExpr::Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, SourceLocation RAngleLoc) { - void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + - sizeof(TemplateArgumentLoc) * NumTemplateArgs); - return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template, - TemplateNameLoc, LAngleLoc, TemplateArgs, - NumTemplateArgs, RAngleLoc); -} - -void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { - const TemplateArgumentLoc *TemplateArgs = getTemplateArgs(); - for (unsigned I = 0; I != NumTemplateArgs; ++I) - if (Expr *E = TemplateArgs[I].getArgument().getAsExpr()) - E->Destroy(Context); - this->~TemplateIdRefExpr(); - Context.Deallocate(this); -} - -Stmt::child_iterator TemplateIdRefExpr::child_begin() { - // FIXME: Walk the expressions in the template arguments (?) - return Stmt::child_iterator(); -} - -Stmt::child_iterator TemplateIdRefExpr::child_end() { - // FIXME: Walk the expressions in the template arguments (?) - return Stmt::child_iterator(); +StmtIterator DependentScopeDeclRefExpr::child_end() { + return child_iterator(); } bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { @@ -526,7 +517,7 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { return child_iterator(reinterpret_cast(this + 1) + NumArgs); } -CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -534,33 +525,20 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) - : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + const TemplateArgumentListInfo *TemplateArgs) + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), Base(Base), IsArrow(IsArrow), - HasExplicitTemplateArgumentList(HasExplicitTemplateArgs), + HasExplicitTemplateArgumentList(TemplateArgs), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { - if (HasExplicitTemplateArgumentList) { - ExplicitTemplateArgumentList *ETemplateArgs - = getExplicitTemplateArgumentList(); - ETemplateArgs->LAngleLoc = LAngleLoc; - ETemplateArgs->RAngleLoc = RAngleLoc; - ETemplateArgs->NumTemplateArgs = NumTemplateArgs; - - TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); - for (unsigned I = 0; I < NumTemplateArgs; ++I) - new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); - } + if (TemplateArgs) + getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); } -CXXUnresolvedMemberExpr * -CXXUnresolvedMemberExpr::Create(ASTContext &C, +CXXDependentScopeMemberExpr * +CXXDependentScopeMemberExpr::Create(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -568,37 +546,79 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationName Member, SourceLocation MemberLoc, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { - if (!HasExplicitTemplateArgs) - return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + const TemplateArgumentListInfo *TemplateArgs) { + if (!TemplateArgs) + return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, Member, MemberLoc); - void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + - sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgumentLoc) * NumTemplateArgs, - llvm::alignof()); - return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + std::size_t size = sizeof(CXXDependentScopeMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignof()); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, Member, MemberLoc, - HasExplicitTemplateArgs, - LAngleLoc, - TemplateArgs, - NumTemplateArgs, - RAngleLoc); + TemplateArgs); +} + +Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { + return child_iterator(&Base); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { +Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { + return child_iterator(&Base + 1); +} + +UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName MemberName, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) + : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), + Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + HasExplicitTemplateArgs(TemplateArgs != 0), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + MemberName(MemberName), MemberLoc(MemberLoc) { + if (TemplateArgs) + getExplicitTemplateArgs()->initializeFrom(*TemplateArgs); +} + +UnresolvedMemberExpr * +UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) { + std::size_t size = sizeof(UnresolvedMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignof()); + return new (Mem) UnresolvedMemberExpr( + Dependent ? C.DependentTy : C.OverloadTy, + Dependent, HasUnresolvedUsing, Base, IsArrow, + OperatorLoc, Qualifier, QualifierRange, + Member, MemberLoc, TemplateArgs); +} + +Stmt::child_iterator UnresolvedMemberExpr::child_begin() { return child_iterator(&Base); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { +Stmt::child_iterator UnresolvedMemberExpr::child_end() { return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 2689859..a20e1cc 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -19,7 +19,6 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/Compiler.h" #include using namespace clang; @@ -153,7 +152,7 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, } namespace { -class VISIBILITY_HIDDEN HasSideEffect +class HasSideEffect : public StmtVisitor { EvalInfo &Info; public: @@ -210,7 +209,7 @@ public: // LValue Evaluation //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN LValueExprEvaluator +class LValueExprEvaluator : public StmtVisitor { EvalInfo &Info; public: @@ -353,7 +352,7 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN PointerExprEvaluator +class PointerExprEvaluator : public StmtVisitor { EvalInfo &Info; public: @@ -508,7 +507,7 @@ APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN VectorExprEvaluator + class VectorExprEvaluator : public StmtVisitor { EvalInfo &Info; APValue GetZeroVector(QualType VecType); @@ -702,7 +701,7 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN IntExprEvaluator +class IntExprEvaluator : public StmtVisitor { EvalInfo &Info; APValue &Result; @@ -776,7 +775,20 @@ public: T1.getUnqualifiedType()), E); } - bool VisitDeclRefExpr(const DeclRefExpr *E); + + bool CheckReferencedDecl(const Expr *E, const Decl *D); + bool VisitDeclRefExpr(const DeclRefExpr *E) { + return CheckReferencedDecl(E, E->getDecl()); + } + bool VisitMemberExpr(const MemberExpr *E) { + if (CheckReferencedDecl(E, E->getMemberDecl())) { + // Conservatively assume a MemberExpr will have side-effects + Info.EvalResult.HasSideEffects = true; + return true; + } + return false; + } + bool VisitCallExpr(const CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); @@ -834,12 +846,12 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { return true; } -bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { +bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. - if (const EnumConstantDecl *D = dyn_cast(E->getDecl())) { + if (const EnumConstantDecl *ECD = dyn_cast(D)) { // FIXME: This is an ugly hack around the fact that enums don't set their // signedness consistently; see PR3173. - APSInt SI = D->getInitVal(); + APSInt SI = ECD->getInitVal(); SI.setIsUnsigned(!E->getType()->isSignedIntegerType()); // FIXME: This is an ugly hack around the fact that enums don't // set their width (!?!) consistently; see PR3173. @@ -851,15 +863,15 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C, they can also be folded, although they are not ICEs. if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() == Qualifiers::Const) { - if (const VarDecl *D = dyn_cast(E->getDecl())) { + if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *Def = 0; - if (const Expr *Init = D->getDefinition(Def)) { - if (APValue *V = D->getEvaluatedValue()) + if (const Expr *Init = VD->getDefinition(Def)) { + if (APValue *V = VD->getEvaluatedValue()) return Success(V->getInt(), E); if (Visit(const_cast(Init))) { // Cache the evaluated value in the variable declaration. - D->setEvaluatedValue(Info.Ctx, Result); + VD->setEvaluatedValue(Info.Ctx, Result); return true; } @@ -1244,6 +1256,13 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { } unsigned IntExprEvaluator::GetAlignOfType(QualType T) { + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = T->getAs()) + T = Ref->getPointeeType(); + // Get information about the alignment. unsigned CharSize = Info.Ctx.Target.getCharWidth(); @@ -1257,10 +1276,11 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast(E)) - return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); + return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast(E)) - return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl()); + return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(), + /*RefAsPointee*/true); return GetAlignOfType(E->getType()); } @@ -1280,6 +1300,12 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { } QualType SrcTy = E->getTypeOfArgument(); + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = SrcTy->getAs()) + SrcTy = Ref->getPointeeType(); // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc // extension. @@ -1460,7 +1486,7 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FloatExprEvaluator +class FloatExprEvaluator : public StmtVisitor { EvalInfo &Info; APFloat &Result; @@ -1652,7 +1678,7 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ComplexExprEvaluator +class ComplexExprEvaluator : public StmtVisitor { EvalInfo &Info; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index b9cfcfe..326a1dc 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -14,7 +14,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" -#include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" #include #include @@ -22,9 +21,9 @@ using namespace clang; ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) - : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0), - DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), - PrimaryBase(0), PrimaryBaseWasVirtual(false) {} + : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0), + MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), + NonVirtualAlignment(8) { } /// LayoutVtable - Lay out the vtable and set PrimaryBase. void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { @@ -34,7 +33,7 @@ void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { } SelectPrimaryBase(RD); - if (PrimaryBase == 0) { + if (!PrimaryBase.getBase()) { int AS = 0; UpdateAlignment(Ctx.Target.getPointerAlign(AS)); Size += Ctx.Target.getPointerWidth(AS); @@ -52,7 +51,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); // Skip the PrimaryBase here, as it is laid down first. - if (Base != PrimaryBase || PrimaryBaseWasVirtual) + if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual()) LayoutBaseNonVirtually(Base, false); } } @@ -74,12 +73,13 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { } void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = + Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo(); // If the record has a primary base class that is virtual, add it to the set // of primary bases. - if (Layout.getPrimaryBaseWasVirtual()) - IndirectPrimaryBases.insert(Layout.getPrimaryBase()); + 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(), @@ -107,7 +107,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, cast(i->getType()->getAs()->getDecl()); if (!i->isVirtual()) { SelectPrimaryVBase(Base, FirstPrimary); - if (PrimaryBase) + if (PrimaryBase.getBase()) return; continue; } @@ -115,7 +115,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, if (FirstPrimary==0) FirstPrimary = Base; if (!IndirectPrimaryBases.count(Base)) { - setPrimaryBase(Base, true); + setPrimaryBase(Base, /*IsVirtual=*/true); return; } } @@ -141,14 +141,17 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // base class, if one exists. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { - if (!i->isVirtual()) { - const CXXRecordDecl *Base = - cast(i->getType()->getAs()->getDecl()); - if (Base->isDynamicClass()) { - // We found it. - setPrimaryBase(Base, false); - return; - } + // Ignore virtual bases. + if (i->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + + if (Base->isDynamicClass()) { + // We found it. + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false); + return; } } @@ -166,8 +169,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // Otherwise if is the first nearly empty virtual base, if one exists, // otherwise there is no primary base class. - if (!PrimaryBase) - setPrimaryBase(FirstPrimary, true); + if (!PrimaryBase.getBase()) + setPrimaryBase(FirstPrimary, /*IsVirtual=*/true); } void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { @@ -232,9 +235,10 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, } if (Base->getNumVBases()) { - const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); - const CXXRecordDecl *PB = L.getPrimaryBase(); - LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary); + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase(); + LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark, + IndirectPrimary); } } } @@ -448,17 +452,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // If this is a C++ class, lay out the vtable and the non-virtual bases. const CXXRecordDecl *RD = dyn_cast(D); if (RD) { LayoutVtable(RD); // PrimaryBase goes first. - if (PrimaryBase) { - if (PrimaryBaseWasVirtual) - IndirectPrimaryBases.insert(PrimaryBase); - LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual); + if (PrimaryBase.getBase()) { + if (PrimaryBase.isVirtual()) + IndirectPrimaryBases.insert(PrimaryBase.getBase()); + LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual()); } LayoutNonVirtualBases(RD); } @@ -470,7 +474,8 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (RD) { llvm::SmallSet mark; - LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases); + LayoutVirtualBases(RD, RD, PrimaryBase.getBase(), + 0, mark, IndirectPrimaryBases); } // Finally, round the size of the total struct up to the alignment of the @@ -498,7 +503,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector Ivars; @@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { LayoutField(*Field); } +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 TypeSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + if (FieldPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + + // 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. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // 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); +} + void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { - bool FieldPacked = Packed; + if (D->isBitField()) { + LayoutBitField(D); + return; + } + + // Reset the unfilled bits. + UnfilledBitsInLastByte = 0; + + bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldOffset = IsUnion ? 0 : DataSize; uint64_t FieldSize; unsigned FieldAlign; - - FieldPacked |= D->hasAttr(); - - if (const Expr *BitWidthExpr = D->getBitWidth()) { - // TODO: Need to check this algorithm on other targets! - // (tested on Linux-X86) - FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); - + + 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()); + } else if (const ReferenceType *RT = D->getType()->getAs()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); - uint64_t TypeSize = FieldInfo.first; - + FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; + } - if (FieldPacked) - FieldAlign = 1; - if (const AlignedAttr *AA = D->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - // 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. - if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - - // Padding members don't affect overall alignment - if (!D->getIdentifier()) - FieldAlign = 1; - } else { - 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()); - } else if (const ReferenceType *RT = D->getType()->getAs()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Ctx.Target.getPointerWidth(AS); - FieldAlign = Ctx.Target.getPointerAlign(AS); - } else { - std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); - FieldSize = FieldInfo.first; - FieldAlign = FieldInfo.second; - } + if (FieldPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); - if (FieldPacked) - FieldAlign = 8; - if (const AlignedAttr *AA = D->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - // The maximum field alignment overrides the aligned attribute. - if (MaxFieldAlignment) - FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); - // 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; - } + // 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; - UpdateEmptyClassOffsets(D, FieldOffset); + // 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); @@ -619,7 +651,7 @@ void ASTRecordLayoutBuilder::FinishLayout() { Size = 8; // Finally, round the size of the record up to the alignment of the // record itself. - Size = (Size + (Alignment-1)) & ~(Alignment-1); + Size = llvm::RoundUpToAlignment(Size, Alignment); } void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { @@ -631,6 +663,31 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } +static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) { + if (!RD->isDynamicClass()) + return 0; + + 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; + + const FunctionDecl *fn; + if (MD->getBody(fn) && !fn->isOutOfLine()) + continue; + + // We found it. + return MD; + } + + return 0; +} + const ASTRecordLayout * ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, const RecordDecl *D) { @@ -654,17 +711,19 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, uint64_t NonVirtualSize = IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + const CXXMethodDecl *KeyFunction = GetKeyFunction(cast(D)); + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), NonVirtualSize, Builder.NonVirtualAlignment, Builder.PrimaryBase, - Builder.PrimaryBaseWasVirtual, Builder.Bases.data(), Builder.Bases.size(), Builder.VBases.data(), - Builder.VBases.size()); + Builder.VBases.size(), + KeyFunction); } const ASTRecordLayout * diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 0770723..69e0498 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H #define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H +#include "clang/AST/RecordLayout.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/System/DataTypes.h" @@ -27,12 +28,21 @@ namespace clang { class ASTRecordLayoutBuilder { ASTContext &Ctx; + /// Size - The current size of the record layout. uint64_t Size; + + /// Alignment - The current alignment of the record layout. unsigned Alignment; + llvm::SmallVector FieldOffsets; /// Packed - Whether the record is packed or not. bool Packed; + + /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, + /// this contains the number of bits in the last byte that can be used for + /// an adjacent bitfield if necessary. + unsigned char UnfilledBitsInLastByte; /// MaxFieldAlignment - The maximum allowed field alignment. This is set by /// #pragma pack. @@ -45,8 +55,8 @@ class ASTRecordLayoutBuilder { uint64_t NonVirtualSize; unsigned NonVirtualAlignment; - const CXXRecordDecl *PrimaryBase; - bool PrimaryBaseWasVirtual; + + ASTRecordLayout::PrimaryBaseInfo PrimaryBase; typedef llvm::SmallVector, 4> BaseOffsetsTy; @@ -74,6 +84,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutBitField(const FieldDecl *D); void SelectPrimaryBase(const CXXRecordDecl *RD); void SelectPrimaryVBase(const CXXRecordDecl *RD, @@ -84,9 +95,8 @@ class ASTRecordLayoutBuilder { /// base class. void IdentifyPrimaryBases(const CXXRecordDecl *RD); - void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) { - PrimaryBase = PB; - PrimaryBaseWasVirtual = Virtual; + void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) { + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual); } bool IsNearlyEmpty(const CXXRecordDecl *RD) const; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6e0da47..fad80ec 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -88,8 +88,8 @@ void Stmt::addStmtClass(StmtClass s) { static bool StatSwitch = false; -bool Stmt::CollectingStats(bool enable) { - if (enable) StatSwitch = true; +bool Stmt::CollectingStats(bool Enable) { + if (Enable) StatSwitch = true; return StatSwitch; } @@ -559,7 +559,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() { return &HandlerBlock + 1; } -QualType CXXCatchStmt::getCaughtType() { +QualType CXXCatchStmt::getCaughtType() const { if (ExceptionDecl) return ExceptionDecl->getType(); return QualType(); diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 93bf875..bbe6a71 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" #include using namespace clang; @@ -26,7 +25,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor { + class StmtDumper : public StmtVisitor { SourceManager *SM; FILE *F; unsigned IndentLevel; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 4bd7f96..205ea0d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -16,7 +16,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" using namespace clang; @@ -25,7 +24,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor { + class StmtPrinter : public StmtVisitor { llvm::raw_ostream &OS; ASTContext &Context; unsigned IndentLevel; @@ -483,19 +482,26 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { Policy); } -void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { +void StmtPrinter::VisitDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *Node) { Node->getQualifier()->print(OS, Policy); OS << Node->getDeclName().getAsString(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } -void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { +void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { if (Node->getQualifier()) Node->getQualifier()->print(OS, Policy); - Node->getTemplateName().print(OS, Policy, true); - OS << TemplateSpecializationType::PrintTemplateArgumentList( - Node->getTemplateArgs(), + OS << Node->getName().getAsString(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), Node->getNumTemplateArgs(), - Policy); + Policy); } void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { @@ -1048,11 +1054,6 @@ void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) { OS << Node->getType().getAsString() << "()"; } -void -StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) { - PrintRawDecl(E->getVarDecl()); -} - void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { if (E->isGlobalNew()) OS << "::"; @@ -1118,10 +1119,6 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << TypeS; } -void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { - OS << E->getName().getAsString(); -} - void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { // Nothing to print. } @@ -1146,7 +1143,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( OS << ")"; } -void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { +void StmtPrinter::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); if (NestedNameSpecifier *Qualifier = Node->getQualifier()) @@ -1165,6 +1163,24 @@ void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { } } +void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + + // FIXME: this might originally have been written with 'template' + + OS << Node->getMemberName().getAsString(); + + if (Node->hasExplicitTemplateArgs()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } +} + static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { default: assert(false && "Unknown type trait"); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 4458c2b..d832a46 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -20,11 +20,10 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor { + class StmtProfiler : public StmtVisitor { llvm::FoldingSetNodeID &ID; ASTContext &Context; bool Canonical; @@ -108,14 +107,17 @@ void StmtProfiler::VisitLabelStmt(LabelStmt *S) { void StmtProfiler::VisitIfStmt(IfStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitWhileStmt(WhileStmt *S) { VisitStmt(S); + VisitDecl(S->getConditionVariable()); } void StmtProfiler::VisitDoStmt(DoStmt *S) { @@ -481,10 +483,6 @@ void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) { - VisitDeclRefExpr(S); -} - void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) { VisitExpr(S); ID.AddBoolean(S->isGlobalDelete()); @@ -515,9 +513,13 @@ void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { } void -StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) { +StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) { VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { @@ -526,18 +528,14 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { VisitType(S->getQueriedType()); } -void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { +void +StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { VisitExpr(S); VisitName(S->getDeclName()); VisitNestedNameSpecifier(S->getQualifier()); - ID.AddBoolean(S->isAddressOfOperand()); -} - -void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) { - VisitExpr(S); - VisitNestedNameSpecifier(S->getQualifier()); - VisitTemplateName(S->getTemplateName()); - VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { @@ -554,11 +552,25 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { VisitType(S->getTypeAsWritten()); } -void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) { +void +StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { VisitExpr(S); ID.AddBoolean(S->isArrow()); VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); + ID.AddBoolean(S->hasExplicitTemplateArgumentList()); + if (S->hasExplicitTemplateArgumentList()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMemberName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp index 61fd750..8be287e 100644 --- a/lib/AST/StmtViz.cpp +++ b/lib/AST/StmtViz.cpp @@ -30,8 +30,9 @@ void Stmt::viewAST() const { namespace llvm { template<> struct DOTGraphTraits : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph, - bool ShortNames) { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) { #ifndef NDEBUG std::string OutSStr; diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index ff02f9a..f341b45 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/FoldingSet.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" @@ -59,8 +60,17 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, break; case Template: - ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) - .getAsVoidPointer()); + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null( + getAsTemplate().getAsTemplateDecl())) { + ID.AddBoolean(true); + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getPosition()); + } else { + ID.AddBoolean(false); + ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) + .getAsVoidPointer()); + } break; case Integral: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 297534e..5a2434d 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -725,6 +725,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case UndeducedAuto: return "auto"; case ObjCId: return "id"; case ObjCClass: return "Class"; + case ObjCSel: return "SEL"; } } @@ -866,6 +867,11 @@ static bool isDependent(const TemplateArgument &Arg) { } bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) { + return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size()); +} + +bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { for (unsigned i = 0; i != N; ++i) if (isDependent(Args[i].getArgument())) diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index a482333..562e830 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -535,6 +535,8 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, ObjCQIString = "id"; else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) ObjCQIString = "Class"; + else if (T->isObjCSelType()) + ObjCQIString = "SEL"; else ObjCQIString = T->getInterfaceDecl()->getNameAsString(); @@ -599,6 +601,14 @@ static void PrintTemplateArgument(std::string &Buffer, } } +std::string TemplateSpecializationType:: + PrintTemplateArgumentList(const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy) { + return PrintTemplateArgumentList(Args.getArgumentArray(), + Args.size(), + Policy); +} + std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 640912a..339e2c9 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -18,21 +18,12 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/Support/BumpVector.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; -AnalysisContext::~AnalysisContext() { - delete cfg; - delete liveness; - delete PM; -} - -AnalysisContextManager::~AnalysisContextManager() { - for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) - delete I->second; -} - void AnalysisContextManager::clear() { for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) delete I->second; @@ -73,7 +64,7 @@ LiveVariables *AnalysisContext::getLiveVariables() { if (!c) return 0; - liveness = new LiveVariables(D->getASTContext(), *c); + liveness = new LiveVariables(*this); liveness->runOnCFG(*c); liveness->runOnAllBlocks(*c, 0, true); } @@ -157,3 +148,75 @@ ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx, } return scope; } + +//===----------------------------------------------------------------------===// +// Lazily generated map to query the external variables referenced by a Block. +//===----------------------------------------------------------------------===// + +namespace { +class FindBlockDeclRefExprsVals : public StmtVisitor{ + BumpVector &BEVals; + BumpVectorContext &BC; +public: + FindBlockDeclRefExprsVals(BumpVector &bevals, + BumpVectorContext &bc) + : BEVals(bevals), BC(bc) {} + + void VisitStmt(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();I!=E;++I) + if (Stmt *child = *I) + Visit(child); + } + + void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) + BEVals.push_back(VD, BC); + } +}; +} // end anonymous namespace + +typedef BumpVector DeclVec; + +static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, + void *&Vec, + llvm::BumpPtrAllocator &A) { + if (Vec) + return (DeclVec*) Vec; + + BumpVectorContext BC(A); + DeclVec *BV = (DeclVec*) A.Allocate(); + new (BV) DeclVec(BC, 10); + + // Find the referenced variables. + FindBlockDeclRefExprsVals F(*BV, BC); + F.Visit(BD->getBody()); + + Vec = BV; + return BV; +} + +std::pair +AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { + if (!ReferencedBlockVars) + ReferencedBlockVars = new llvm::DenseMap(); + + DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); + return std::make_pair(V->begin(), V->end()); +} + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +AnalysisContext::~AnalysisContext() { + delete cfg; + delete liveness; + delete PM; + delete ReferencedBlockVars; +} + +AnalysisContextManager::~AnalysisContextManager() { + for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) + delete I->second; +} diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp index 549a22b..3d95ab1 100644 --- a/lib/Analysis/ArrayBoundChecker.cpp +++ b/lib/Analysis/ArrayBoundChecker.cpp @@ -20,7 +20,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN ArrayBoundChecker : +class ArrayBoundChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -62,8 +62,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.GenerateNode(S, StOutBound, true); - + ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; @@ -80,7 +79,12 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(S->getSourceRange()); - C.EmitReport(report); + return; } + + // Array bound check succeeded. From this point forward the array bound + // should always succeed. + assert(StInBound); + C.addTransition(StInBound); } diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp index 01e1a1f..aa21700 100644 --- a/lib/Analysis/AttrNonNullChecker.cpp +++ b/lib/Analysis/AttrNonNullChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN AttrNonNullChecker +class AttrNonNullChecker : public CheckerVisitor { BugType *BT; public: @@ -39,7 +39,6 @@ void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) { void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); - const GRState *originalState = state; // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); @@ -74,7 +73,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, if (stateNull && !stateNotNull) { // Generate an error node. Check for a null node in case // we cache out. - if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { + if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) { // Lazily allocate the BugType object if it hasn't already been // created. Ownership is transferred to the BugReporter object once @@ -109,6 +108,5 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, // If we reach here all of the arguments passed the nonnull check. // If 'state' has been updated generated a new node. - if (state != originalState) - C.addTransition(C.GenerateNode(CE, state)); + C.addTransition(state); } diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp deleted file mode 100644 index 7a7ea18..0000000 --- a/lib/Analysis/BadCallChecker.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines BadCallChecker, a builtin check in GRExprEngine that performs -// checks for bad callee at call sites. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "GRExprEngineInternalChecks.h" - -using namespace clang; - -namespace { -class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor { - BuiltinBug *BT; -public: - BadCallChecker() : BT(0) {} - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; -} // end anonymous namespace - -void clang::RegisterBadCallChecker(GRExprEngine &Eng) { - Eng.registerCheck(new BadCallChecker()); -} - -void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const Expr *Callee = CE->getCallee()->IgnoreParens(); - SVal L = C.getState()->getSVal(Callee); - - if (L.isUndef() || isa(L)) { - if (ExplodedNode *N = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BuiltinBug("Invalid function call", - "Called function pointer is a null or undefined pointer value"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription(), N); - - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetCalleeExpr(N)); - - C.EmitReport(R); - } - } -} diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index d0b8289..6c3f7b2 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -16,14 +16,13 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; -namespace { class VISIBILITY_HIDDEN ConstNotEq {}; } -namespace { class VISIBILITY_HIDDEN ConstEq {}; } +namespace { class ConstNotEq {}; } +namespace { class ConstEq {}; } typedef llvm::ImmutableMap ConstNotEqTy; typedef llvm::ImmutableMap ConstEqTy; @@ -46,7 +45,7 @@ struct GRStateTrait : public GRStatePartialTrait { namespace { // BasicConstraintManager only tracks equality and inequality constraints of // constants and integer variables. -class VISIBILITY_HIDDEN BasicConstraintManager +class BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index c2ecfa1..c913779 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -22,12 +22,12 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathDiagnostic.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" -#include "llvm/Support/Compiler.h" using namespace clang; @@ -52,12 +52,12 @@ static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { namespace { -class VISIBILITY_HIDDEN APIMisuse : public BugType { +class APIMisuse : public BugType { public: APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} }; -class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { +class BasicObjCFoundationChecks : public GRSimpleAPICheck { APIMisuse *BT; BugReporter& BR; ASTContext &Ctx; @@ -87,7 +87,7 @@ private: // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("nil argument"); - RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N); + RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); R->addRange(ME->getArg(Arg)->getSourceRange()); BR.EmitReport(R); } @@ -228,7 +228,7 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, namespace { -class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck { +class AuditCFNumberCreate : public GRSimpleAPICheck { APIMisuse* BT; // FIXME: Either this should be refactored into GRSimpleAPICheck, or @@ -435,7 +435,7 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, // Lazily create the BugType object. This will be owned // by the BugReporter object 'BR' once we call BR.EmitWarning. if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); - RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N); + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); report->addRange(Ex->getSourceRange()); BR.EmitReport(report); } @@ -450,7 +450,7 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck { +class AuditCFRetainRelease : public GRSimpleAPICheck { APIMisuse *BT; // FIXME: Either this should be refactored into GRSimpleAPICheck, or @@ -522,6 +522,64 @@ clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { } //===----------------------------------------------------------------------===// +// Check for sending 'retain', 'release', or 'autorelease' directly to a Class. +//===----------------------------------------------------------------------===// + +namespace { +class ClassReleaseChecker : + public CheckerVisitor { + Selector releaseS; + Selector retainS; + Selector autoreleaseS; + Selector drainS; + BugType *BT; +public: + ClassReleaseChecker(ASTContext &Ctx) + : releaseS(GetNullarySelector("release", Ctx)), + retainS(GetNullarySelector("retain", Ctx)), + autoreleaseS(GetNullarySelector("autorelease", Ctx)), + drainS(GetNullarySelector("drain", Ctx)), + BT(0) {} + + static void *getTag() { static int x = 0; return &x; } + + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); +}; +} + +void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const IdentifierInfo *ClsName = ME->getClassName(); + if (!ClsName) + return; + + Selector S = ME->getSelector(); + if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) + return; + + if (!BT) + BT = new APIMisuse("message incorrectly sent to class instead of class " + "instance"); + + ExplodedNode *N = C.GenerateNode(); + + if (!N) + return; + + llvm::SmallString<200> buf; + llvm::raw_svector_ostream os(buf); + + os << "The '" << S.getAsString() << "' message should be sent to instances " + "of class '" << ClsName->getName() + << "' and not the class directly"; + + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + report->addRange(ME->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -536,4 +594,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { RegisterNSErrorChecks(BR, Eng, D); RegisterNSAutoreleasePoolChecks(Eng); + Eng.registerCheck(new ClassReleaseChecker(Ctx)); } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h index ea4d3ec..679c6dc 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Analysis/BasicObjCFoundationChecks.h @@ -13,24 +13,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/ExplodedGraph.h" -#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ASTContext.h" -#include "llvm/Support/Compiler.h" - #ifndef LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS #define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS namespace clang { -class GRSimpleAPICheck; class ASTContext; -class GRStateManager; class BugReporter; +class Decl; class GRExprEngine; +class GRSimpleAPICheck; GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR); diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 800a76f..45fc11a 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/Analysis/PathSensitive/GRState.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -24,7 +23,7 @@ typedef llvm::ImmutableMap BindingsTy; namespace { -class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap { +class BasicStoreSubRegionMap : public SubRegionMap { public: BasicStoreSubRegionMap() {} @@ -33,7 +32,7 @@ public: } }; -class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager { +class BasicStoreManager : public StoreManager { BindingsTy::Factory VBFactory; public: BasicStoreManager(GRStateManager& mgr) diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 8235f4a..c26a60a 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -119,7 +119,7 @@ typedef llvm::DenseMap NodeBackMap; namespace { -class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver { +class NodeMapClosure : public BugReport::NodeResolver { NodeBackMap& M; public: NodeMapClosure(NodeBackMap *m) : M(*m) {} @@ -131,7 +131,7 @@ public: } }; -class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext { +class PathDiagnosticBuilder : public BugReporterContext { BugReport *R; PathDiagnosticClient *PDC; llvm::OwningPtr PM; @@ -358,7 +358,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N, } namespace { -class VISIBILITY_HIDDEN NotableSymbolHandler +class NotableSymbolHandler : public StoreManager::BindingsHandler { SymbolRef Sym; @@ -458,7 +458,7 @@ static void HandleNotableSymbol(const ExplodedNode* N, } namespace { -class VISIBILITY_HIDDEN ScanNotableSymbols +class ScanNotableSymbols : public StoreManager::BindingsHandler { llvm::SmallSet AlreadyProcessed; @@ -802,7 +802,7 @@ static bool IsControlFlowExpr(const Stmt *S) { } namespace { -class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation { +class ContextLocation : public PathDiagnosticLocation { bool IsDead; public: ContextLocation(const PathDiagnosticLocation &L, bool isdead = false) @@ -812,7 +812,7 @@ public: bool isDead() const { return IsDead; } }; -class VISIBILITY_HIDDEN EdgeBuilder { +class EdgeBuilder { std::vector CLocs; typedef std::vector::iterator iterator; PathDiagnostic &PD; @@ -1645,7 +1645,7 @@ void BugReporter::EmitReport(BugReport* R) { //===----------------------------------------------------------------------===// namespace { -struct VISIBILITY_HIDDEN FRIEC_WLItem { +struct FRIEC_WLItem { const ExplodedNode *N; ExplodedNode::const_succ_iterator I, E; @@ -1738,7 +1738,7 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) { // uses global state, which eventually should go elsewhere. //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode { +class DiagCacheItem : public llvm::FoldingSetNode { llvm::FoldingSetNodeID ID; public: DiagCacheItem(BugReport *R, PathDiagnostic *PD) { @@ -1835,14 +1835,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { PD->HandlePathDiagnostic(D.take()); } -void BugReporter::EmitBasicReport(const char* name, const char* str, +void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str, SourceLocation Loc, SourceRange* RBeg, unsigned NumRanges) { EmitBasicReport(name, "", str, Loc, RBeg, NumRanges); } -void BugReporter::EmitBasicReport(const char* name, const char* category, - const char* str, SourceLocation Loc, +void BugReporter::EmitBasicReport(llvm::StringRef name, + llvm::StringRef category, + llvm::StringRef str, SourceLocation Loc, SourceRange* RBeg, unsigned NumRanges) { // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'. diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp index 89c9ca1..87de30a 100644 --- a/lib/Analysis/BugReporterVisitors.cpp +++ b/lib/Analysis/BugReporterVisitors.cpp @@ -83,7 +83,7 @@ clang::bugreporter::GetRetValExpr(const ExplodedNode *N) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor { +class FindLastStoreBRVisitor : public BugReporterVisitor { const MemRegion *R; SVal V; bool satisfied; @@ -231,7 +231,7 @@ static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R, BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); } -class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor { +class TrackConstraintBRVisitor : public BugReporterVisitor { DefinedSVal Constraint; const bool Assumption; bool isSatisfied; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 3141759..c97692f 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -17,7 +17,6 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/GraphWriter.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Format.h" #include "llvm/ADT/DenseMap.h" @@ -50,7 +49,7 @@ static SourceLocation GetEndLoc(Decl* D) { /// constructed prior to its predecessor. This allows us to nicely capture /// implicit fall-throughs without extra basic blocks. /// -class VISIBILITY_HIDDEN CFGBuilder { +class CFGBuilder { ASTContext *Context; llvm::OwningPtr cfg; @@ -461,9 +460,12 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { return VisitStmt(B, alwaysAdd); } -CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) { - // FIXME - return NYS(); +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { + if (alwaysAdd) { + autoCreateBlock(); + AppendStmt(Block, E); + } + return Block; } CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E, @@ -1624,7 +1626,7 @@ CFG::~CFG() { namespace { -class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { +class StmtPrinterHelper : public PrinterHelper { typedef llvm::DenseMap > StmtMapTy; StmtMapTy StmtMap; @@ -1668,7 +1670,7 @@ public: namespace { -class VISIBILITY_HIDDEN CFGBlockTerminatorPrint +class CFGBlockTerminatorPrint : public StmtVisitor { llvm::raw_ostream& OS; @@ -2047,8 +2049,10 @@ void CFG::viewCFG(const LangOptions &LO) const { namespace llvm { template<> struct DOTGraphTraits : public DefaultDOTGraphTraits { - static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph, - bool ShortNames) { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { #ifndef NDEBUG std::string OutSStr; diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 55e5f17..b95f981 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -22,13 +22,14 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/STLExtras.h" #include @@ -168,7 +169,7 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { } namespace { -class VISIBILITY_HIDDEN GenericNodeBuilder { +class GenericNodeBuilder { GRStmtNodeBuilder *SNB; Stmt *S; const void *tag; @@ -246,7 +247,7 @@ namespace { /// RetEffect is used to summarize a function/method call's behavior with /// respect to its return value. -class VISIBILITY_HIDDEN RetEffect { +class RetEffect { public: enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias, @@ -312,7 +313,7 @@ public: // Reference-counting logic (typestate + counts). //===----------------------------------------------------------------------===// -class VISIBILITY_HIDDEN RefVal { +class RefVal { public: enum Kind { Owned = 0, // Owning reference. @@ -536,7 +537,7 @@ namespace clang { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RetainSummary { +class RetainSummary { /// Args - an ordered vector of (index, ArgEffect) pairs, where index /// specifies the argument (starting from 0). This can be sparsely /// populated; arguments with no entry in Args use 'DefaultArgEffect'. @@ -627,7 +628,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ObjCSummaryKey { +class ObjCSummaryKey { IdentifierInfo* II; Selector S; public: @@ -682,7 +683,7 @@ template <> struct DenseMapInfo { } // end llvm namespace namespace { -class VISIBILITY_HIDDEN ObjCSummaryCache { +class ObjCSummaryCache { typedef llvm::DenseMap MapTy; MapTy M; public: @@ -776,7 +777,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RetainSummaryManager { +class RetainSummaryManager { //==-----------------------------------------------------------------==// // Typedefs. @@ -1865,8 +1866,8 @@ typedef llvm::ImmutableList ARStack; static int AutoRCIndex = 0; static int AutoRBIndex = 0; -namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; } -namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; } +namespace { class AutoreleasePoolContents {}; } +namespace { class AutoreleaseStack {}; } namespace clang { template<> struct GRStateTrait @@ -1908,7 +1909,7 @@ static const GRState * SendAutorelease(const GRState *state, namespace { -class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { +class CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { public: @@ -2093,11 +2094,11 @@ namespace { // Bug Descriptions. // //===-------------===// - class VISIBILITY_HIDDEN CFRefBug : public BugType { + class CFRefBug : public BugType { protected: CFRefCount& TF; - CFRefBug(CFRefCount* tf, const char* name) + CFRefBug(CFRefCount* tf, llvm::StringRef name) : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {} public: @@ -2110,7 +2111,7 @@ namespace { virtual bool isLeak() const { return false; } }; - class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug { + class UseAfterRelease : public CFRefBug { public: UseAfterRelease(CFRefCount* tf) : CFRefBug(tf, "Use-after-release") {} @@ -2120,7 +2121,7 @@ namespace { } }; - class VISIBILITY_HIDDEN BadRelease : public CFRefBug { + class BadRelease : public CFRefBug { public: BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {} @@ -2130,7 +2131,7 @@ namespace { } }; - class VISIBILITY_HIDDEN DeallocGC : public CFRefBug { + class DeallocGC : public CFRefBug { public: DeallocGC(CFRefCount *tf) : CFRefBug(tf, "-dealloc called while using garbage collection") {} @@ -2140,7 +2141,7 @@ namespace { } }; - class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug { + class DeallocNotOwned : public CFRefBug { public: DeallocNotOwned(CFRefCount *tf) : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {} @@ -2150,7 +2151,7 @@ namespace { } }; - class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug { + class OverAutorelease : public CFRefBug { public: OverAutorelease(CFRefCount *tf) : CFRefBug(tf, "Object sent -autorelease too many times") {} @@ -2160,7 +2161,7 @@ namespace { } }; - class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug { + class ReturnedNotOwnedForOwned : public CFRefBug { public: ReturnedNotOwnedForOwned(CFRefCount *tf) : CFRefBug(tf, "Method should return an owned object") {} @@ -2171,10 +2172,10 @@ namespace { } }; - class VISIBILITY_HIDDEN Leak : public CFRefBug { + class Leak : public CFRefBug { const bool isReturn; protected: - Leak(CFRefCount* tf, const char* name, bool isRet) + Leak(CFRefCount* tf, llvm::StringRef name, bool isRet) : CFRefBug(tf, name), isReturn(isRet) {} public: @@ -2183,15 +2184,15 @@ namespace { bool isLeak() const { return true; } }; - class VISIBILITY_HIDDEN LeakAtReturn : public Leak { + class LeakAtReturn : public Leak { public: - LeakAtReturn(CFRefCount* tf, const char* name) + LeakAtReturn(CFRefCount* tf, llvm::StringRef name) : Leak(tf, name, true) {} }; - class VISIBILITY_HIDDEN LeakWithinFunction : public Leak { + class LeakWithinFunction : public Leak { public: - LeakWithinFunction(CFRefCount* tf, const char* name) + LeakWithinFunction(CFRefCount* tf, llvm::StringRef name) : Leak(tf, name, false) {} }; @@ -2199,7 +2200,7 @@ namespace { // Bug Reports. // //===---------===// - class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport { + class CFRefReport : public RangedBugReport { protected: SymbolRef Sym; const CFRefCount &TF; @@ -2209,7 +2210,7 @@ namespace { : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {} CFRefReport(CFRefBug& D, const CFRefCount &tf, - ExplodedNode *n, SymbolRef sym, const char* endText) + ExplodedNode *n, SymbolRef sym, llvm::StringRef endText) : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {} virtual ~CFRefReport() {} @@ -2240,7 +2241,7 @@ namespace { BugReporterContext& BRC); }; - class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport { + class CFRefLeakReport : public CFRefReport { SourceLocation AllocSite; const MemRegion* AllocBinding; public: @@ -2255,64 +2256,7 @@ namespace { }; } // end anonymous namespace -void CFRefCount::RegisterChecks(GRExprEngine& Eng) { - BugReporter &BR = Eng.getBugReporter(); - - useAfterRelease = new UseAfterRelease(this); - BR.Register(useAfterRelease); - - releaseNotOwned = new BadRelease(this); - BR.Register(releaseNotOwned); - - deallocGC = new DeallocGC(this); - BR.Register(deallocGC); - - deallocNotOwned = new DeallocNotOwned(this); - BR.Register(deallocNotOwned); - - overAutorelease = new OverAutorelease(this); - BR.Register(overAutorelease); - - returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); - BR.Register(returnNotOwnedForOwned); - - // First register "return" leaks. - const char* name = 0; - - if (isGCEnabled()) - name = "Leak of returned object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of returned object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak of returned object"; - } - - // Leaks should not be reported if they are post-dominated by a sink. - leakAtReturn = new LeakAtReturn(this, name); - leakAtReturn->setSuppressOnSink(true); - BR.Register(leakAtReturn); - - // Second, register leaks within a function/method. - if (isGCEnabled()) - name = "Leak of object when using garbage collection"; - else if (getLangOptions().getGCMode() == LangOptions::HybridGC) - name = "Leak of object when not using garbage collection (GC) in " - "dual GC/non-GC code"; - else { - assert(getLangOptions().getGCMode() == LangOptions::NonGC); - name = "Leak"; - } - - // Leaks should not be reported if they are post-dominated by sinks. - leakWithinFunction = new LeakWithinFunction(this, name); - leakWithinFunction->setSuppressOnSink(true); - BR.Register(leakWithinFunction); - // Save the reference to the BugReporter. - this->BR = &BR; -} static const char* Msgs[] = { // GC only @@ -2603,7 +2547,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } namespace { - class VISIBILITY_HIDDEN FindUniqueBinding : + class FindUniqueBinding : public StoreManager::BindingsHandler { SymbolRef Sym; const MemRegion* Binding; @@ -3052,9 +2996,20 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, ExplodedNode* Pred) { - const FunctionDecl* FD = L.getAsFunctionDecl(); - RetainSummary* Summ = !FD ? Summaries.getDefaultSummary() - : Summaries.getSummary(const_cast(FD)); + + RetainSummary *Summ = 0; + + // FIXME: Better support for blocks. For now we stop tracking anything + // that is passed to blocks. + // FIXME: Need to handle variables that are "captured" by the block. + if (dyn_cast_or_null(L.getAsRegion())) { + Summ = Summaries.getPersistentStopSummary(); + } + else { + const FunctionDecl* FD = L.getAsFunctionDecl(); + Summ = !FD ? Summaries.getDefaultSummary() : + Summaries.getSummary(const_cast(FD)); + } assert(Summ); EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, @@ -3066,6 +3021,16 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, ExplodedNode* Pred) { + // FIXME: Since we moved the nil check into a checker, we could get nil + // receiver here. Need a better way to check such case. + if (Expr* Receiver = ME->getReceiver()) { + const GRState *state = Pred->getState(); + DefinedOrUnknownSVal L=cast(state->getSVal(Receiver)); + if (!state->Assume(L, true)) { + Dst.Add(Pred); + return; + } + } RetainSummary *Summ = ME->getReceiver() @@ -3079,7 +3044,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, } namespace { -class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor { +class StopTrackingCallback : public SymbolVisitor { const GRState *state; public: StopTrackingCallback(const GRState *st) : state(st) {} @@ -3501,7 +3466,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd CFRefReport *report = new CFRefReport(*static_cast(overAutorelease), - *this, N, Sym, os.str().c_str()); + *this, N, Sym, os.str()); BR->EmitReport(report); } @@ -3670,9 +3635,114 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, } //===----------------------------------------------------------------------===// +// Pieces of the retain/release checker implemented using a CheckerVisitor. +// More pieces of the retain/release checker will be migrated to this interface +// (ideally, all of it some day). +//===----------------------------------------------------------------------===// + +namespace { +class RetainReleaseChecker + : public CheckerVisitor { + CFRefCount *TF; +public: + RetainReleaseChecker(CFRefCount *tf) : TF(tf) {} + static void* getTag() { static int x = 0; return &x; } + + void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); +}; +} // end anonymous namespace + + +void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, + const BlockExpr *BE) { + + // Scan the BlockDecRefExprs for any object the retain/release checker + // may be tracking. + if (!BE->hasBlockDeclRefExprs()) + return; + + const GRState *state = C.getState(); + const BlockDataRegion *R = + cast(state->getSVal(BE).getAsRegion()); + + BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), + E = R->referenced_vars_end(); + + if (I == E) + return; + + state = state->scanReachableSymbols(I, E).getState(); + C.addTransition(state); +} + +//===----------------------------------------------------------------------===// // Transfer function creation for external clients. //===----------------------------------------------------------------------===// +void CFRefCount::RegisterChecks(GRExprEngine& Eng) { + BugReporter &BR = Eng.getBugReporter(); + + useAfterRelease = new UseAfterRelease(this); + BR.Register(useAfterRelease); + + releaseNotOwned = new BadRelease(this); + BR.Register(releaseNotOwned); + + deallocGC = new DeallocGC(this); + BR.Register(deallocGC); + + deallocNotOwned = new DeallocNotOwned(this); + BR.Register(deallocNotOwned); + + overAutorelease = new OverAutorelease(this); + BR.Register(overAutorelease); + + returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this); + BR.Register(returnNotOwnedForOwned); + + // First register "return" leaks. + const char* name = 0; + + if (isGCEnabled()) + name = "Leak of returned object when using garbage collection"; + else if (getLangOptions().getGCMode() == LangOptions::HybridGC) + name = "Leak of returned object when not using garbage collection (GC) in " + "dual GC/non-GC code"; + else { + assert(getLangOptions().getGCMode() == LangOptions::NonGC); + name = "Leak of returned object"; + } + + // Leaks should not be reported if they are post-dominated by a sink. + leakAtReturn = new LeakAtReturn(this, name); + leakAtReturn->setSuppressOnSink(true); + BR.Register(leakAtReturn); + + // Second, register leaks within a function/method. + if (isGCEnabled()) + name = "Leak of object when using garbage collection"; + else if (getLangOptions().getGCMode() == LangOptions::HybridGC) + name = "Leak of object when not using garbage collection (GC) in " + "dual GC/non-GC code"; + else { + assert(getLangOptions().getGCMode() == LangOptions::NonGC); + name = "Leak"; + } + + // Leaks should not be reported if they are post-dominated by sinks. + leakWithinFunction = new LeakWithinFunction(this, name); + leakWithinFunction->setSuppressOnSink(true); + BR.Register(leakWithinFunction); + + // Save the reference to the BugReporter. + this->BR = &BR; + + // Register the RetainReleaseChecker with the GRExprEngine object. + // Functionality in CFRefCount will be migrated to RetainReleaseChecker + // over time. + Eng.registerCheck(new RetainReleaseChecker(this)); +} + GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts) { return new CFRefCount(Ctx, GCEnabled, lopts); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 8e8c1e7..409292d 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -4,7 +4,6 @@ add_clang_library(clangAnalysis AnalysisContext.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp - BadCallChecker.cpp BasicConstraintManager.cpp BasicObjCFoundationChecks.cpp BasicStore.cpp @@ -13,6 +12,7 @@ add_clang_library(clangAnalysis BugReporterVisitors.cpp CFG.cpp CFRefCount.cpp + CallAndMessageChecker.cpp CallGraph.cpp CallInliner.cpp CastToStructChecker.cpp @@ -22,6 +22,7 @@ add_clang_library(clangAnalysis CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp + Checker.cpp DereferenceChecker.cpp DivZeroChecker.cpp Environment.cpp @@ -31,7 +32,6 @@ add_clang_library(clangAnalysis GRCoreEngine.cpp GRExprEngine.cpp GRExprEngineExperimentalChecks.cpp - GRExprEngineInternalChecks.cpp GRState.cpp LiveVariables.cpp MallocChecker.cpp @@ -54,7 +54,8 @@ add_clang_library(clangAnalysis SimpleSValuator.cpp Store.cpp SymbolManager.cpp - UndefinedArgChecker.cpp + UndefBranchChecker.cpp + UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp UninitializedValues.cpp diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp new file mode 100644 index 0000000..d8dd16c --- /dev/null +++ b/lib/Analysis/CallAndMessageChecker.cpp @@ -0,0 +1,267 @@ +//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines CallAndMessageChecker, a builtin checker that checks for various +// errors of call and objc message expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/ParentMap.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class CallAndMessageChecker + : public CheckerVisitor { + BugType *BT_call_null; + BugType *BT_call_undef; + BugType *BT_call_arg; + BugType *BT_msg_undef; + BugType *BT_msg_arg; + BugType *BT_msg_ret; +public: + CallAndMessageChecker() : + BT_call_null(0), BT_call_undef(0), BT_call_arg(0), + BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {} + + static void *getTag() { + static int x = 0; + return &x; + } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + +private: + void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); + void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, + ExplodedNode *N); + + void HandleNilReceiver(CheckerContext &C, const GRState *state, + const ObjCMessageExpr *ME); +}; +} // end anonymous namespace + +void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) { + Eng.registerCheck(new CallAndMessageChecker()); +} + +void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, + const CallExpr *CE) { + ExplodedNode *N = C.GenerateSink(); + if (!N) + return; + + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetCalleeExpr(N)); + C.EmitReport(R); +} + +void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, + const CallExpr *CE){ + + const Expr *Callee = CE->getCallee()->IgnoreParens(); + SVal L = C.getState()->getSVal(Callee); + + if (L.isUndef()) { + if (!BT_call_undef) + BT_call_undef = + new BuiltinBug("Called function pointer is an undefined pointer value"); + EmitBadCall(BT_call_undef, C, CE); + return; + } + + if (isa(L)) { + if (!BT_call_null) + BT_call_null = + new BuiltinBug("Called function pointer is null (null dereference)"); + EmitBadCall(BT_call_null, C, CE); + } + + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + if (C.getState()->getSVal(*I).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_call_arg) + BT_call_arg = new BuiltinBug("Pass-by-value argument in function call" + " is undefined"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg, + BT_call_arg->getName(), N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + return; + } + } + } +} + +void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const GRState *state = C.getState(); + + if (const Expr *receiver = ME->getReceiver()) + if (state->getSVal(receiver).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_msg_undef) + BT_msg_undef = + new BuiltinBug("Receiver in message expression is a garbage value"); + EnhancedBugReport *R = + new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); + R->addRange(receiver->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + C.EmitReport(R); + } + return; + } + + // Check for any arguments that are uninitialized/undefined. + for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), + E = ME->arg_end(); I != E; ++I) { + if (state->getSVal(*I).isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + if (!BT_msg_arg) + BT_msg_arg = + new BuiltinBug("Pass-by-value argument in message expression" + " is undefined"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg, + BT_msg_arg->getName(), N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + return; + } + } + } + + // Check if the receiver was nil and then returns a value that may + // be garbage. + if (const Expr *Receiver = ME->getReceiver()) { + DefinedOrUnknownSVal receiverVal = + cast(state->getSVal(Receiver)); + + const GRState *notNullState, *nullState; + llvm::tie(notNullState, nullState) = state->Assume(receiverVal); + + if (nullState && !notNullState) { + HandleNilReceiver(C, nullState, ME); + C.setDoneEvaluating(); // FIXME: eventually remove. + return; + } + + assert(notNullState); + state = notNullState; + } + + // Add a state transition if the state has changed. + C.addTransition(state); +} + +void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, + const ObjCMessageExpr *ME, + ExplodedNode *N) { + + if (!BT_msg_ret) + BT_msg_ret = + new BuiltinBug("Receiver in message expression is " + "'nil' and returns a garbage value"); + + llvm::SmallString<200> buf; + llvm::raw_svector_ostream os(buf); + os << "The receiver of message '" << ME->getSelector().getAsString() + << "' is nil and returns a value of type '" + << 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); + C.EmitReport(report); +} + +static bool SupportsNilWithFloatRet(const llvm::Triple &triple) { + return triple.getVendor() == llvm::Triple::Apple && + triple.getDarwinMajorNumber() >= 9; +} + +void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, + const GRState *state, + const ObjCMessageExpr *ME) { + + // Check the return type of the message expression. A message to nil will + // return different values depending on the return type and the architecture. + QualType RetTy = ME->getType(); + + ASTContext &Ctx = C.getASTContext(); + CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); + + if (CanRetTy->isStructureType()) { + // 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. + if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + if (ExplodedNode* N = C.GenerateSink(state)) + EmitNilReceiverBug(C, ME, N); + return; + } + + // The result is not consumed by a surrounding expression. Just propagate + // the current state. + C.addTransition(state); + return; + } + + // Other cases: check if the return type is smaller than void*. + if (CanRetTy != Ctx.VoidTy && + C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { + // Compute: sizeof(void *) and sizeof(return type) + const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); + const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); + + if (voidPtrSize < returnTypeSize && + !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) && + (Ctx.FloatTy == CanRetTy || + Ctx.DoubleTy == CanRetTy || + Ctx.LongDoubleTy == CanRetTy || + Ctx.LongLongTy == CanRetTy))) { + if (ExplodedNode* N = C.GenerateSink(state)) + EmitNilReceiverBug(C, ME, N); + return; + } + + // Handle the safe cases where the return value is 0 if the + // receiver is nil. + // + // FIXME: For now take the conservative approach that we only + // return null values if we *know* that the receiver is nil. + // This is because we can have surprises like: + // + // ... = [[NSScreens screens] objectAtIndex:0]; + // + // What can happen is that [... screens] could return nil, but + // it most likely isn't nil. We should assume the semantics + // of this case unless we have *a lot* more knowledge. + // + SVal V = C.getValueManager().makeZeroVal(ME->getType()); + C.GenerateNode(state->BindExpr(ME, V)); + return; + } + + C.addTransition(state); +} diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index 06e3317..c1040f0 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -137,8 +137,10 @@ namespace llvm { template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + static std::string getNodeLabel(const CallGraphNode *Node, - const CallGraph &CG, bool ShortNames) { + const CallGraph &CG) { return Node->getName(); } diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp index cca8584..43523c2 100644 --- a/lib/Analysis/CallInliner.cpp +++ b/lib/Analysis/CallInliner.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs { +class CallInliner : public GRTransferFuncs { ASTContext &Ctx; public: CallInliner(ASTContext &ctx) : Ctx(ctx) {} diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp index ccd4a33..a366342 100644 --- a/lib/Analysis/CastToStructChecker.cpp +++ b/lib/Analysis/CastToStructChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN CastToStructChecker +class CastToStructChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -59,7 +59,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, // Now the cast-to-type is struct pointer, the original type is not void*. if (!OrigPointeeTy->isRecordType()) { - if (ExplodedNode *N = C.GenerateNode(CE)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Cast from non-struct type to struct type", "Casting a non-structure type to a structure type " diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index d5cb7ca..ad63eb4 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -22,13 +22,12 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ParentMap.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy { +class DeadStoreObs : public LiveVariables::ObserverTy { ASTContext &Ctx; BugReporter& BR; ParentMap& Parents; @@ -77,7 +76,7 @@ public: break; } - BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R); + BR.EmitBasicReport(BugType, "Dead store", msg, L, R); } void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val, @@ -134,16 +133,15 @@ public: if (DeclRefExpr* DR = dyn_cast(B->getLHS())) if (VarDecl *VD = dyn_cast(DR->getDecl())) { - Expr* RHS = B->getRHS()->IgnoreParenCasts(); - // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. if (VD->getType()->isPointerType()) { - if (IntegerLiteral* L = dyn_cast(RHS)) - // FIXME: Probably should have an Expr::isNullPointerConstant. - if (L->getValue() == 0) - return; + if (B->getRHS()->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull)) + return; } + + Expr* RHS = B->getRHS()->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. if (DeclRefExpr* RhsDR = dyn_cast(RHS)) @@ -226,7 +224,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor{ +class FindEscaped : public CFGRecStmtDeclVisitor{ CFG *cfg; public: FindEscaped(CFG *c) : cfg(c) {} diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp index 92e3e11..87c1f27 100644 --- a/lib/Analysis/CheckObjCDealloc.cpp +++ b/lib/Analysis/CheckObjCDealloc.cpp @@ -169,7 +169,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, os << "Objective-C class '" << D->getNameAsString() << "' lacks a 'dealloc' instance method"; - BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; } @@ -187,7 +187,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; - BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart()); + BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; } @@ -251,8 +251,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, "but was released in 'dealloc'"; } - BR.EmitBasicReport(name, category, - os.str().c_str(), (*I)->getLocation()); + BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation()); } } } diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp index 8c0d396..10ba896 100644 --- a/lib/Analysis/CheckObjCInstMethSignature.cpp +++ b/lib/Analysis/CheckObjCInstMethSignature.cpp @@ -65,7 +65,7 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, "behavior for clients of these classes."; BR.EmitBasicReport("Incompatible instance method return type", - os.str().c_str(), MethDerived->getLocStart()); + os.str(), MethDerived->getLocStart()); } } diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 2d9b531..d4067c9 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" using namespace clang; @@ -85,6 +86,17 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { } } +static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, + SourceManager &SM) { + for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end(); + I!=E; ++I) + if (const FunctionDecl *FD = dyn_cast(*I)) { + SourceLocation L = FD->getLocStart(); + if (SM.getFileID(L) == FID) + Scan(M, FD->getBody()); + } +} + void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { @@ -110,10 +122,30 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (M.empty()) return; - + // Now scan the implementation declaration. Scan(M, D); + + // Any potentially unused ivars? + bool hasUnused = false; + for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) + if (I->second == Unused) { + hasUnused = true; + break; + } + + if (!hasUnused) + return; + + // We found some potentially unused ivars. Scan the entire translation unit + // for functions inside the @implementation that reference these ivars. + // FIXME: In the future hopefully we can just use the lexical DeclContext + // to go from the ObjCImplementationDecl to the lexically "nested" + // C functions. + SourceManager &SM = BR.getSourceManager(); + Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM); + // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { @@ -125,6 +157,6 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, "(although it may be used by category methods)."; BR.EmitBasicReport("Unused instance variable", "Optimization", - os.str().c_str(), I->first->getLocation()); + os.str(), I->first->getLocation()); } } diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index f1b9c21..e6ab17a 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -14,13 +14,12 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/StmtVisitor.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN WalkAST : public StmtVisitor { +class WalkAST : public StmtVisitor { BugReporter &BR; IdentifierInfo *II_gets; IdentifierInfo *II_getpw; @@ -210,7 +209,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { ranges.push_back(drInc->getSourceRange()); const char *bugType = "Floating point variable used as loop counter"; - BR.EmitBasicReport(bugType, "Security", os.str().c_str(), + BR.EmitBasicReport(bugType, "Security", os.str(), FS->getLocStart(), ranges.data(), ranges.size()); } @@ -347,7 +346,7 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CE->getLocStart(), &R, 1); } @@ -437,7 +436,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { SourceRange R = CE->getCallee()->getSourceRange(); - BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(), + BR.EmitBasicReport(os1.str(), "Security", os2.str(), CE->getLocStart(), &R, 1); } diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp index 174beef..4f5da9f 100644 --- a/lib/Analysis/CheckSizeofPointer.cpp +++ b/lib/Analysis/CheckSizeofPointer.cpp @@ -15,12 +15,11 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/LocalCheckers.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN WalkAST : public StmtVisitor { +class WalkAST : public StmtVisitor { BugReporter &BR; public: diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp new file mode 100644 index 0000000..0d907e5 --- /dev/null +++ b/lib/Analysis/Checker.cpp @@ -0,0 +1,35 @@ +//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Checker and CheckerVisitor, classes used for creating +// domain-specific checks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checker.h" +using namespace clang; + +Checker::~Checker() {} + +CheckerContext::~CheckerContext() { + // Do we need to autotransition? 'Dst' can get populated in a variety of + // ways, including 'addTransition()' adding the predecessor node to Dst + // without actually generated a new node. We also shouldn't autotransition + // if we are building sinks or we generated a node and decided to not + // add it as a transition. + if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) { + if (state && state != B.GetState(Pred)) { + static int autoTransitionTag = 0; + B.Tag = &autoTransitionTag; + addTransition(state); + } + else + Dst.Add(Pred); + } +} diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp index c3aa8f3..9824387 100644 --- a/lib/Analysis/DereferenceChecker.cpp +++ b/lib/Analysis/DereferenceChecker.cpp @@ -21,7 +21,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN DereferenceChecker : public Checker { +class DereferenceChecker : public Checker { BuiltinBug *BT_null; BuiltinBug *BT_undef; llvm::SmallVector ImplicitNullDerefNodes; @@ -56,8 +56,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { // Check for dereference of an undefined value. if (l.isUndef()) { - ExplodedNode *N = C.GenerateNode(S, true); - if (N) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_undef) BT_undef = new BuiltinBug("Dereference of undefined pointer value"); @@ -82,34 +81,55 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, // The explicit NULL case. if (nullState) { - // Generate an error node. - ExplodedNode *N = C.GenerateNode(S, nullState, true); - if (N) { - if (!notNullState) { - // We know that 'location' cannot be non-null. This is what - // we call an "explicit" null dereference. - if (!BT_null) - BT_null = new BuiltinBug("Null pointer dereference", - "Dereference of null pointer"); - - EnhancedBugReport *report = - new EnhancedBugReport(*BT_null, BT_null->getDescription(), N); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); - - C.EmitReport(report); + if (!notNullState) { + // Generate an error node. + ExplodedNode *N = C.GenerateSink(nullState); + if (!N) return; + + // We know that 'location' cannot be non-null. This is what + // we call an "explicit" null dereference. + if (!BT_null) + BT_null = new BuiltinBug("Dereference of null pointer"); + + llvm::SmallString<100> buf; + + switch (S->getStmtClass()) { + case Stmt::UnaryOperatorClass: { + const UnaryOperator *U = cast(S); + const Expr *SU = U->getSubExpr()->IgnoreParens(); + if (const DeclRefExpr *DR = dyn_cast(SU)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + llvm::raw_svector_ostream os(buf); + os << "Dereference of null pointer loaded from variable '" + << VD->getName() << '\''; + } + } + } + default: + break; } + EnhancedBugReport *report = + new EnhancedBugReport(*BT_null, + buf.empty() ? BT_null->getDescription():buf.str(), + N); + + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + + C.EmitReport(report); + return; + } + else { // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null - // dereference. - ImplicitNullDerefNodes.push_back(N); + // dereference. + if (ExplodedNode *N = C.GenerateSink(nullState)) + ImplicitNullDerefNodes.push_back(N); } } // From this point forward, we know that the location is not null. - assert(notNullState); - C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) : - C.getPredecessor()); + C.addTransition(notNullState); } diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp index a8630f1..266c236 100644 --- a/lib/Analysis/DivZeroChecker.cpp +++ b/lib/Analysis/DivZeroChecker.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor { +class DivZeroChecker : public CheckerVisitor { BuiltinBug *BT; public: DivZeroChecker() : BT(0) {} @@ -63,7 +63,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); if (stateZero && !stateNotZero) { - if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (ExplodedNode *N = C.GenerateSink(stateZero)) { if (!BT) BT = new BuiltinBug("Division by zero"); @@ -80,6 +80,5 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, // If we get here, then the denom should not be zero. We abandon the implicit // zero denom case for now. - if (stateNotZero != C.getState()) - C.addTransition(C.GenerateNode(B, stateNotZero)); + C.addTransition(stateNotZero); } diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index 1610ad4..dd2f08b 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/Analyses/LiveVariables.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/ImmutableMap.h" using namespace clang; @@ -83,7 +82,7 @@ Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S, } namespace { -class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor { +class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; public: MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp index 80096dc..031ca44 100644 --- a/lib/Analysis/FixedAddressChecker.cpp +++ b/lib/Analysis/FixedAddressChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN FixedAddressChecker +class FixedAddressChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -53,7 +53,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, if (!RV.isConstant() || RV.isZeroConstant()) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Use fixed address", "Using a fixed address is not portable because that " diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index b99ba4f..644dd19 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/PathSensitive/GRCoreEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/AST/Expr.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" #include @@ -30,7 +29,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN DFS : public GRWorkList { +class DFS : public GRWorkList { llvm::SmallVector Stack; public: virtual bool hasWork() const { @@ -49,7 +48,7 @@ public: } }; -class VISIBILITY_HIDDEN BFS : public GRWorkList { +class BFS : public GRWorkList { std::queue Queue; public: virtual bool hasWork() const { @@ -79,7 +78,7 @@ GRWorkList *GRWorkList::MakeDFS() { return new DFS(); } GRWorkList *GRWorkList::MakeBFS() { return new BFS(); } namespace { - class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList { + class BFSBlockDFSContents : public GRWorkList { std::queue Queue; llvm::SmallVector Stack; public: diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 2633177..20820d4 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" #include "clang/Analysis/PathSensitive/Checker.h" @@ -22,7 +23,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/PrettyStackTrace.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/StringSwitch.h" @@ -37,12 +37,21 @@ using llvm::cast; using llvm::APSInt; //===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(0, &II); +} + +//===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck { +class MappedBatchAuditor : public GRSimpleAPICheck { typedef llvm::ImmutableList Checks; typedef llvm::DenseMap MapTy; @@ -107,16 +116,17 @@ public: // Checker worklist routines. //===----------------------------------------------------------------------===// -void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, +bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { if (Checkers.empty()) { - Dst = Src; - return; + Dst.insert(Src); + return false; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; + bool stopProcessingAfterCurrentChecker = false; for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { @@ -126,17 +136,33 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; - + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); + NI != NE; ++NI) { + // FIXME: Halting evaluation of the checkers is something we may + // not support later. The design is still evolving. + if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, + tag, isPrevisit)) { + if (CurrSet != &Dst) + Dst.insert(*CurrSet); + + stopProcessingAfterCurrentChecker = true; + continue; + } + assert(stopProcessingAfterCurrentChecker == false && + "Inconsistent setting of 'stopProcessingAfterCurrentChecker'"); + } + + if (stopProcessingAfterCurrentChecker) + return true; - // Update which NodeSet is the current one. + // Continue on to the next checker. Update the current NodeSet. PrevSet = CurrSet; } // Don't autotransition. The CheckerContext objects should do this // automatically. + return false; } // FIXME: This is largely copy-paste from CheckerVisit(). Need to @@ -179,12 +205,30 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, // Engine construction and deletion. //===----------------------------------------------------------------------===// -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(0, &II); +static void RegisterInternalChecks(GRExprEngine &Eng) { + // Register internal "built-in" BugTypes with the BugReporter. These BugTypes + // are different than what probably many checks will do since they don't + // create BugReports on-the-fly but instead wait until GRExprEngine finishes + // analyzing a function. Generation of BugReport objects is done via a call + // to 'FlushReports' from BugReporter. + // The following checks do not need to have their associated BugTypes + // explicitly registered with the BugReporter. If they issue any BugReports, + // their associated BugType will get registered with the BugReporter + // automatically. Note that the check itself is owned by the GRExprEngine + // object. + RegisterAttrNonNullChecker(Eng); + RegisterCallAndMessageChecker(Eng); + RegisterDereferenceChecker(Eng); + RegisterVLASizeChecker(Eng); + RegisterDivZeroChecker(Eng); + RegisterReturnStackAddressChecker(Eng); + RegisterReturnUndefChecker(Eng); + RegisterUndefinedArraySubscriptChecker(Eng); + RegisterUndefinedAssignmentChecker(Eng); + RegisterUndefBranchChecker(Eng); + RegisterUndefResultChecker(Eng); } - GRExprEngine::GRExprEngine(AnalysisManager &mgr) : AMgr(mgr), CoreEngine(mgr.getASTContext(), *this), @@ -198,7 +242,11 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr) CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), - BR(mgr, *this) {} + BR(mgr, *this) +{ + // Register internal checks. + RegisterInternalChecks(*this); +} GRExprEngine::~GRExprEngine() { BR.FlushReports(); @@ -211,7 +259,6 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// - void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { StateMgr.TF = tf; tf->RegisterChecks(*this); @@ -410,6 +457,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmt(cast(S), Pred, Dst); break; + case Stmt::BlockExprClass: + VisitBlockExpr(cast(S), Pred, Dst); + break; + case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(S); @@ -771,55 +822,49 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, Condition->getLocStart(), "Error evaluating branch"); - const GRState* PrevState = builder.getState(); - SVal X = PrevState->getSVal(Condition); - DefinedSVal *V = NULL; - - while (true) { - V = dyn_cast(&X); - - if (!V) { - if (X.isUnknown()) { - if (const Expr *Ex = dyn_cast(Condition)) { - if (Ex->getType()->isIntegerType()) { - // Try to recover some path-sensitivity. Right now casts of symbolic - // integers that promote their values are currently not tracked well. - // If 'Condition' is such an expression, try and recover the - // underlying value and use that instead. - SVal recovered = RecoverCastedSymbol(getStateManager(), - builder.getState(), Condition, - getContext()); - - if (!recovered.isUnknown()) { - X = recovered; - continue; - } - } - } + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + checker->VisitBranchCondition(builder, *this, Condition, tag); + } - builder.generateNode(MarkBranch(PrevState, Term, true), true); - builder.generateNode(MarkBranch(PrevState, Term, false), false); - return; - } + // If the branch condition is undefined, return; + if (!builder.isFeasible(true) && !builder.isFeasible(false)) + return; - assert(X.isUndef()); - ExplodedNode *N = builder.generateNode(PrevState, true); + const GRState* PrevState = builder.getState(); + SVal X = PrevState->getSVal(Condition); - if (N) { - N->markAsSink(); - UndefBranches.insert(N); + if (X.isUnknown()) { + // Give it a chance to recover from unknown. + if (const Expr *Ex = dyn_cast(Condition)) { + if (Ex->getType()->isIntegerType()) { + // Try to recover some path-sensitivity. Right now casts of symbolic + // integers that promote their values are currently not tracked well. + // If 'Condition' is such an expression, try and recover the + // underlying value and use that instead. + SVal recovered = RecoverCastedSymbol(getStateManager(), + builder.getState(), Condition, + getContext()); + + if (!recovered.isUnknown()) { + X = recovered; + } } - - builder.markInfeasible(false); + } + // If the condition is still unknown, give up. + if (X.isUnknown()) { + builder.generateNode(MarkBranch(PrevState, Term, true), true); + builder.generateNode(MarkBranch(PrevState, Term, false), false); return; } - - break; } + DefinedSVal V = cast(X); + // Process the true branch. if (builder.isFeasible(true)) { - if (const GRState *state = PrevState->Assume(*V, true)) + if (const GRState *state = PrevState->Assume(V, true)) builder.generateNode(MarkBranch(state, Term, true), true); else builder.markInfeasible(true); @@ -827,7 +872,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, // Process the false branch. if (builder.isFeasible(false)) { - if (const GRState *state = PrevState->Assume(*V, false)) + if (const GRState *state = PrevState->Assume(V, false)) builder.generateNode(MarkBranch(state, Term, false), false); else builder.markInfeasible(false); @@ -866,8 +911,9 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { if (isa(V) || isa(V)) { // Dispatch to the first target and mark it as a sink. - ExplodedNode* N = builder.generateNode(builder.begin(), state, true); - UndefBranches.insert(N); + //ExplodedNode* N = builder.generateNode(builder.begin(), state, true); + // FIXME: add checker visit. + // UndefBranches.insert(N); return; } @@ -918,8 +964,10 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { SVal CondV_untested = state->getSVal(CondE); if (CondV_untested.isUndef()) { - ExplodedNode* N = builder.generateDefaultCaseNode(state, true); - UndefBranches.insert(N); + //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); + // FIXME: add checker + //UndefBranches.insert(N); + return; } DefinedOrUnknownSVal CondV = cast(CondV_untested); @@ -1052,6 +1100,22 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, // Transfer functions: Loads and stores. //===----------------------------------------------------------------------===// +void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + ExplodedNodeSet Tmp; + + CanQualType T = getContext().getCanonicalType(BE->getType()); + SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T, + Pred->getLocationContext()); + + MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V), + ProgramPoint::PostLValueKind); + + // Post-visit the BlockExpr. + CheckerVisit(BE, Dst, Tmp, false); +} + void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { @@ -1278,7 +1342,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, bool isLoad) { - + // Early checks for performance reason. if (location.isUnknown() || Checkers.empty()) { Dst.Add(Pred); return; @@ -1298,9 +1362,13 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state, + NI != NE; ++NI) { + // Use the 'state' argument only when the predecessor node is the + // same as Pred. This allows us to catch updates to the state. + checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, + *NI == Pred ? state : GetState(*NI), location, tag, isLoad); + } // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -1850,197 +1918,89 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - // FIXME: More logic for the processing the method call. - - const GRState* state = GetState(Pred); - bool RaisesException = false; - - - if (Expr* Receiver = ME->getReceiver()) { - - SVal L_untested = state->getSVal(Receiver); - - // Check for undefined control-flow. - if (L_untested.isUndef()) { - ExplodedNode* N = Builder->generateNode(ME, state, Pred); - - if (N) { - N->markAsSink(); - UndefReceivers.insert(N); - } - - return; - } - - // "Assume" that the receiver is not NULL. - DefinedOrUnknownSVal L = cast(L_untested); - const GRState *StNotNull = state->Assume(L, true); - - // "Assume" that the receiver is NULL. - const GRState *StNull = state->Assume(L, false); - - if (StNull) { - QualType RetTy = ME->getType(); - - // Check if the receiver was nil and the return value a struct. - if (RetTy->isRecordType()) { - if (Pred->getParentMap().isConsumedExpr(ME)) { - // The [0 ...] expressions will return garbage. Flag either an - // explicit or implicit error. Because of the structure of this - // function we currently do not bifurfacte the state graph at - // this point. - // FIXME: We should bifurcate and fill the returned struct with - // garbage. - if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { - N->markAsSink(); - if (StNotNull) - NilReceiverStructRetImplicit.insert(N); - else - NilReceiverStructRetExplicit.insert(N); - } - } - } - else { - ASTContext& Ctx = getContext(); - if (RetTy != Ctx.VoidTy) { - if (Pred->getParentMap().isConsumedExpr(ME)) { - // sizeof(void *) - const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); - // sizeof(return type) - const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType()); - - if (voidPtrSize < returnTypeSize) { - if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) { - N->markAsSink(); - if (StNotNull) - NilReceiverLargerThanVoidPtrRetImplicit.insert(N); - else - NilReceiverLargerThanVoidPtrRetExplicit.insert(N); - } - } - else if (!StNotNull) { - // Handle the safe cases where the return value is 0 if the - // receiver is nil. - // - // FIXME: For now take the conservative approach that we only - // return null values if we *know* that the receiver is nil. - // This is because we can have surprises like: - // - // ... = [[NSScreens screens] objectAtIndex:0]; - // - // What can happen is that [... screens] could return nil, but - // it most likely isn't nil. We should assume the semantics - // of this case unless we have *a lot* more knowledge. - // - SVal V = ValMgr.makeZeroVal(ME->getType()); - MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V)); - return; - } - } - } - } - // We have handled the cases where the receiver is nil. The remainder - // of this method should assume that the receiver is not nil. - if (!StNotNull) - return; - - state = StNotNull; - } - - // Check if the "raise" message was sent. - if (ME->getSelector() == RaiseSel) - RaisesException = true; + // Handle previsits checks. + ExplodedNodeSet Src, DstTmp; + Src.Add(Pred); + + if (CheckerVisit(ME, DstTmp, Src, true)) { + Dst.insert(DstTmp); + return; } - else { - - IdentifierInfo* ClsName = ME->getClassName(); - Selector S = ME->getSelector(); - - // Check for special instance methods. + + unsigned size = Dst.size(); - if (!NSExceptionII) { - ASTContext& Ctx = getContext(); + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); + DI!=DE; ++DI) { + Pred = *DI; + bool RaisesException = false; - NSExceptionII = &Ctx.Idents.get("NSException"); + if (ME->getReceiver()) { + // Check if the "raise" message was sent. + if (ME->getSelector() == RaiseSel) + RaisesException = true; } + else { - if (ClsName == NSExceptionII) { - - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. + IdentifierInfo* ClsName = ME->getClassName(); + Selector S = ME->getSelector(); - if (!NSExceptionInstanceRaiseSelectors) { + // Check for special instance methods. + if (!NSExceptionII) { ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; + NSExceptionII = &Ctx.Idents.get("NSException"); + } - llvm::SmallVector II; - unsigned idx = 0; + if (ClsName == NSExceptionII) { - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); + enum { NUM_RAISE_SELECTORS = 2 }; - // raise:format::arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - } + // Lazily create a cache of the selectors. - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; break; - } - } - } + if (!NSExceptionInstanceRaiseSelectors) { - // Check for any arguments that are uninitialized/undefined. + ASTContext& Ctx = getContext(); - for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end(); - I != E; ++I) { + NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; - if (state->getSVal(*I).isUndef()) { + llvm::SmallVector II; + unsigned idx = 0; - // Generate an error node for passing an uninitialized/undefined value - // as an argument to a message expression. This node is a sink. - ExplodedNode* N = Builder->generateNode(ME, state, Pred); + // raise:format: + II.push_back(&Ctx.Idents.get("raise")); + II.push_back(&Ctx.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); - if (N) { - N->markAsSink(); - MsgExprUndefArgs[N] = *I; - } + // raise:format::arguments: + II.push_back(&Ctx.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + } - return; + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) + if (S == NSExceptionInstanceRaiseSelectors[i]) { + RaisesException = true; break; + } + } } - } - // Handle previsits checks. - ExplodedNodeSet Src, DstTmp; - Src.Add(Pred); - CheckerVisit(ME, DstTmp, Src, true); - - // Check if we raise an exception. For now treat these as sinks. Eventually - // we will want to handle exceptions properly. - SaveAndRestore OldSink(Builder->BuildSinks); - if (RaisesException) - Builder->BuildSinks = true; + // Check if we raise an exception. For now treat these as sinks. Eventually + // we will want to handle exceptions properly. + SaveAndRestore OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - unsigned size = Dst.size(); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI!=DE; ++DI) - EvalObjCMessageExpr(Dst, ME, *DI); + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred); + } // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - MakeNode(Dst, ME, Pred, state); + MakeNode(Dst, ME, Pred, GetState(Pred)); } //===----------------------------------------------------------------------===// @@ -2157,7 +2117,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, namespace { // This class is used by VisitInitListExpr as an item in a worklist // for processing the values contained in an InitListExpr. -class VISIBILITY_HIDDEN InitListWLItem { +class InitListWLItem { public: llvm::ImmutableList Vals; ExplodedNode* N; @@ -2246,8 +2206,6 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, return; } - - printf("InitListExpr type = %s\n", T.getAsString().c_str()); assert(0 && "unprocessed InitListExpr type"); } @@ -2689,6 +2647,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, else Visit(LHS, Pred, Tmp1); + ExplodedNodeSet Tmp3; + for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { SVal LeftV = (*I1)->getState()->getSVal(LHS); ExplodedNodeSet Tmp2; @@ -2723,7 +2683,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); + EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); continue; } @@ -2735,28 +2695,17 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, if (Result.isUnknown()) { if (OldSt != state) { // Generate a new node if we have already created a new state. - MakeNode(Dst, B, *I2, state); + MakeNode(Tmp3, B, *I2, state); } else - Dst.Add(*I2); + Tmp3.Add(*I2); continue; } state = state->BindExpr(B, Result); - if (Result.isUndef()) { - // The operands were *not* undefined, but the result is undefined. - // This is a special node that should be flagged as an error. - if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){ - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; - } - - // Otherwise, create a new node. - MakeNode(Dst, B, *I2, state); + MakeNode(Tmp3, B, *I2, state); continue; } @@ -2809,15 +2758,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, RightV, CTy), state, B->getType(), CTy); - if (Result.isUndef()) { - // The operands were not undefined, but the result is undefined. - if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) { - UndefNode->markAsSink(); - UndefResults.insert(UndefNode); - } - continue; - } - // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. @@ -2844,11 +2784,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); } - EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result), + EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result), location, LHSVal); } } } + + CheckerVisit(B, Dst, Tmp3, false); } //===----------------------------------------------------------------------===// @@ -2870,8 +2812,11 @@ static SourceManager* GraphPrintSourceManager; namespace llvm { template<> -struct VISIBILITY_HIDDEN DOTGraphTraits : +struct DOTGraphTraits : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not // work. static std::string getNodeAttributes(const ExplodedNode* N, void*) { @@ -2888,15 +2833,14 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : GraphPrintCheckerState->isBadCall(N) || GraphPrintCheckerState->isUndefArg(N)) return "color=\"red\",style=\"filled\""; -#endif if (GraphPrintCheckerState->isNoReturnCall(N)) return "color=\"blue\",style=\"filled\""; - +#endif return ""; } - static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){ + static std::string getNodeLabel(const ExplodedNode* N, void*){ std::string sbuf; llvm::raw_string_ostream Out(sbuf); diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp index 2fb7e9f..33479b0 100644 --- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp +++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp @@ -31,6 +31,8 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { // Note that this must be registered after ReturnStackAddresEngsChecker. RegisterReturnPointerRangeChecker(Eng); + + RegisterFixedAddressChecker(Eng); RegisterPointerSubChecker(Eng); RegisterPointerArithChecker(Eng); RegisterCastToStructChecker(Eng); diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp deleted file mode 100644 index d0f60fd..0000000 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ /dev/null @@ -1,400 +0,0 @@ -//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- C++ -*-= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the BugType classes used by GRExprEngine to report -// bugs derived from builtin checks in the path-sensitive engine. -// -//===----------------------------------------------------------------------===// - -#include "GRExprEngineInternalChecks.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::bugreporter; - -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -template inline -ExplodedNode* GetNode(ITERATOR I) { - return *I; -} - -template <> inline -ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { - return I->first; -} - -//===----------------------------------------------------------------------===// -// Bug Descriptions. -//===----------------------------------------------------------------------===// -namespace clang { -class BuiltinBugReport : public RangedBugReport { -public: - BuiltinBugReport(BugType& bt, const char* desc, - ExplodedNode *n) - : RangedBugReport(bt, desc, n) {} - - BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n) - : RangedBugReport(bt, shortDesc, desc, n) {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N); -}; - -void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) { - static_cast(getBugType()).registerInitialVisitors(BRC, N, this); -} - -template -void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { - for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(), - GetNode(I))); -} - -class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug { -public: - NilReceiverStructRet(GRExprEngine* eng) : - BuiltinBug(eng, "'nil' receiver with struct return type") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::nil_receiver_struct_ret_iterator - I=Eng.nil_receiver_struct_ret_begin(), - E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) { - - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - PostStmt P = cast((*I)->getLocation()); - const ObjCMessageExpr *ME = cast(P.getStmt()); - os << "The receiver in the message expression is 'nil' and results in the" - " returned value (of type '" - << ME->getType().getAsString() - << "') to be garbage or otherwise undefined"; - - BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); - R->addRange(ME->getReceiver()->getSourceRange()); - BR.EmitReport(R); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug { -public: - NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) : - BuiltinBug(eng, - "'nil' receiver with return type larger than sizeof(void *)") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator - I=Eng.nil_receiver_larger_than_voidptr_ret_begin(), - E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) { - - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - PostStmt P = cast((*I)->getLocation()); - const ObjCMessageExpr *ME = cast(P.getStmt()); - os << "The receiver in the message expression is 'nil' and results in the" - " returned value (of type '" - << ME->getType().getAsString() - << "' and of size " - << Eng.getContext().getTypeSize(ME->getType()) / 8 - << " bytes) to be garbage or otherwise undefined"; - - BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I); - R->addRange(ME->getReceiver()->getSourceRange()); - BR.EmitReport(R); - } - } - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN UndefResult : public BuiltinBug { -public: - UndefResult(GRExprEngine* eng) - : BuiltinBug(eng,"Undefined or garbage result", - "Result of operation is garbage or undefined") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(), - E = Eng.undef_results_end(); I!=E; ++I) { - - ExplodedNode *N = *I; - const Stmt *S = N->getLocationAs()->getStmt(); - BuiltinBugReport *report = NULL; - - if (const BinaryOperator *B = dyn_cast(S)) { - llvm::SmallString<256> sbuf; - llvm::raw_svector_ostream OS(sbuf); - const GRState *ST = N->getState(); - const Expr *Ex = NULL; - bool isLeft = true; - - if (ST->getSVal(B->getLHS()).isUndef()) { - Ex = B->getLHS()->IgnoreParenCasts(); - isLeft = true; - } - else if (ST->getSVal(B->getRHS()).isUndef()) { - Ex = B->getRHS()->IgnoreParenCasts(); - isLeft = false; - } - - if (Ex) { - OS << "The " << (isLeft ? "left" : "right") - << " operand of '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' is a garbage value"; - } - else { - // Neither operand was undefined, but the result is undefined. - OS << "The result of the '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' expression is undefined"; - } - - // FIXME: Use StringRefs to pass string information. - report = new BuiltinBugReport(*this, OS.str().str().c_str(), N); - if (Ex) report->addRange(Ex->getSourceRange()); - } - else { - report = new BuiltinBugReport(*this, - "Expression evaluates to an uninitialized" - " or undefined value", N); - } - - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - - const Stmt *S = N->getLocationAs()->getStmt(); - const Stmt *X = S; - - if (const BinaryOperator *B = dyn_cast(S)) { - const GRState *ST = N->getState(); - if (ST->getSVal(B->getLHS()).isUndef()) - X = B->getLHS(); - else if (ST->getSVal(B->getRHS()).isUndef()) - X = B->getRHS(); - } - - registerTrackNullOrUndefValue(BRC, X, N); - } -}; - -class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport { - const Stmt *Arg; -public: - ArgReport(BugType& bt, const char* desc, ExplodedNode *n, - const Stmt *arg) - : BuiltinBugReport(bt, desc, n), Arg(arg) {} - - ArgReport(BugType& bt, const char *shortDesc, const char *desc, - ExplodedNode *n, const Stmt *arg) - : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {} - - const Stmt *getArg() const { return Arg; } -}; - -class VISIBILITY_HIDDEN BadArg : public BuiltinBug { -public: - BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument", - "Pass-by-value argument in function call is undefined") {} - - BadArg(GRExprEngine* eng, const char* d) - : BuiltinBug(eng,"Uninitialized argument", d) {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), - N); - } -}; - -class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg { -public: - BadMsgExprArg(GRExprEngine* eng) - : BadArg(eng,"Pass-by-value argument in message expression is undefined"){} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(), - E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) { - // Generate a report for this bug. - ArgReport *report = new ArgReport(*this, desc.c_str(), I->first, - I->second); - report->addRange(I->second->getSourceRange()); - BR.EmitReport(report); - } - } -}; - -class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug { -public: - BadReceiver(GRExprEngine* eng) - : BuiltinBug(eng,"Uninitialized receiver", - "Receiver in message expression is an uninitialized value") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(), - End = Eng.undef_receivers_end(); I!=End; ++I) { - - // Generate a report for this bug. - BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I); - ExplodedNode* N = *I; - const Stmt *S = cast(N->getLocation()).getStmt(); - const Expr* E = cast(S)->getReceiver(); - assert (E && "Receiver cannot be NULL"); - report->addRange(E->getSourceRange()); - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug { - struct VISIBILITY_HIDDEN FindUndefExpr { - GRStateManager& VM; - const GRState* St; - - FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} - - Expr* FindExpr(Expr* Ex) { - if (!MatchesCriteria(Ex)) - return 0; - - for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I) - if (Expr* ExI = dyn_cast_or_null(*I)) { - Expr* E2 = FindExpr(ExI); - if (E2) return E2; - } - - return Ex; - } - - bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); } - }; - -public: - UndefBranch(GRExprEngine *eng) - : BuiltinBug(eng,"Use of garbage value", - "Branch condition evaluates to an undefined or garbage value") - {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(), - E=Eng.undef_branches_end(); I!=E; ++I) { - - // What's going on here: we want to highlight the subexpression of the - // condition that is the most likely source of the "uninitialized - // branch condition." We do a recursive walk of the condition's - // subexpressions and roughly look for the most nested subexpression - // that binds to Undefined. We then highlight that expression's range. - BlockEdge B = cast((*I)->getLocation()); - Expr* Ex = cast(B.getSrc()->getTerminatorCondition()); - assert (Ex && "Block must have a terminator."); - - // Get the predecessor node and check if is a PostStmt with the Stmt - // being the terminator condition. We want to inspect the state - // of that node instead because it will contain main information about - // the subexpressions. - assert (!(*I)->pred_empty()); - - // Note: any predecessor will do. They should have identical state, - // since all the BlockEdge did was act as an error sink since the value - // had to already be undefined. - ExplodedNode *N = *(*I)->pred_begin(); - ProgramPoint P = N->getLocation(); - const GRState* St = (*I)->getState(); - - if (PostStmt* PS = dyn_cast(&P)) - if (PS->getStmt() == Ex) - St = N->getState(); - - FindUndefExpr FindIt(Eng.getStateManager(), St); - Ex = FindIt.FindExpr(Ex); - - ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex); - R->addRange(Ex->getSourceRange()); - BR.EmitReport(R); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast(R)->getArg(), - N); - } -}; - -} // end clang namespace - -//===----------------------------------------------------------------------===// -// Check registration. -//===----------------------------------------------------------------------===// - -void GRExprEngine::RegisterInternalChecks() { - // Register internal "built-in" BugTypes with the BugReporter. These BugTypes - // are different than what probably many checks will do since they don't - // create BugReports on-the-fly but instead wait until GRExprEngine finishes - // analyzing a function. Generation of BugReport objects is done via a call - // to 'FlushReports' from BugReporter. - BR.Register(new UndefBranch(this)); - BR.Register(new UndefResult(this)); - BR.Register(new BadMsgExprArg(this)); - BR.Register(new BadReceiver(this)); - BR.Register(new NilReceiverStructRet(this)); - BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); - - // The following checks do not need to have their associated BugTypes - // explicitly registered with the BugReporter. If they issue any BugReports, - // their associated BugType will get registered with the BugReporter - // automatically. Note that the check itself is owned by the GRExprEngine - // object. - registerCheck(new UndefinedAssignmentChecker()); - - RegisterAttrNonNullChecker(*this); - RegisterUndefinedArgChecker(*this); - RegisterBadCallChecker(*this); - RegisterDereferenceChecker(*this); - RegisterVLASizeChecker(*this); - RegisterDivZeroChecker(*this); - RegisterReturnStackAddressChecker(*this); - RegisterReturnUndefChecker(*this); - RegisterFixedAddressChecker(*this); - RegisterUndefinedArraySubscriptChecker(*this); -} diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h index a9077bf..5b7a757 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.h +++ b/lib/Analysis/GRExprEngineInternalChecks.h @@ -20,7 +20,6 @@ namespace clang { class GRExprEngine; void RegisterAttrNonNullChecker(GRExprEngine &Eng); -void RegisterBadCallChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); @@ -31,9 +30,12 @@ void RegisterPointerSubChecker(GRExprEngine &Eng); void RegisterPointerArithChecker(GRExprEngine &Eng); void RegisterFixedAddressChecker(GRExprEngine &Eng); void RegisterCastToStructChecker(GRExprEngine &Eng); -void RegisterUndefinedArgChecker(GRExprEngine &Eng); +void RegisterCallAndMessageChecker(GRExprEngine &Eng); void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); +void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); +void RegisterUndefBranchChecker(GRExprEngine &Eng); +void RegisterUndefResultChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 23ee0b2..a56859d 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -232,7 +232,7 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){ //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor { +class ScanReachableSymbols : public SubRegionMap::Visitor { typedef llvm::DenseSet VisitedRegionsTy; VisitedRegionsTy visited; @@ -308,6 +308,27 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const { return S.scan(val); } +bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const { + ScanReachableSymbols S(this, visitor); + for ( ; I != E; ++I) { + if (S.scan(*I)) + return true; + } + return false; +} + +bool GRState::scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const { + ScanReachableSymbols S(this, visitor); + for ( ; I != E; ++I) { + if (S.scan(*I)) + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // Queries. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 2510445..84e268f 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -19,9 +19,9 @@ #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" #include "clang/Analysis/Support/SaveAndRestore.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -38,7 +38,7 @@ static const bool Dead = false; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN RegisterDecls +class RegisterDecls : public CFGRecStmtDeclVisitor { LiveVariables::AnalysisDataTy& AD; @@ -77,10 +77,12 @@ public: }; } // end anonymous namespace -LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) { +LiveVariables::LiveVariables(AnalysisContext &AC) { // Register all referenced VarDecls. + CFG &cfg = *AC.getCFG(); getAnalysisData().setCFG(cfg); - getAnalysisData().setContext(Ctx); + getAnalysisData().setContext(AC.getASTContext()); + getAnalysisData().AC = &AC; RegisterDecls R(getAnalysisData()); cfg.VisitBlockStmts(R); @@ -92,7 +94,7 @@ LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) { namespace { -class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor{ +class TransferFuncs : public CFGRecStmtVisitor{ LiveVariables::AnalysisDataTy& AD; LiveVariables::ValTy LiveState; public: @@ -103,6 +105,7 @@ public: void VisitDeclRefExpr(DeclRefExpr* DR); void VisitBinaryOperator(BinaryOperator* B); + void VisitBlockExpr(BlockExpr *B); void VisitAssign(BinaryOperator* B); void VisitDeclStmt(DeclStmt* DS); void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); @@ -153,7 +156,17 @@ void TransferFuncs::VisitTerminator(CFGBlock* B) { void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { if (VarDecl* V = dyn_cast(DR->getDecl())) - LiveState(V,AD) = Alive; + LiveState(V, AD) = Alive; +} + +void TransferFuncs::VisitBlockExpr(BlockExpr *BE) { + AnalysisContext::referenced_decls_iterator I, E; + llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl()); + for ( ; I != E ; ++I) { + DeclBitVector_Types::Idx i = AD.getIdx(*I); + if (i.isValid()) + LiveState.getBit(i) = Alive; + } } void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 93e7083..204c7b3 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -46,9 +46,9 @@ struct RefState { } }; -class VISIBILITY_HIDDEN RegionState {}; +class RegionState {}; -class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor { +class MallocChecker : public CheckerVisitor { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; IdentifierInfo *II_malloc; @@ -65,7 +65,7 @@ private: void MallocMem(CheckerContext &C, const CallExpr *CE); void FreeMem(CheckerContext &C, const CallExpr *CE); }; -} +} // end anonymous namespace namespace clang { template <> @@ -112,9 +112,7 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { SymbolRef Sym = CallVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - const GRState *AllocState - = state->set(Sym, RefState::getAllocated(CE)); - C.addTransition(C.GenerateNode(CE, AllocState)); + C.addTransition(state->set(Sym, RefState::getAllocated(CE))); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { @@ -128,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Check double free. if (RS->isReleased()) { - ExplodedNode *N = C.GenerateNode(CE, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_DoubleFree) BT_DoubleFree = new BuiltinBug("Double free", @@ -144,7 +142,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { // Normal free. const GRState *FreedState = state->set(Sym, RefState::getReleased(CE)); - C.addTransition(C.GenerateNode(CE, FreedState)); + C.addTransition(FreedState); } void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, @@ -158,7 +156,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, return; if (RS->isAllocated()) { - ExplodedNode *N = C.GenerateNode(S, true); + ExplodedNode *N = C.GenerateSink(); if (N) { if (!BT_Leak) BT_Leak = new BuiltinBug("Memory leak", @@ -173,6 +171,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) { + SaveAndRestore OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); typedef llvm::ImmutableMap SymMap; SymMap M = state->get(); @@ -212,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { if (RS->isAllocated()) state = state->set(Sym, RefState::getEscaped(S)); - ExplodedNode *N = C.GenerateNode(S, state); - if (N) - C.addTransition(N); + C.addTransition(state); } diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 8c0b85c..af8bd16 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -17,15 +17,25 @@ #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/ValueManager.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/AST/StmtVisitor.h" using namespace clang; //===----------------------------------------------------------------------===// -// Basic methods. +// Object destruction. //===----------------------------------------------------------------------===// MemRegion::~MemRegion() {} +MemRegionManager::~MemRegionManager() { + // All regions and their data are BumpPtrAllocated. No need to call + // their destructors. +} + +//===----------------------------------------------------------------------===// +// Basic methods. +//===----------------------------------------------------------------------===// + bool SubRegion::isSubRegionOf(const MemRegion* R) const { const MemRegion* r = getSuperRegion(); while (r != 0) { @@ -126,15 +136,39 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const { ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion); } -void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const FunctionDecl *FD, - const MemRegion*) { - ID.AddInteger(MemRegion::CodeTextRegionKind); +void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const FunctionDecl *FD, + const MemRegion*) { + ID.AddInteger(MemRegion::FunctionTextRegionKind); ID.AddPointer(FD); } -void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { - CodeTextRegion::ProfileRegion(ID, FD, superRegion); +void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { + FunctionTextRegion::ProfileRegion(ID, FD, superRegion); +} + +void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockDecl *BD, CanQualType, + const MemRegion*) { + ID.AddInteger(MemRegion::BlockTextRegionKind); + ID.AddPointer(BD); +} + +void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { + BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion); +} + +void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockTextRegion *BC, + const LocationContext *LC, + const MemRegion *) { + ID.AddInteger(MemRegion::BlockDataRegionKind); + ID.AddPointer(BC); + ID.AddPointer(LC); +} + +void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { + BlockDataRegion::ProfileRegion(ID, BC, LC, NULL); } //===----------------------------------------------------------------------===// @@ -160,10 +194,19 @@ void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const { os << "alloca{" << (void*) Ex << ',' << Cnt << '}'; } -void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const { +void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const { os << "code{" << getDecl()->getDeclName().getAsString() << '}'; } +void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "block_code{" << (void*) this << '}'; +} + +void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const { + os << "block_data{" << BC << '}'; +} + + void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { // FIXME: More elaborate pretty-printing. os << "{ " << (void*) CL << " }"; @@ -259,6 +302,18 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, return getRegion(D, LC); } +BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, + const LocationContext *LC) +{ + // FIXME: Once we implement scope handling, we will need to properly lookup + // 'D' to the proper LocationContext. For now, just strip down to the + // StackFrame. + while (!isa(LC)) + LC = LC->getParent(); + + return getSubRegion(BC, LC, getStackRegion()); +} + CompoundLiteralRegion* MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) { return getRegion(CL); @@ -287,10 +342,17 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, return R; } -CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) { - return getRegion(FD); +FunctionTextRegion * +MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) { + return getRegion(FD); +} + +BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy) { + return getRegion(BD, locTy); } + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) { return getRegion(sym); @@ -473,3 +535,53 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { return RegionRawOffset(superR, offset); } +//===----------------------------------------------------------------------===// +// BlockDataRegion +//===----------------------------------------------------------------------===// + +void BlockDataRegion::LazyInitializeReferencedVars() { + if (ReferencedVars) + return; + + AnalysisContext *AC = LC->getAnalysisContext(); + AnalysisContext::referenced_decls_iterator I, E; + llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); + + if (I == E) { + ReferencedVars = (void*) 0x1; + return; + } + + MemRegionManager &MemMgr = *getMemRegionManager(); + llvm::BumpPtrAllocator &A = MemMgr.getAllocator(); + BumpVectorContext BC(A); + + typedef BumpVector VarVec; + VarVec *BV = (VarVec*) A.Allocate(); + new (BV) VarVec(BC, (E - I) / sizeof(*I)); + + for ( ; I != E; ++I) + BV->push_back(MemMgr.getVarRegion(*I, LC), BC); + + ReferencedVars = BV; +} + +BlockDataRegion::referenced_vars_iterator +BlockDataRegion::referenced_vars_begin() const { + const_cast(this)->LazyInitializeReferencedVars(); + + BumpVector *Vec = + static_cast*>(ReferencedVars); + + return Vec == (void*) 0x1 ? NULL : Vec->begin(); +} + +BlockDataRegion::referenced_vars_iterator +BlockDataRegion::referenced_vars_end() const { + const_cast(this)->LazyInitializeReferencedVars(); + + BumpVector *Vec = + static_cast*>(ReferencedVars); + + return Vec == (void*) 0x1 ? NULL : Vec->end(); +} diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp index e0a8d0d..2ff0487 100644 --- a/lib/Analysis/NSAutoreleasePoolChecker.cpp +++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp @@ -19,14 +19,13 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "BasicObjCFoundationChecks.h" -#include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN NSAutoreleasePoolChecker +class NSAutoreleasePoolChecker : public CheckerVisitor { Selector releaseS; @@ -65,6 +64,9 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, // the type of the expression. const ObjCObjectPointerType* PT = receiver->getType()->getAs(); + + if (!PT) + return; const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); if (!OD) return; diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp index 93b617b..e3cf57f 100644 --- a/lib/Analysis/NSErrorChecker.cpp +++ b/lib/Analysis/NSErrorChecker.cpp @@ -20,7 +20,6 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" -#include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" @@ -28,7 +27,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN NSErrorChecker : public BugType { +class NSErrorChecker : public BugType { const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; @@ -117,7 +116,7 @@ void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { BR.EmitBasicReport(isNSErrorWarning ? "Bad return type when passing NSError**" : "Bad return type when passing CFError*", - getCategory().c_str(), os.str().c_str(), + getCategory(), os.str(), CodeDecl.getLocation()); } @@ -229,7 +228,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, os << Param->getNameAsString() << "' may be null."; - BugReport *report = new BugReport(*this, os.str().c_str(), *I); + BugReport *report = new BugReport(*this, os.str(), *I); // FIXME: Notable symbols are now part of the report. We should // add support for notable symbols in BugReport. // BR.addNotableSymbol(SV->getSymbol()); diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp index 9382348..370233c 100644 --- a/lib/Analysis/PointerArithChecker.cpp +++ b/lib/Analysis/PointerArithChecker.cpp @@ -18,7 +18,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PointerArithChecker +class PointerArithChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa(LR) || isa(LR) || isa(LR)) { - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Dangerous pointer arithmetic", "Pointer arithmetic done on non-array variables " diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp index 4c7906f..c597a25 100644 --- a/lib/Analysis/PointerSubChecker.cpp +++ b/lib/Analysis/PointerSubChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PointerSubChecker +class PointerSubChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, if (isa(BaseLR) || isa(BaseRR)) return; - if (ExplodedNode *N = C.GenerateNode(B)) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Pointer subtraction", "Subtraction of two pointers that do not point to " diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp index 6620661..e95095c 100644 --- a/lib/Analysis/PthreadLockChecker.cpp +++ b/lib/Analysis/PthreadLockChecker.cpp @@ -21,7 +21,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN PthreadLockChecker +class PthreadLockChecker : public CheckerVisitor { BugType *BT; public: @@ -42,7 +42,7 @@ public: } // end anonymous namespace // GDM Entry for tracking lock state. -namespace { class VISIBILITY_HIDDEN LockSet {}; } +namespace { class LockSet {}; } namespace clang { template <> struct GRStateTrait : public GRStatePartialTrait > { @@ -59,8 +59,8 @@ void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); - const CodeTextRegion *R = - dyn_cast_or_null(state->getSVal(Callee).getAsRegion()); + const FunctionTextRegion *R = + dyn_cast_or_null(state->getSVal(Callee).getAsRegion()); if (!R) return; diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index f5cae69..7330b62 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -17,7 +17,6 @@ #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Analysis/ManagerRegistry.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableSet.h" @@ -25,14 +24,14 @@ using namespace clang; -namespace { class VISIBILITY_HIDDEN ConstraintRange {}; } +namespace { class ConstraintRange {}; } static int ConstraintRangeIndex = 0; /// A Range represents the closed range [from, to]. The caller must /// guarantee that from <= to. Note that Range is immutable, so as not /// to subvert RangeSet's immutability. namespace { -class VISIBILITY_HIDDEN Range : public std::pair { public: Range(const llvm::APSInt &from, const llvm::APSInt &to) @@ -59,7 +58,7 @@ public: }; -class VISIBILITY_HIDDEN RangeTrait : public llvm::ImutContainerInfo { +class RangeTrait : public llvm::ImutContainerInfo { public: // When comparing if one Range is less than another, we should compare // the actual APSInt values instead of their pointers. This keeps the order @@ -74,7 +73,7 @@ public: /// RangeSet contains a set of ranges. If the set is empty, then /// there the value of a symbol is overly constrained and there are no /// possible values for that symbol. -class VISIBILITY_HIDDEN RangeSet { +class RangeSet { typedef llvm::ImmutableSet PrimRangeSet; PrimRangeSet ranges; // no need to make const, since it is an // ImmutableSet - this allows default operator= @@ -232,7 +231,7 @@ struct GRStateTrait } namespace { -class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{ +class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(const GRState *state, SymbolRef sym); public: RangeConstraintManager() {} diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index ae3fa14..e645172 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -25,7 +25,6 @@ #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Compiler.h" using namespace clang; @@ -86,10 +85,10 @@ typedef llvm::ImmutableMap RegionBindings; //===----------------------------------------------------------------------===// namespace { -struct VISIBILITY_HIDDEN minimal_features_tag {}; -struct VISIBILITY_HIDDEN maximal_features_tag {}; +struct minimal_features_tag {}; +struct maximal_features_tag {}; -class VISIBILITY_HIDDEN RegionStoreFeatures { +class RegionStoreFeatures { bool SupportsFields; bool SupportsRemaining; @@ -114,7 +113,7 @@ public: // MemRegions represent chunks of memory with a size (their "extent"). This // GDM entry tracks the extents for regions. Extents are in bytes. // -namespace { class VISIBILITY_HIDDEN RegionExtents {}; } +namespace { class RegionExtents {}; } static int RegionExtentsIndex = 0; namespace clang { template<> struct GRStateTrait @@ -141,7 +140,7 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) { namespace { -class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap { +class RegionStoreSubRegionMap : public SubRegionMap { typedef llvm::ImmutableSet SetTy; typedef llvm::DenseMap Map; SetTy::Factory F; @@ -188,7 +187,7 @@ public: } }; -class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager { +class RegionStoreManager : public StoreManager { const RegionStoreFeatures Features; RegionBindings::Factory RBFactory; @@ -215,6 +214,13 @@ public: /// getDefaultBinding - Returns an SVal* representing an optional default /// binding associated with a region and its subregions. Optional getDefaultBinding(RegionBindings B, const MemRegion *R); + + /// setImplicitDefaultValue - Set the default binding for the provided + /// MemRegion to the value implicitly defined for compound literals when + /// the value is not specified. + const GRState *setImplicitDefaultValue(const GRState *state, + const MemRegion *R, + QualType T); /// getLValueString - Returns an SVal representing the lvalue of a /// StringLiteral. Within RegionStore a StringLiteral has an @@ -705,7 +711,9 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); - case MemRegion::CodeTextRegionKind: + case MemRegion::FunctionTextRegionKind: + case MemRegion::BlockTextRegionKind: + case MemRegion::BlockDataRegionKind: // Technically this can happen if people do funny things with casts. return UnknownVal(); @@ -850,7 +858,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, case MemRegion::ObjCIvarRegionKind: return UnknownVal(); - case MemRegion::CodeTextRegionKind: + case MemRegion::FunctionTextRegionKind: + case MemRegion::BlockTextRegionKind: + case MemRegion::BlockDataRegionKind: // Technically this can happen if people do funny things with casts. return UnknownVal(); @@ -1437,6 +1447,30 @@ RegionStoreManager::BindCompoundLiteral(const GRState *state, return Bind(state, loc::MemRegionVal(R), V); } +const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, + const MemRegion *R, + QualType T) { + Store store = state->getStore(); + RegionBindings B = GetRegionBindings(store); + SVal V; + + if (Loc::IsLocType(T)) + V = ValMgr.makeNull(); + else if (T->isIntegerType()) + V = ValMgr.makeZeroVal(T); + else if (T->isStructureType() || 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); + } + else { + return state; + } + + B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + return state->makeWithStore(B.getRoot()); +} + const GRState *RegionStoreManager::BindArray(const GRState *state, const TypedRegion* R, SVal Init) { @@ -1478,6 +1512,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, return CopyLazyBindings(*LCV, state, R); // Remaining case: explicit compound values. + + if (Init.isUnknown()) + return setImplicitDefaultValue(state, R, ElementTy); + nonloc::CompoundVal& CV = cast(Init); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); uint64_t i = 0; @@ -1497,17 +1535,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, state = Bind(state, ValMgr.makeLoc(ER), *VI); } - // If the init list is shorter than the array length, set the array default - // value. - if (i < size) { - if (ElementTy->isIntegerType()) { - SVal V = ValMgr.makeZeroVal(ElementTy); - Store store = state->getStore(); - RegionBindings B = GetRegionBindings(store); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); - state = state->makeWithStore(B.getRoot()); - } - } + // If the init list is shorter than the array length, set the + // array default value. + if (i < size) + state = setImplicitDefaultValue(state, R, ElementTy); return state; } @@ -1619,9 +1650,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, llvm::OwningPtr SubRegions(getRegionStoreSubRegionMap(store)); - // Do a pass over the regions in the store. For VarRegions we check if - // the variable is still live and if so add it to the list of live roots. - // For other regions we populate our region backmap. + // Do a pass over the regions in the store. For VarRegions we check if + // the variable is still live and if so add it to the list of live roots. + // For other regions we populate our region backmap. llvm::SmallVector IntermediateRoots; // Scan the direct bindings for "intermediate" roots. @@ -1719,8 +1750,21 @@ tryAgain: // Mark the symbol for any live SymbolicRegion as "live". This means we // should continue to track that symbol. - if (const SymbolicRegion* SymR = dyn_cast(R)) + if (const SymbolicRegion *SymR = dyn_cast(R)) SymReaper.markLive(SymR->getSymbol()); + + // For BlockDataRegions, enqueue all VarRegions for that are referenced + // via BlockDeclRefExprs. + if (const BlockDataRegion *BD = dyn_cast(R)) { + for (BlockDataRegion::referenced_vars_iterator + RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); + RI != RE; ++RI) + WorkList.push_back(std::make_pair(state_N, *RI)); + + // No possible data bindings on a BlockDataRegion. Continue to the + // next region in the worklist. + continue; + } Store store_N = state_N->getStore(); RegionBindings B_N = GetRegionBindings(store_N); diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp index 44887b2..ab0fcab 100644 --- a/lib/Analysis/ReturnPointerRangeChecker.cpp +++ b/lib/Analysis/ReturnPointerRangeChecker.cpp @@ -20,7 +20,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN ReturnPointerRangeChecker : +class ReturnPointerRangeChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -70,7 +70,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { - ExplodedNode *N = C.GenerateNode(RS, StOutBound, true); + ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; @@ -91,7 +91,6 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - C.EmitReport(report); } } diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp index e4be871..3a6d8a4 100644 --- a/lib/Analysis/ReturnStackAddressChecker.cpp +++ b/lib/Analysis/ReturnStackAddressChecker.cpp @@ -17,12 +17,13 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN ReturnStackAddressChecker : +class ReturnStackAddressChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -53,7 +54,7 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, if (!R || !R->hasStackStorage()) return; - ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; @@ -83,6 +84,14 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, << C.getSourceManager().getInstantiationLineNumber(L) << " returned to caller"; } + else if (const BlockDataRegion *BR = dyn_cast(R)) { + const BlockDecl *BD = BR->getCodeRegion()->getDecl(); + SourceLocation L = BD->getLocStart(); + range = BD->getSourceRange(); + os << "Address of stack-allocated block declared on line " + << C.getSourceManager().getInstantiationLineNumber(L) + << " returned to caller"; + } else { os << "Address of stack memory associated with local variable '" << R->getString() << "' returned."; diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp index 796c760..7cd7126 100644 --- a/lib/Analysis/ReturnUndefChecker.cpp +++ b/lib/Analysis/ReturnUndefChecker.cpp @@ -22,7 +22,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN ReturnUndefChecker : +class ReturnUndefChecker : public CheckerVisitor { BuiltinBug *BT; public: @@ -50,7 +50,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, if (!C.getState()->getSVal(RetE).isUndef()) return; - ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index d5d36e3..9163b27 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -51,7 +51,7 @@ bool SVal::hasConjuredSymbol() const { const FunctionDecl *SVal::getAsFunctionDecl() const { if (const loc::MemRegionVal* X = dyn_cast(this)) { const MemRegion* R = X->getRegion(); - if (const CodeTextRegion *CTR = R->getAs()) + if (const FunctionTextRegion *CTR = R->getAs()) return CTR->getDecl(); } diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 4487aa9..2afcd3e 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -13,12 +13,11 @@ #include "clang/Analysis/PathSensitive/SValuator.h" #include "clang/Analysis/PathSensitive/GRState.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { -class VISIBILITY_HIDDEN SimpleSValuator : public SValuator { +class SimpleSValuator : public SValuator { protected: virtual SVal EvalCastNL(NonLoc val, QualType castTy); virtual SVal EvalCastL(Loc val, QualType castTy); diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 2fd72ac..2fd573c 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -85,7 +85,10 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) assert(0 && "Invalid region cast"); break; } - case MemRegion::CodeTextRegionKind: { + + case MemRegion::FunctionTextRegionKind: + case MemRegion::BlockTextRegionKind: + case MemRegion::BlockDataRegionKind: { // CodeTextRegion should be cast to only a function or block pointer type, // although they can in practice be casted to anything, e.g, void*, char*, // etc. @@ -194,12 +197,11 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, QualType castTy) { - ASTContext &Ctx = ValMgr.getContext(); - if (castTy.isNull()) return V; - assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx))); + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, + R->getValueType(ValMgr.getContext()))); return V; } diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Analysis/UndefBranchChecker.cpp new file mode 100644 index 0000000..c739d1a --- /dev/null +++ b/lib/Analysis/UndefBranchChecker.cpp @@ -0,0 +1,117 @@ +//=== UndefBranchChecker.cpp -----------------------------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines UndefBranchChecker, which checks for undefined branch +// condition. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" + +using namespace clang; + +namespace { + +class UndefBranchChecker : public Checker { + BuiltinBug *BT; + + struct FindUndefExpr { + GRStateManager& VM; + const GRState* St; + + FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} + + Expr* FindExpr(Expr* Ex) { + if (!MatchesCriteria(Ex)) + return 0; + + for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I) + if (Expr* ExI = dyn_cast_or_null(*I)) { + Expr* E2 = FindExpr(ExI); + if (E2) return E2; + } + + return Ex; + } + + bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); } + }; + +public: + UndefBranchChecker() : BT(0) {} + static void *getTag(); + void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, + Stmt *Condition, void *tag); +}; + +} + +void clang::RegisterUndefBranchChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefBranchChecker()); +} + +void *UndefBranchChecker::getTag() { + static int x; + return &x; +} + +void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder, + GRExprEngine &Eng, + Stmt *Condition, void *tag) { + const GRState *state = Builder.getState(); + SVal X = state->getSVal(Condition); + if (X.isUndef()) { + ExplodedNode *N = Builder.generateNode(state, true); + if (N) { + N->markAsSink(); + if (!BT) + BT = new BuiltinBug("Branch condition evaluates to a garbage value"); + + // What's going on here: we want to highlight the subexpression of the + // condition that is the most likely source of the "uninitialized + // branch condition." We do a recursive walk of the condition's + // subexpressions and roughly look for the most nested subexpression + // that binds to Undefined. We then highlight that expression's range. + BlockEdge B = cast(N->getLocation()); + Expr* Ex = cast(B.getSrc()->getTerminatorCondition()); + assert (Ex && "Block must have a terminator."); + + // Get the predecessor node and check if is a PostStmt with the Stmt + // being the terminator condition. We want to inspect the state + // of that node instead because it will contain main information about + // the subexpressions. + assert (!N->pred_empty()); + + // Note: any predecessor will do. They should have identical state, + // since all the BlockEdge did was act as an error sink since the value + // had to already be undefined. + ExplodedNode *PrevN = *N->pred_begin(); + ProgramPoint P = PrevN->getLocation(); + const GRState* St = N->getState(); + + if (PostStmt* PS = dyn_cast(&P)) + if (PS->getStmt() == Ex) + St = PrevN->getState(); + + FindUndefExpr FindIt(Eng.getStateManager(), St); + Ex = FindIt.FindExpr(Ex); + + // Emit the bug report. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + R->addRange(Ex->getSourceRange()); + + Eng.getBugReporter().EmitReport(R); + } + + Builder.markInfeasible(true); + Builder.markInfeasible(false); + } +} diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Analysis/UndefResultChecker.cpp new file mode 100644 index 0000000..acc86dd --- /dev/null +++ b/lib/Analysis/UndefResultChecker.cpp @@ -0,0 +1,86 @@ +//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UndefResultChecker, a builtin check in GRExprEngine that +// performs checks for undefined results of non-assignment binary operators. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +namespace { +class UndefResultChecker + : public CheckerVisitor { + + BugType *BT; + +public: + UndefResultChecker() : BT(0) {} + static void *getTag() { static int tag = 0; return &tag; } + void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; +} // end anonymous namespace + +void clang::RegisterUndefResultChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefResultChecker()); +} + +void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + const GRState *state = C.getState(); + if (state->getSVal(B).isUndef()) { + // Generate an error node. + ExplodedNode *N = C.GenerateSink(); + if (!N) + return; + + if (!BT) + BT = new BuiltinBug("Result of operation is garbage or undefined"); + + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream OS(sbuf); + const Expr *Ex = NULL; + bool isLeft = true; + + if (state->getSVal(B->getLHS()).isUndef()) { + Ex = B->getLHS()->IgnoreParenCasts(); + isLeft = true; + } + else if (state->getSVal(B->getRHS()).isUndef()) { + Ex = B->getRHS()->IgnoreParenCasts(); + isLeft = false; + } + + if (Ex) { + OS << "The " << (isLeft ? "left" : "right") + << " operand of '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' is a garbage value"; + } + else { + // Neither operand was undefined, but the result is undefined. + OS << "The result of the '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' expression is undefined"; + } + EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N); + if (Ex) { + report->addRange(Ex->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + } + else + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B); + C.EmitReport(report); + } +} diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp deleted file mode 100644 index 923a7e1..0000000 --- a/lib/Analysis/UndefinedArgChecker.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===--- UndefinedArgChecker.h - Undefined arguments checker ----*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines BadCallChecker, a builtin check in GRExprEngine that performs -// checks for undefined arguments. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "GRExprEngineInternalChecks.h" - -using namespace clang; - -namespace { -class VISIBILITY_HIDDEN UndefinedArgChecker - : public CheckerVisitor { - BugType *BT; -public: - UndefinedArgChecker() : BT(0) {} - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; -} // end anonymous namespace - -void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) { - Eng.registerCheck(new UndefinedArgChecker()); -} - -void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, - const CallExpr *CE){ - for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - if (C.getState()->getSVal(*I).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BuiltinBug("Pass-by-value argument in function call is " - "undefined"); - // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); - R->addRange((*I)->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); - C.EmitReport(R); - } - } - } -} diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Analysis/UndefinedArraySubscriptChecker.cpp index 887c775..d6aacaf 100644 --- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp +++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp @@ -19,7 +19,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker +class UndefinedArraySubscriptChecker : public CheckerVisitor { BugType *BT; public: @@ -41,7 +41,7 @@ void UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, const ArraySubscriptExpr *A) { if (C.getState()->getSVal(A->getIdx()).isUndef()) { - if (ExplodedNode *N = C.GenerateNode(A, true)) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT) BT = new BuiltinBug("Array subscript is undefined"); diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp index b8062f3..4630b82 100644 --- a/lib/Analysis/UndefinedAssignmentChecker.cpp +++ b/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -12,11 +12,29 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathSensitive/BugReporter.h" using namespace clang; +namespace { +class UndefinedAssignmentChecker + : public CheckerVisitor { + BugType *BT; +public: + UndefinedAssignmentChecker() : BT(0) {} + static void *getTag(); + virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, + const Stmt *StoreE, SVal location, + SVal val); +}; +} + +void clang::RegisterUndefinedAssignmentChecker(GRExprEngine &Eng){ + Eng.registerCheck(new UndefinedAssignmentChecker()); +} + void *UndefinedAssignmentChecker::getTag() { static int x = 0; return &x; @@ -30,7 +48,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, if (!val.isUndef()) return; - ExplodedNode *N = C.GenerateNode(StoreE, true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 8e7b158..6fa4b53 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -17,7 +17,6 @@ #include "clang/Analysis/AnalysisDiagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/SmallPtrSet.h" @@ -29,7 +28,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN RegisterDecls +class RegisterDecls : public CFGRecStmtDeclVisitor { UninitializedValues::AnalysisDataTy& AD; @@ -52,7 +51,7 @@ void UninitializedValues::InitializeValues(const CFG& cfg) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN TransferFuncs +class TransferFuncs : public CFGStmtVisitor { UninitializedValues::ValTy V; @@ -269,7 +268,7 @@ namespace { UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} namespace { -class VISIBILITY_HIDDEN UninitializedValuesChecker +class UninitializedValuesChecker : public UninitializedValues::ObserverTy { ASTContext &Ctx; diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp index 799a73e..2690d6f 100644 --- a/lib/Analysis/VLASizeChecker.cpp +++ b/lib/Analysis/VLASizeChecker.cpp @@ -20,7 +20,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor { +class VLASizeChecker : public CheckerVisitor { BugType *BT_zero; BugType *BT_undef; @@ -55,7 +55,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { if (sizeV.isUndef()) { // Generate an error node. - ExplodedNode *N = C.GenerateNode(DS, true); + ExplodedNode *N = C.GenerateSink(); if (!N) return; @@ -78,7 +78,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD); if (stateZero && !stateNotZero) { - ExplodedNode* N = C.GenerateNode(DS, stateZero, true); + ExplodedNode* N = C.GenerateSink(stateZero); if (!BT_zero) BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero " "size"); @@ -92,6 +92,5 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { } // From this point on, assume that the size is not zero. - if (state != stateNotZero) - C.addTransition(C.GenerateNode(DS, stateNotZero)); + C.addTransition(stateNotZero); } diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp index fe670e7..22a8211 100644 --- a/lib/Analysis/ValueManager.cpp +++ b/lib/Analysis/ValueManager.cpp @@ -138,6 +138,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, } DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) { - CodeTextRegion *R = MemMgr.getCodeTextRegion(FD); + CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD); return loc::MemRegionVal(R); } + +DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D, + CanQualType locTy, + const LocationContext *LC) { + BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy); + BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); + return loc::MemRegionVal(BD); +} + diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index b6c4df8..a1f97f4 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -44,6 +44,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char16Type = UnsignedShort; Char32Type = UnsignedInt; Int64Type = SignedLongLong; + SigAtomicType = SignedInt; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 07c2bb9..e5a4c43 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -313,6 +313,42 @@ public: } }; +// PS3 PPU Target +template +class PS3PPUTargetInfo : public OSTargetInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector &Defs) const { + // PS3 PPU defines. + Define(Defs, "__PPU__", "1"); + Define(Defs, "__CELLOS_LV2__", "1"); + Define(Defs, "__ELF__", "1"); + } +public: + PS3PPUTargetInfo(const std::string& triple) + : OSTargetInfo(triple) { + this->UserLabelPrefix = ""; + } +}; + +// FIXME: Need a real SPU target. +// PS3 SPU Target +template +class PS3SPUTargetInfo : public OSTargetInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector &Defs) const { + // PS3 PPU defines. + Define(Defs, "__SPU__", "1"); + Define(Defs, "__ELF__", "1"); + } +public: + PS3SPUTargetInfo(const std::string& triple) + : OSTargetInfo(triple) { + this->UserLabelPrefix = ""; + } +}; + // AuroraUX target template class AuroraUXTargetInfo : public OSTargetInfo { @@ -445,6 +481,11 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, // FIXME: Should be controlled by command line option. Define(Defs, "__LONG_DOUBLE_128__"); + + if (Opts.AltiVec) { + Define(Defs, "__VEC__", "10206"); + Define(Defs, "__ALTIVEC__", "1"); + } } @@ -1492,6 +1533,7 @@ namespace { UIntMaxType = UnsignedLong; IntPtrType = SignedShort; PtrDiffType = SignedInt; + SigAtomicType = SignedLong; FloatWidth = 32; FloatAlign = 32; DoubleWidth = 32; @@ -1559,6 +1601,7 @@ namespace { UIntMaxType = UnsignedLong; IntPtrType = SignedShort; PtrDiffType = SignedInt; + SigAtomicType = SignedLong; DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16"; } virtual void getTargetDefines(const LangOptions &Opts, @@ -1990,6 +2033,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::ppc64: if (os == llvm::Triple::Darwin) return new DarwinTargetInfo(T); + else if (os == llvm::Triple::Lv2) + return new PS3PPUTargetInfo(T); return new PPC64TargetInfo(T); case llvm::Triple::sparc: @@ -1999,6 +2044,10 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new SolarisSparcV8TargetInfo(T); return new SparcV8TargetInfo(T); + // FIXME: Need a real SPU target. + case llvm::Triple::cellspu: + return new PS3SPUTargetInfo(T); + case llvm::Triple::systemz: return new SystemZTargetInfo(T); diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp index 4afeaf0..8cdc1e3 100644 --- a/lib/Basic/TokenKinds.cpp +++ b/lib/Basic/TokenKinds.cpp @@ -30,59 +30,8 @@ const char *tok::getTokenName(enum TokenKind Kind) { const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) { switch (Kind) { - case tok::l_square: return "["; - case tok::r_square: return "]"; - case tok::l_paren: return "("; - case tok::r_paren: return ")"; - case tok::l_brace: return "{"; - case tok::r_brace: return "}"; - case tok::period: return "."; - case tok::ellipsis: return "..."; - case tok::amp: return "&"; - case tok::ampamp: return "&&"; - case tok::ampequal: return "&="; - case tok::star: return "*"; - case tok::starequal: return "*="; - case tok::plus: return "+"; - case tok::plusplus: return "++"; - case tok::plusequal: return "+="; - case tok::minus: return "-"; - case tok::arrow: return "->"; - case tok::minusminus: return "--"; - case tok::minusequal: return "-="; - case tok::tilde: return "~"; - case tok::exclaim: return "!"; - case tok::exclaimequal: return "!="; - case tok::slash: return "/"; - case tok::slashequal: return "/="; - case tok::percent: return "%"; - case tok::percentequal: return "%="; - case tok::less: return "<"; - case tok::lessless: return "<<"; - case tok::lessequal: return "<="; - case tok::lesslessequal: return "<<="; - case tok::greater: return ">"; - case tok::greatergreater: return ">>"; - case tok::greaterequal: return ">="; - case tok::greatergreaterequal: return ">>="; - case tok::caret: return "^"; - case tok::caretequal: return "^="; - case tok::pipe: return "|"; - case tok::pipepipe: return "||"; - case tok::pipeequal: return "|="; - case tok::question: return "?"; - case tok::colon: return ":"; - case tok::semi: return ";"; - case tok::equal: return "="; - case tok::equalequal: return "=="; - case tok::comma: return ","; - case tok::hash: return "#"; - case tok::hashhash: return "##"; - case tok::hashat: return "#@"; - case tok::periodstar: return ".*"; - case tok::arrowstar: return "->*"; - case tok::coloncolon: return "::"; - case tok::at: return "@"; +#define PUNCTUATOR(X,Y) case X: return Y; +#include "clang/Basic/TokenKinds.def" default: break; } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index bc9eb67..2df779c 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -291,14 +291,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { (VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0); llvm::Value *Loc = LocalDeclMap[VD]; Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc, false); + Loc = Builder.CreateLoad(Loc); Builder.CreateStore(Loc, Addr); ++helpersize; continue; } else E = new (getContext()) DeclRefExpr (cast(VD), - VD->getType(), SourceLocation(), - false, false); + VD->getType(), + SourceLocation()); } if (BDRE->isByRef()) { NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF | @@ -331,7 +331,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { "block.literal"); Ty = llvm::PointerType::get(Ty, 0); Loc = Builder.CreateBitCast(Loc, Ty); - Loc = Builder.CreateLoad(Loc, false); + Loc = Builder.CreateLoad(Loc); // Loc = Builder.CreateBitCast(Loc, Ty); } Builder.CreateStore(Loc, Addr); @@ -494,7 +494,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) { E->arg_begin(), E->arg_end()); // Load the function. - llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp"); + llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); QualType ResultType = FnType->getAs()->getResultType(); @@ -551,9 +551,9 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { const llvm::Type *Ty = PtrStructTy; Ty = llvm::PointerType::get(Ty, 0); V = Builder.CreateBitCast(V, Ty); - V = Builder.CreateLoad(V, false); + V = Builder.CreateLoad(V); V = Builder.CreateStructGEP(V, 1, "forwarding"); - V = Builder.CreateLoad(V, false); + V = Builder.CreateLoad(V); V = Builder.CreateBitCast(V, PtrStructTy); V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), VD->getNameAsString()); @@ -836,7 +836,7 @@ uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { 0, QualType(PadTy), 0, VarDecl::None); Expr *E; E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), - SourceLocation(), false, false); + SourceLocation()); BlockDeclRefDecls.push_back(E); } BlockDeclRefDecls.push_back(BDRE); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 399b873..be4c27c 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -530,7 +530,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Ptr = EmitScalarExpr(E->getArg(0)); const llvm::Type *ElTy = cast(Ptr->getType())->getElementType(); - Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr, true); + llvm::StoreInst *Store = + Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr); + Store->setVolatile(true); return RValue::get(0); } @@ -813,6 +815,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy); return Builder.CreateStore(Ops[1], Ops[0]); } + case X86::BI__builtin_ia32_palignr128: + case X86::BI__builtin_ia32_palignr: { + Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ? + Intrinsic::x86_ssse3_palign_r_128 : + Intrinsic::x86_ssse3_palign_r); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); + } } } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index b1d30a6..34d1c8d 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -151,8 +151,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, "thread safe statics are currently not supported!"); llvm::SmallString<256> GuardVName; - llvm::raw_svector_ostream GuardVOut(GuardVName); - mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut); + CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); // Create the guard variable. llvm::GlobalValue *GuardV = @@ -197,11 +196,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); - // A call to a trivial destructor requires no code generation. - if (const CXXDestructorDecl *Destructor = dyn_cast(MD)) - if (Destructor->isTrivial()) - return RValue::get(0); - const FunctionProtoType *FPT = MD->getType()->getAs(); CallArgList Args; @@ -275,6 +269,14 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { This = BaseLV.getAddress(); } + if (MD->isCopyAssignment() && MD->isTrivial()) { + // We don't like to generate the trivial copy assignment operator when + // it isn't necessary; just produce the proper effect here. + llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); + EmitAggregateCopy(This, RHS, CE->getType()); + return RValue::get(This); + } + // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the // virtual call mechanism. @@ -284,6 +286,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { llvm::Value *Callee; if (const CXXDestructorDecl *Destructor = dyn_cast(MD)) { + if (Destructor->isTrivial()) + return RValue::get(0); if (MD->isVirtual() && !ME->hasQualifier() && !canDevirtualizeMemberFunctionCalls(ME->getBase())) { Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); @@ -464,26 +468,31 @@ llvm::Value *CodeGenFunction::LoadCXXThis() { /// It is assumed that all relevant checks have been made by the caller. void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr) { + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value * NumElements = llvm::ConstantInt::get(SizeTy, getContext().getConstantArrayElementCount(ArrayTy)); - EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr); + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd); } void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - llvm::Value *NumElements, - llvm::Value *ArrayPtr) { + llvm::Value *NumElements, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); // Create a temporary for the loop index and initialize it with 0. llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); - Builder.CreateStore(Zero, IndexPtr, false); + Builder.CreateStore(Zero, IndexPtr); // Start the loop with a block that tests the condition. llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); @@ -507,15 +516,31 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, "arrayidx"); - EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0); + // C++ [class.temporary]p4: + // There are two contexts in which temporaries are destroyed at a different + // point than the end of the full- expression. The first context is when a + // default constructor is called to initialize an element of an array. + // If the constructor has one or more default arguments, the destruction of + // every temporary created in a default argument expression is sequenced + // before the construction of the next array element, if any. + + // Keep track of the current number of live temporaries. + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + EmitBlock(ContinueBlock); // Emit the increment of the loop counter. llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); Counter = Builder.CreateLoad(IndexPtr); NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr, false); + Builder.CreateStore(NextVal, IndexPtr); // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); @@ -551,7 +576,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), "loop.index"); // Index = ElementCount; - Builder.CreateStore(UpperCount, IndexPtr, false); + Builder.CreateStore(UpperCount, IndexPtr); // Start the loop with a block that tests the condition. llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); @@ -578,23 +603,14 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One); llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - if (D->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), - /*isVariadic=*/false); - - llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, Address, Ty); - EmitCXXMemberCall(D, Callee, Address, 0, 0); - } - else - EmitCXXDestructorCall(D, Dtor_Complete, Address); + EmitCXXDestructorCall(D, Dtor_Complete, Address); EmitBlock(ContinueBlock); // Emit the decrement of the loop counter. Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One, "dec"); - Builder.CreateStore(Counter, IndexPtr, false); + Builder.CreateStore(Counter, IndexPtr); // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); @@ -664,6 +680,10 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitAggregateCopy(This, Src, Ty); return; } + } else if (D->isTrivial()) { + // FIXME: Track down why we're trying to generate calls to the trivial + // default constructor! + return; } llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); @@ -674,6 +694,15 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This) { + if (D->isVirtual()) { + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), + /*isVariadic=*/false); + + llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty); + EmitCXXMemberCall(D, Callee, This, 0, 0); + return; + } llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); EmitCXXMemberCall(D, Callee, This, 0, 0); @@ -715,7 +744,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = Builder.CreateBitCast(Dest, BasePtr); - EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr); + EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, + E->arg_begin(), E->arg_end()); } else // Call the constructor. @@ -744,7 +774,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { const FunctionProtoType *FPT = D->getType()->getAs(); const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(D), + getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), FPT->isVariadic()); const char *Name = getMangledCXXCtorName(D, Type); @@ -755,8 +785,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, CXXCtorType Type) { llvm::SmallString<256> Name; - llvm::raw_svector_ostream Out(Name); - mangleCXXCtor(getMangleContext(), D, Type, Out); + getMangleContext().mangleCXXCtor(D, Type, Name); Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); @@ -764,9 +793,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { if (D->isVirtual()) - EmitCXXDestructor(D, Dtor_Deleting); - EmitCXXDestructor(D, Dtor_Complete); - EmitCXXDestructor(D, Dtor_Base); + EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting)); + EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete)); + EmitGlobalDefinition(GlobalDecl(D, Dtor_Base)); } void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, @@ -783,7 +812,7 @@ llvm::Function * CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); + getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false); const char *Name = getMangledCXXDtorName(D, Type); return cast( @@ -793,59 +822,61 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, CXXDtorType Type) { llvm::SmallString<256> Name; - llvm::raw_svector_ostream Out(Name); - mangleCXXDtor(getMangleContext(), D, Type, Out); + getMangleContext().mangleCXXDtor(D, Type, Name); Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } -llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, - bool Extern, int64_t nv, - int64_t v) { - return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0); +llvm::Constant * +CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + bool Extern, + const ThunkAdjustment &ThisAdjustment) { + return GenerateCovariantThunk(Fn, MD, Extern, + CovariantThunkAdjustment(ThisAdjustment, + ThunkAdjustment())); } -llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv, - int64_t v) { - llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), - 0); +llvm::Value * +CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, + const ThunkAdjustment &Adjustment) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + const llvm::Type *OrigTy = V->getType(); - if (nv) { + if (Adjustment.NonVirtual) { // Do the non-virtual adjustment - V = Builder.CreateBitCast(V, Ptr8Ty); - V = Builder.CreateConstInBoundsGEP1_64(V, nv); - V = Builder.CreateBitCast(V, OrigTy); - } - if (v) { - // Do the virtual this adjustment - const llvm::Type *PtrDiffTy = - ConvertType(getContext().getPointerDiffType()); - llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy; - PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); - PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0); - llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty); - V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo()); - V = Builder.CreateLoad(V, "vtable"); - llvm::Value *VTablePtr = V; - assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned"); - v /= LLVMPointerWidth/8; - V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v); - V = Builder.CreateLoad(V); - V = Builder.CreateGEP(ThisVal, V); + V = Builder.CreateBitCast(V, Int8PtrTy); + V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual); V = Builder.CreateBitCast(V, OrigTy); } - return V; + + if (!Adjustment.Virtual) + return V; + + assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 && + "vtable entry unaligned"); + + // Do the virtual this adjustment + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo(); + + llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy); + V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + + llvm::Value *VTablePtr = V; + uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8); + V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment); + V = Builder.CreateLoad(V); + V = Builder.CreateGEP(ThisVal, V); + + return Builder.CreateBitCast(V, OrigTy); } -llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, - bool Extern, - int64_t nv_t, - int64_t v_t, - int64_t nv_r, - int64_t v_r) { +llvm::Constant * +CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, bool Extern, + const CovariantThunkAdjustment &Adjustment) { QualType ResultType = MD->getType()->getAs()->getResultType(); FunctionArgList Args; @@ -878,16 +909,23 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); CallArgList CallArgs; + bool ShouldAdjustReturnPointer = true; QualType ArgType = MD->getThisType(getContext()); llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this"); - if (nv_t || v_t) { + if (!Adjustment.ThisAdjustment.isEmpty()) { // Do the this adjustment. const llvm::Type *OrigTy = Callee->getType(); - Arg = DynamicTypeAdjust(Arg, nv_t, v_t); - if (nv_r || v_r) { - Callee = CGM.BuildCovariantThunk(MD, Extern, 0, 0, nv_r, v_r); + Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment); + + if (!Adjustment.ReturnAdjustment.isEmpty()) { + const CovariantThunkAdjustment &ReturnAdjustment = + CovariantThunkAdjustment(ThunkAdjustment(), + Adjustment.ReturnAdjustment); + + Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment); + Callee = Builder.CreateBitCast(Callee, OrigTy); - nv_r = v_r = 0; + ShouldAdjustReturnPointer = false; } } @@ -906,7 +944,7 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, MD); - if (nv_r || v_r) { + if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) { bool CanBeZero = !(ResultType->isReferenceType() // FIXME: attr nonnull can't be zero either /* || ResultType->hasAttr() */ ); @@ -921,7 +959,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero), NonZeroBlock, ZeroBlock); EmitBlock(NonZeroBlock); - llvm::Value *NZ = DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r); + llvm::Value *NZ = + DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment); EmitBranch(ContBlock); EmitBlock(ZeroBlock); llvm::Value *Z = RV.getScalarVal(); @@ -932,7 +971,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, RVOrZero->addIncoming(Z, ZeroBlock); RV = RValue::get(RVOrZero); } else - RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); + RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), + Adjustment.ReturnAdjustment)); } if (!ResultType->isVoidType()) @@ -942,11 +982,13 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, return Fn; } -llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, - int64_t nv, int64_t v) { +llvm::Constant * +CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, + const ThunkAdjustment &ThisAdjustment) { + llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleThunk(getMangleContext(), MD, nv, v, Out); + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; if (!Extern) @@ -957,20 +999,18 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); + CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } -llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, - bool Extern, int64_t nv_t, - int64_t v_t, int64_t nv_r, - int64_t v_r) { +llvm::Constant * +CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + const CovariantThunkAdjustment &Adjustment) { llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out); + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; if (!Extern) @@ -981,10 +1021,9 @@ llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), &getModule()); - CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r, - v_r); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } @@ -1016,7 +1055,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, return VBaseOffset; } -static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex, +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -1032,7 +1071,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); return ::BuildVirtualCall(*this, VtableIndex, This, Ty); } @@ -1041,7 +1080,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast(DD->getCanonicalDecl()); - int64_t VtableIndex = + uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VtableIndex, This, Ty); @@ -1065,7 +1104,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, "loop.index"); llvm::Value* zeroConstant = llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr, false); + 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"); @@ -1115,7 +1154,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); Counter = Builder.CreateLoad(IndexPtr); NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr, false); + Builder.CreateStore(NextVal, IndexPtr); // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); @@ -1142,7 +1181,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, "loop.index"); llvm::Value* zeroConstant = llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr, false); + 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"); @@ -1199,7 +1238,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); Counter = Builder.CreateLoad(IndexPtr); NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr, false); + Builder.CreateStore(NextVal, IndexPtr); // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); @@ -1216,10 +1255,10 @@ void CodeGenFunction::EmitClassMemberwiseCopy( const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl, QualType Ty) { if (ClassDecl) { - Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); + Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); } if (BaseClassDecl->hasTrivialCopyConstructor()) { EmitAggregateCopy(Dest, Src, Ty); @@ -1255,10 +1294,10 @@ void CodeGenFunction::EmitClassCopyAssignment( const CXXRecordDecl *BaseClassDecl, QualType Ty) { if (ClassDecl) { - Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); + Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); } if (BaseClassDecl->hasTrivialCopyAssignment()) { EmitAggregateCopy(Dest, Src, Ty); @@ -1297,6 +1336,7 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, CXXCtorType Type, llvm::Function *Fn, const FunctionArgList &Args) { + assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, SourceLocation()); EmitCtorPrologue(Ctor, Type); @@ -1326,6 +1366,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, SourceLocation()); @@ -1349,10 +1390,11 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, Base->getType()); } - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + QualType FieldType = getContext().getCanonicalType(Field->getType()); const ConstantArrayType *Array = getContext().getAsConstantArrayType(FieldType); if (Array) @@ -1361,8 +1403,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, if (const RecordType *FieldClassType = FieldType->getAs()) { CXXRecordDecl *FieldClassDecl = cast(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); if (Array) { const llvm::Type *BasePtr = ConvertType(FieldType); BasePtr = llvm::PointerType::getUnqual(BasePtr); @@ -1378,9 +1420,28 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, 0 /*ClassDecl*/, FieldClassDecl, FieldType); continue; } + + if (Field->getType()->isReferenceType()) { + unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field); + + llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, + "lhs.ref"); + + llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex, + "rhs.ref"); + + // Load the value in RHS. + RHS = Builder.CreateLoad(RHS); + + // And store it in the LHS + Builder.CreateStore(RHS, LHS); + + continue; + } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0); + if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); @@ -1498,9 +1559,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, const Type *BaseType = BaseInit->getBaseClass(); CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); - llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl, - BaseClassDecl, - /*NullCheckValue=*/false); + llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), CtorType, V, BaseInit->const_arg_begin(), @@ -1564,7 +1625,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), - Array, BaseAddrPtr); + Array, BaseAddrPtr, + MemberInit->const_arg_begin(), + MemberInit->const_arg_end()); } else CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), @@ -1714,12 +1777,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; - - llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), - Dtor_Base, V); + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + + llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(D, Dtor_Base, V); } // If we're emitting a base destructor, we don't want to emit calls to the @@ -1727,10 +1790,21 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, if (DtorType == Dtor_Base) return; - // FIXME: Handle virtual bases. + // Handle virtual bases. for (CXXRecordDecl::reverse_base_class_const_iterator I = ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { - assert(false && "FIXME: Handle virtual bases."); + const CXXBaseSpecifier &Base = *I; + CXXRecordDecl *BaseClassDecl + = cast(Base.getType()->getAs()->getDecl()); + + // 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); } // If we have a deleting destructor, emit a call to the delete operator. @@ -1752,9 +1826,3 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, EmitDtorEpilogue(Dtor, DtorType); FinishFunction(); } - -// FIXME: Move this to CGStmtCXX.cpp -void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { - // FIXME: We need to do more here. - EmitStmt(S.getTryBlock()); -} diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp deleted file mode 100644 index 533aabc..0000000 --- a/lib/CodeGen/CGCXXClass.cpp +++ /dev/null @@ -1,179 +0,0 @@ -//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===// -// -// 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 classes -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/RecordLayout.h" - -using namespace clang; -using namespace CodeGen; - -static uint64_t -ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, - unsigned Start) { - uint64_t Offset = 0; - - const CXXBasePath &Path = Paths.front(); - for (unsigned i = Start, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; - - // Get the layout. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - - const CXXBaseSpecifier *BS = Element.Base; - // FIXME: enable test3 from virt.cc to not abort. - if (BS->isVirtual()) - return 0; - assert(!BS->isVirtual() && "Should not see virtual bases here!"); - - const CXXRecordDecl *Base = - cast(BS->getType()->getAs()->getDecl()); - - // Add the offset. - Offset += Layout.getBaseClassOffset(Base) / 8; - } - - return Offset; -} - -llvm::Constant * -CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - if (ClassDecl == BaseClassDecl) - return 0; - - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(ClassDecl)-> - isDerivedFrom(const_cast(BaseClassDecl), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } - - uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0); - if (!Offset) - return 0; - - const llvm::Type *PtrDiffTy = - Types.ConvertType(getContext().getPointerDiffType()); - - return llvm::ConstantInt::get(PtrDiffTy, Offset); -} - -static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, - llvm::Value *BaseValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - if (!const_cast(ClassDecl)-> - isDerivedFrom(const_cast(BaseClassDecl), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } - - unsigned Start = 0; - llvm::Value *VirtualOffset = 0; - if (const RecordType *RT = Paths.getDetectedVirtual()) { - const CXXRecordDecl *VBase = cast(RT->getDecl()); - - VirtualOffset = - CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase); - - const CXXBasePath &Path = Paths.front(); - unsigned e = Path.size(); - for (Start = 0; Start != e; ++Start) { - const CXXBasePathElement& Element = Path[Start]; - - if (Element.Class == VBase) - break; - } - } - - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start); - - if (!Offset) - return VirtualOffset; - - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - if (VirtualOffset) - return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - - return NonVirtualOffset; -} - -llvm::Value * -CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - bool NullCheckValue) { - QualType BTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast(BaseClassDecl))); - const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); - - if (ClassDecl == BaseClassDecl) { - // Just cast back. - return Builder.CreateBitCast(BaseValue, BasePtrTy); - } - - llvm::BasicBlock *CastNull = 0; - llvm::BasicBlock *CastNotNull = 0; - llvm::BasicBlock *CastEnd = 0; - - if (NullCheckValue) { - CastNull = createBasicBlock("cast.null"); - CastNotNull = createBasicBlock("cast.notnull"); - CastEnd = createBasicBlock("cast.end"); - - llvm::Value *IsNull = - Builder.CreateICmpEQ(BaseValue, - llvm::Constant::getNullValue(BaseValue->getType())); - Builder.CreateCondBr(IsNull, CastNull, CastNotNull); - EmitBlock(CastNotNull); - } - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - - llvm::Value *Offset = - GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl); - - if (Offset) { - // Apply the offset. - BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy); - BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr"); - } - - // Cast back. - BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy); - - if (NullCheckValue) { - Builder.CreateBr(CastEnd); - EmitBlock(CastNull); - Builder.CreateBr(CastEnd); - EmitBlock(CastEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(BaseValue, CastNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()), - CastNull); - BaseValue = PHI; - } - - return BaseValue; -} diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp deleted file mode 100644 index cd7d21b..0000000 --- a/lib/CodeGen/CGCXXExpr.cpp +++ /dev/null @@ -1,524 +0,0 @@ -//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ expressions ---------------===// -// -// 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 code generation of C++ expressions -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -using namespace clang; -using namespace CodeGen; - -static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { - if (!E->isArray()) - return 0; - - QualType T = E->getAllocatedType(); - - const RecordType *RT = T->getAs(); - if (!RT) - return 0; - - const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); - if (!RD) - return 0; - - // Check if the class has a trivial destructor. - if (RD->hasTrivialDestructor()) { - // FIXME: Check for a two-argument delete. - return 0; - } - - // Padding is the maximum of sizeof(size_t) and alignof(T) - return std::max(Ctx.getTypeSize(Ctx.getSizeType()), - static_cast(Ctx.getTypeAlign(T))) / 8; -} - -static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, - const CXXNewExpr *E, - llvm::Value *& NumElements) { - QualType Type = E->getAllocatedType(); - uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8; - const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - - if (!E->isArray()) - return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes); - - uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E); - - Expr::EvalResult Result; - if (E->getArraySize()->Evaluate(Result, CGF.getContext()) && - !Result.HasSideEffects && Result.Val.isInt()) { - - uint64_t AllocSize = - Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding; - - NumElements = - llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); - - return llvm::ConstantInt::get(SizeTy, AllocSize); - } - - // Emit the array size expression. - NumElements = CGF.EmitScalarExpr(E->getArraySize()); - - // Multiply with the type size. - llvm::Value *V = - CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get(SizeTy, TypeSizeInBytes)); - - // And add the cookie padding if necessary. - if (CookiePadding) - V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding)); - - return V; -} - -static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, - llvm::Value *NewPtr, - llvm::Value *NumElements) { - QualType AllocType = E->getAllocatedType(); - - if (!E->isArray()) { - if (CXXConstructorDecl *Ctor = E->getConstructor()) { - CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - - return; - } - - // We have a POD type. - if (E->getNumConstructorArgs() == 0) - return; - - assert(E->getNumConstructorArgs() == 1 && - "Can only have one argument to initializer of POD type."); - - const Expr *Init = E->getConstructorArg(0); - - if (!CGF.hasAggregateLLVMType(AllocType)) - CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr); - else if (AllocType->isAnyComplexType()) - CGF.EmitComplexExprIntoAddr(Init, NewPtr, - AllocType.isVolatileQualified()); - else - CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); - return; - } - - if (CXXConstructorDecl *Ctor = E->getConstructor()) - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr); -} - -llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { - QualType AllocType = E->getAllocatedType(); - FunctionDecl *NewFD = E->getOperatorNew(); - const FunctionProtoType *NewFTy = NewFD->getType()->getAs(); - - CallArgList NewArgs; - - // The allocation size is the first argument. - QualType SizeTy = getContext().getSizeType(); - - llvm::Value *NumElements = 0; - llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements); - - NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); - - // Emit the rest of the arguments. - // FIXME: Ideally, this should just use EmitCallArgs. - CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); - - // First, use the types from the function type. - // We start at 1 here because the first argument (the allocation size) - // has already been emitted. - for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { - QualType ArgType = NewFTy->getArgType(i); - - assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). - getTypePtr() == - getContext().getCanonicalType(NewArg->getType()).getTypePtr() && - "type mismatch in call argument!"); - - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - - } - - // Either we've emitted all the call args, or we have a call to a - // variadic function. - assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && - "Extra arguments in non-variadic function!"); - - // If we still have any arguments, emit them using the type of the argument. - for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); - NewArg != NewArgEnd; ++NewArg) { - QualType ArgType = NewArg->getType(); - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - } - - // Emit the call to new. - RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), - CGM.GetAddrOfFunction(NewFD), NewArgs, NewFD); - - // If an allocation function is declared with an empty exception specification - // it returns null to indicate failure to allocate storage. [expr.new]p13. - // (We don't need to check for null when there's no new initializer and - // we're allocating a POD type). - bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && - !(AllocType->isPODType() && !E->hasInitializer()); - - llvm::BasicBlock *NewNull = 0; - llvm::BasicBlock *NewNotNull = 0; - llvm::BasicBlock *NewEnd = 0; - - llvm::Value *NewPtr = RV.getScalarVal(); - - if (NullCheckResult) { - NewNull = createBasicBlock("new.null"); - NewNotNull = createBasicBlock("new.notnull"); - NewEnd = createBasicBlock("new.end"); - - llvm::Value *IsNull = - Builder.CreateICmpEQ(NewPtr, - llvm::Constant::getNullValue(NewPtr->getType()), - "isnull"); - - Builder.CreateCondBr(IsNull, NewNull, NewNotNull); - EmitBlock(NewNotNull); - } - - if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) { - uint64_t CookieOffset = - CookiePadding - getContext().getTypeSize(SizeTy) / 8; - - llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset); - - NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, - ConvertType(SizeTy)->getPointerTo()); - Builder.CreateStore(NumElements, NumElementsPtr); - - // Now add the padding to the new ptr. - NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding); - } - - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - - EmitNewInitializer(*this, E, NewPtr, NumElements); - - if (NullCheckResult) { - Builder.CreateBr(NewEnd); - NewNotNull = Builder.GetInsertBlock(); - EmitBlock(NewNull); - Builder.CreateBr(NewEnd); - EmitBlock(NewEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(NewPtr, NewNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); - - NewPtr = PHI; - } - - return NewPtr; -} - -void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, - llvm::Value *Ptr, - QualType DeleteTy) { - const FunctionProtoType *DeleteFTy = - DeleteFD->getType()->getAs(); - - CallArgList DeleteArgs; - - QualType ArgTy = DeleteFTy->getArgType(0); - llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); - DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); - - if (DeleteFTy->getNumArgs() == 2) { - QualType SizeTy = DeleteFTy->getArgType(1); - uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8; - llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy), - SizeVal); - DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); - } - - // Emit the call to delete. - EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), - DeleteArgs), - CGM.GetAddrOfFunction(DeleteFD), - DeleteArgs, DeleteFD); -} - -void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { - - // Get at the argument before we performed the implicit conversion - // to void*. - const Expr *Arg = E->getArgument(); - while (const ImplicitCastExpr *ICE = dyn_cast(Arg)) { - if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion && - ICE->getType()->isVoidPointerType()) - Arg = ICE->getSubExpr(); - else - break; - } - - QualType DeleteTy = Arg->getType()->getAs()->getPointeeType(); - - llvm::Value *Ptr = EmitScalarExpr(Arg); - - // Null check the pointer. - llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); - llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); - - llvm::Value *IsNull = - Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()), - "isnull"); - - Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); - EmitBlock(DeleteNotNull); - - bool ShouldCallDelete = true; - - // Call the destructor if necessary. - if (const RecordType *RT = DeleteTy->getAs()) { - if (CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { - if (!RD->hasTrivialDestructor()) { - const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); - if (E->isArrayForm()) { - QualType SizeTy = getContext().getSizeType(); - uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy), - static_cast(getContext().getTypeAlign(DeleteTy))) / 8; - if (CookiePadding) { - llvm::Type *Ptr8Ty = - llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - uint64_t CookieOffset = - CookiePadding - getContext().getTypeSize(SizeTy) / 8; - llvm::Value *AllocatedObjectPtr = - Builder.CreateConstInBoundsGEP1_64( - Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding); - llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - CookieOffset); - NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, - ConvertType(SizeTy)->getPointerTo()); - - llvm::Value *NumElements = - Builder.CreateLoad(NumElementsPtr); - NumElements = - Builder.CreateIntCast(NumElements, - llvm::Type::getInt64Ty(VMContext), false, - "count.tmp"); - EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); - Ptr = AllocatedObjectPtr; - } - } - else if (Dtor->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), - /*isVariadic=*/false); - - llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); - EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0); - - // The dtor took care of deleting the object. - ShouldCallDelete = false; - } else - EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); - } - } - } - - if (ShouldCallDelete) - EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy); - - EmitBlock(DeleteEnd); -} - -llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { - QualType Ty = E->getType(); - const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); - if (E->isTypeOperand()) { - Ty = E->getTypeOperand(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType().getNonReferenceType(); - if (const RecordType *RT = Ty->getAs()) { - const CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->isPolymorphic()) - return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); - } - return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy); - } - Expr *subE = E->getExprOperand(); - Ty = subE->getType(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType().getNonReferenceType(); - if (const RecordType *RT = Ty->getAs()) { - const CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->isPolymorphic()) { - // FIXME: if subE is an lvalue do - LValue Obj = EmitLValue(subE); - llvm::Value *This = Obj.getAddress(); - LTy = LTy->getPointerTo()->getPointerTo(); - llvm::Value *V = Builder.CreateBitCast(This, LTy); - // We need to do a zero check for *p, unless it has NonNullAttr. - // FIXME: PointerType->hasAttr() - bool CanBeZero = false; - if (UnaryOperator *UO = dyn_cast(subE->IgnoreParens())) - if (UO->getOpcode() == UnaryOperator::Deref) - CanBeZero = true; - if (CanBeZero) { - llvm::BasicBlock *NonZeroBlock = createBasicBlock(); - llvm::BasicBlock *ZeroBlock = createBasicBlock(); - - llvm::Value *Zero = llvm::Constant::getNullValue(LTy); - Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), - NonZeroBlock, ZeroBlock); - EmitBlock(ZeroBlock); - /// Call __cxa_bad_typeid - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - const llvm::FunctionType *FTy; - FTy = llvm::FunctionType::get(ResultType, false); - llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); - Builder.CreateCall(F)->setDoesNotReturn(); - Builder.CreateUnreachable(); - EmitBlock(NonZeroBlock); - } - V = Builder.CreateLoad(V, "vtable"); - V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); - V = Builder.CreateLoad(V); - return V; - } - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); - } - return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy); -} - -llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, - const CXXDynamicCastExpr *DCE) { - QualType CastTy = DCE->getTypeAsWritten(); - QualType InnerType = CastTy->getPointeeType(); - QualType ArgTy = DCE->getSubExpr()->getType(); - const llvm::Type *LArgTy = ConvertType(ArgTy); - const llvm::Type *LTy = ConvertType(DCE->getType()); - - bool CanBeZero = false; - bool ToVoid = false; - bool ThrowOnBad = false; - if (CastTy->isPointerType()) { - // FIXME: if PointerType->hasAttr(), we don't set this - CanBeZero = true; - if (InnerType->isVoidType()) - ToVoid = true; - } else { - LTy = LTy->getPointerTo(); - ThrowOnBad = true; - } - - CXXRecordDecl *SrcTy; - QualType Ty = ArgTy; - if (ArgTy.getTypePtr()->isPointerType() - || ArgTy.getTypePtr()->isReferenceType()) - Ty = Ty.getTypePtr()->getPointeeType(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType(); - SrcTy = cast(Ty->getAs()->getDecl()); - - llvm::BasicBlock *ContBlock = createBasicBlock(); - llvm::BasicBlock *NullBlock = 0; - llvm::BasicBlock *NonZeroBlock = 0; - if (CanBeZero) { - NonZeroBlock = createBasicBlock(); - NullBlock = createBasicBlock(); - llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); - Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), - NonZeroBlock, NullBlock); - EmitBlock(NonZeroBlock); - } - - llvm::BasicBlock *BadCastBlock = 0; - - const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); - - // See if this is a dynamic_cast(void*) - if (ToVoid) { - llvm::Value *This = V; - V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo()); - V = Builder.CreateLoad(V, "vtable"); - V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL); - V = Builder.CreateLoad(V, "offset to top"); - This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext)); - V = Builder.CreateInBoundsGEP(This, V); - V = Builder.CreateBitCast(V, LTy); - } else { - /// Call __dynamic_cast - const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext); - const llvm::FunctionType *FTy; - std::vector ArgTys; - const llvm::Type *PtrToInt8Ty - = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(PtrDiffTy); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - CXXRecordDecl *DstTy; - Ty = CastTy.getTypePtr()->getPointeeType(); - CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType(); - DstTy = cast(Ty->getAs()->getDecl()); - - // FIXME: Calculate better hint. - llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); - llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); - V = Builder.CreateBitCast(V, PtrToInt8Ty); - V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), - V, SrcArg, DstArg, hint); - V = Builder.CreateBitCast(V, LTy); - - if (ThrowOnBad) { - BadCastBlock = createBasicBlock(); - - llvm::Value *Zero = llvm::Constant::getNullValue(LTy); - Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), - ContBlock, BadCastBlock); - EmitBlock(BadCastBlock); - /// Call __cxa_bad_cast - ResultType = llvm::Type::getVoidTy(VMContext); - const llvm::FunctionType *FBadTy; - FBadTy = llvm::FunctionType::get(ResultType, false); - llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); - Builder.CreateCall(F)->setDoesNotReturn(); - Builder.CreateUnreachable(); - } - } - - if (CanBeZero) { - Builder.CreateBr(ContBlock); - EmitBlock(NullBlock); - Builder.CreateBr(ContBlock); - } - EmitBlock(ContBlock); - if (CanBeZero) { - llvm::PHINode *PHI = Builder.CreatePHI(LTy); - PHI->reserveOperandSpace(2); - PHI->addIncoming(V, NonZeroBlock); - PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); - V = PHI; - } - - return V; -} diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGCXXTemp.cpp deleted file mode 100644 index 4768556..0000000 --- a/lib/CodeGen/CGCXXTemp.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===--- CGCXXTemp.cpp - Emit LLVM Code for C++ temporaries ---------------===// -// -// 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 temporaries -// -//===----------------------------------------------------------------------===// - -#include "CodeGenFunction.h" -using namespace clang; -using namespace CodeGen; - -void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, - llvm::Value *Ptr) { - llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - - llvm::Value *CondPtr = 0; - - // Check if temporaries need to be conditional. If so, we'll create a - // condition boolean, initialize it to 0 and - if (!ConditionalTempDestructionStack.empty()) { - CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); - - // 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); - - // Now set it to true. - Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); - } - - LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, - CondPtr)); - - PushCleanupBlock(DtorBlock); -} - -void CodeGenFunction::PopCXXTemporary() { - const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); - - CleanupBlockInfo CleanupInfo = PopCleanupBlock(); - assert(CleanupInfo.CleanupBlock == Info.DtorBlock && - "Cleanup block mismatch!"); - assert(!CleanupInfo.SwitchBlock && - "Should not have a switch block for temporary cleanup!"); - assert(!CleanupInfo.EndBlock && - "Should not have an end block for temporary cleanup!"); - - llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); - if (CurBB && !CurBB->getTerminator() && - Info.DtorBlock->getNumUses() == 0) { - CurBB->getInstList().splice(CurBB->end(), Info.DtorBlock->getInstList()); - delete Info.DtorBlock; - } else - EmitBlock(Info.DtorBlock); - - llvm::BasicBlock *CondEnd = 0; - - // If this is a conditional temporary, we need to check the condition - // boolean and only call the destructor if it's true. - if (Info.CondPtr) { - llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); - CondEnd = createBasicBlock("cond.dtor.end"); - - llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); - Builder.CreateCondBr(Cond, CondBlock, CondEnd); - EmitBlock(CondBlock); - } - - EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); - - if (CondEnd) { - // Reset the condition. to false. - Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); - EmitBlock(CondEnd); - } - - LiveTemporaries.pop_back(); -} - -RValue -CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, - llvm::Value *AggLoc, - bool IsAggLocVolatile, - bool IsInitializer) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!E->shouldDestroyTemporaries()) - return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, - /*IgnoreResult=*/false, IsInitializer); - - // Keep track of the current cleanup stack depth. - size_t CleanupStackDepth = CleanupEntries.size(); - (void) CleanupStackDepth; - - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, - /*IgnoreResult=*/false, IsInitializer); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); - - assert(CleanupEntries.size() == CleanupStackDepth && - "Cleanup size mismatch!"); - - return RV; -} - -LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( - const CXXExprWithTemporaries *E) { - // If we shouldn't destroy the temporaries, just emit the - // child expression. - if (!E->shouldDestroyTemporaries()) - return EmitLValue(E->getSubExpr()); - - // Keep track of the current cleanup stack depth. - size_t CleanupStackDepth = CleanupEntries.size(); - (void) CleanupStackDepth; - - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - LValue LV = EmitLValue(E->getSubExpr()); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); - - assert(CleanupEntries.size() == CleanupStackDepth && - "Cleanup size mismatch!"); - - return LV; -} - -void -CodeGenFunction::PushConditionalTempDestruction() { - // Store the current number of live temporaries. - ConditionalTempDestructionStack.push_back(LiveTemporaries.size()); -} - -void CodeGenFunction::PopConditionalTempDestruction() { - size_t NumLiveTemporaries = ConditionalTempDestructionStack.back(); - ConditionalTempDestructionStack.pop_back(); - - // Pop temporaries. - while (LiveTemporaries.size() > NumLiveTemporaries) { - assert(LiveTemporaries.back().CondPtr && - "Conditional temporary must have a cond ptr!"); - - PopCXXTemporary(); - } -} - diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index d0c7d03..decc73c 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -91,6 +91,42 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { getCallingConventionForDecl(MD)); } +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, + CXXCtorType Type) { + llvm::SmallVector ArgTys; + + // Add the 'this' pointer. + ArgTys.push_back(D->getThisType(Context)); + + // Check if we need to add a VTT parameter (which has type void **). + if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0) + ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + + const FunctionProtoType *FTP = D->getType()->getAs(); + for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) + ArgTys.push_back(FTP->getArgType(i)); + return getFunctionInfo(FTP->getResultType(), ArgTys, + getCallingConventionForDecl(D)); +} + +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, + CXXDtorType Type) { + llvm::SmallVector ArgTys; + + // Add the 'this' pointer. + ArgTys.push_back(D->getThisType(Context)); + + // Check if we need to add a VTT parameter (which has type void **). + if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) + ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + + const FunctionProtoType *FTP = D->getType()->getAs(); + for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) + ArgTys.push_back(FTP->getArgType(i)); + return getFunctionInfo(FTP->getResultType(), ArgTys, + getCallingConventionForDecl(D)); +} + const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { if (const CXXMethodDecl *MD = dyn_cast(FD)) if (MD->isInstance()) @@ -418,6 +454,32 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic); } +static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) { + if (const TagType *TT = T->getResultType()->getAs()) { + if (!TT->getDecl()->isDefinition()) + return true; + } + + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { + if (const TagType *TT = T->getArgType(i)->getAs()) { + if (!TT->getDecl()->isDefinition()) + return true; + } + } + + return false; +} + +const llvm::Type * +CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) { + const FunctionProtoType *FPT = MD->getType()->getAs(); + + if (!HasIncompleteReturnTypeOrArgumentTypes(FPT)) + return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic()); + + return llvm::OpaqueType::get(getLLVMContext()); +} + void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const Decl *TargetDecl, AttributeListType &PAL, diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp new file mode 100644 index 0000000..b3c2b98 --- /dev/null +++ b/lib/CodeGen/CGClass.cpp @@ -0,0 +1,235 @@ +//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===// +// +// 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 classes +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" + +using namespace clang; +using namespace CodeGen; + +static uint64_t +ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, + unsigned Start) { + uint64_t Offset = 0; + + const CXXBasePath &Path = Paths.front(); + for (unsigned i = Start, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + + // Get the layout. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + + const CXXBaseSpecifier *BS = Element.Base; + assert(!BS->isVirtual() && "Should not see virtual bases here!"); + + const CXXRecordDecl *Base = + cast(BS->getType()->getAs()->getDecl()); + + // Add the offset. + Offset += Layout.getBaseClassOffset(Base) / 8; + } + + return Offset; +} + +llvm::Constant * +CodeGenModule::GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + if (ClassDecl == BaseClassDecl) + return 0; + + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast(ClassDecl)-> + isDerivedFrom(const_cast(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0); + if (!Offset) + return 0; + + const llvm::Type *PtrDiffTy = + Types.ConvertType(getContext().getPointerDiffType()); + + return llvm::ConstantInt::get(PtrDiffTy, Offset); +} + +static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, + llvm::Value *BaseValue, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast(ClassDecl)-> + isDerivedFrom(const_cast(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + unsigned Start = 0; + llvm::Value *VirtualOffset = 0; + + const CXXBasePath &Path = Paths.front(); + const CXXRecordDecl *VBase = 0; + for (unsigned i = 0, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + if (Element.Base->isVirtual()) { + Start = i+1; + QualType VBaseType = Element.Base->getType(); + VBase = cast(VBaseType->getAs()->getDecl()); + } + } + if (VBase) + VirtualOffset = + CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase); + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start); + + if (!Offset) + return VirtualOffset; + + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); + + if (VirtualOffset) + return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset); + + return NonVirtualOffset; +} + +llvm::Value * +CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + bool NullCheckValue) { + QualType BTy = + getContext().getCanonicalType( + getContext().getTypeDeclType(const_cast(BaseClassDecl))); + const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); + + if (ClassDecl == BaseClassDecl) { + // Just cast back. + return Builder.CreateBitCast(Value, BasePtrTy); + } + + llvm::BasicBlock *CastNull = 0; + llvm::BasicBlock *CastNotNull = 0; + llvm::BasicBlock *CastEnd = 0; + + if (NullCheckValue) { + CastNull = createBasicBlock("cast.null"); + CastNotNull = createBasicBlock("cast.notnull"); + CastEnd = createBasicBlock("cast.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Value, + llvm::Constant::getNullValue(Value->getType())); + Builder.CreateCondBr(IsNull, CastNull, CastNotNull); + EmitBlock(CastNotNull); + } + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + + llvm::Value *Offset = + GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl); + + if (Offset) { + // Apply the offset. + Value = Builder.CreateBitCast(Value, Int8PtrTy); + Value = Builder.CreateGEP(Value, Offset, "add.ptr"); + } + + // Cast back. + Value = Builder.CreateBitCast(Value, BasePtrTy); + + if (NullCheckValue) { + Builder.CreateBr(CastEnd); + EmitBlock(CastNull); + Builder.CreateBr(CastEnd); + EmitBlock(CastEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(Value, CastNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), + CastNull); + Value = PHI; + } + + return Value; +} + +llvm::Value * +CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *DerivedClassDecl, + bool NullCheckValue) { + QualType DerivedTy = + getContext().getCanonicalType( + getContext().getTypeDeclType(const_cast(DerivedClassDecl))); + const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); + + if (ClassDecl == DerivedClassDecl) { + // Just cast back. + return Builder.CreateBitCast(Value, DerivedPtrTy); + } + + llvm::BasicBlock *CastNull = 0; + llvm::BasicBlock *CastNotNull = 0; + llvm::BasicBlock *CastEnd = 0; + + if (NullCheckValue) { + CastNull = createBasicBlock("cast.null"); + CastNotNull = createBasicBlock("cast.notnull"); + CastEnd = createBasicBlock("cast.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Value, + llvm::Constant::getNullValue(Value->getType())); + Builder.CreateCondBr(IsNull, CastNull, CastNotNull); + EmitBlock(CastNotNull); + } + + llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl, + ClassDecl); + if (Offset) { + // Apply the offset. + Value = Builder.CreatePtrToInt(Value, Offset->getType()); + Value = Builder.CreateSub(Value, Offset); + Value = Builder.CreateIntToPtr(Value, DerivedPtrTy); + } else { + // Just cast. + Value = Builder.CreateBitCast(Value, DerivedPtrTy); + } + + if (NullCheckValue) { + Builder.CreateBr(CastEnd); + EmitBlock(CastNull); + Builder.CreateBr(CastEnd); + EmitBlock(CastEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(Value, CastNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), + CastNull); + Value = PHI; + } + + return Value; +} diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 0551667..317da7e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -95,10 +95,10 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // file at a time. bool isMain = false; const LangOptions &LO = M->getLangOptions(); - const char *MainFileName = LO.getMainFileName(); + const CodeGenOptions &CGO = M->getCodeGenOpts(); if (isMainCompileUnitCreated == false) { - if (MainFileName) { - if (!strcmp(AbsFileName.getLast().c_str(), MainFileName)) + if (!CGO.MainFileName.empty()) { + if (AbsFileName.getLast() == CGO.MainFileName) isMain = true; } else { if (Loc.isValid() && SM.isFromMainFile(Loc)) @@ -417,7 +417,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIType DbgTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, - Ty->getDecl()->getNameAsCString(), + Ty->getDecl()->getName(), DefUnit, Line, 0, 0, 0, 0, Src); return DbgTy; } @@ -482,7 +482,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(), + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); @@ -507,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - const char *FieldName = Field->getNameAsCString(); + llvm::StringRef FieldName = Field->getName(); // Ignore unnamed fields. - if (!FieldName) + if (FieldName.empty()) continue; // Get the location for the field. @@ -558,7 +558,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(), + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements); @@ -592,7 +592,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray(), RuntimeLang); @@ -628,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCIvarDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - const char *FieldName = Field->getNameAsCString(); + llvm::StringRef FieldName = Field->getName(); // Ignore unnamed fields. - if (!FieldName) + if (FieldName.empty()) continue; // Get the location for the field. @@ -682,7 +682,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit, + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements, RuntimeLang); @@ -703,7 +703,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, for (EnumDecl::enumerator_iterator Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end(); Enum != EnumEnd; ++Enum) { - Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsCString(), + Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(), Enum->getInitVal().getZExtValue())); } @@ -728,7 +728,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIType DbgTy = DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, Decl->getNameAsCString(), DefUnit, Line, + Unit, Decl->getName(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), EltArray); return DbgTy; @@ -1104,7 +1104,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FieldAlign = Align*8; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Decl->getNameAsCString(), DefUnit, + Decl->getName(), DefUnit, 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); @@ -1135,7 +1135,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Create the descriptor for the variable. llvm::DIVariable D = DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()), - Decl->getNameAsCString(), + Decl->getName(), Unit, Line, Ty); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1282,7 +1282,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, XOffset = FieldOffset; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Decl->getNameAsCString(), DefUnit, + Decl->getName(), DefUnit, 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); @@ -1336,7 +1336,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Create the descriptor for the variable. llvm::DIVariable D = DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()), - Decl->getNameAsCString(), Unit, Line, Ty, + Decl->getName(), Unit, Line, Ty, addr); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1392,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = M->getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - const char *DeclName = Decl->getNameAsCString(); + llvm::StringRef DeclName = Decl->getName(); DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName, - NULL, Unit, LineNo, + llvm::StringRef(), Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); @@ -1409,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - const char *Name = Decl->getNameAsCString(); + llvm::StringRef Name = Decl->getName(); QualType T = M->getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 349ede5..c047283 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -30,7 +30,9 @@ using namespace CodeGen; void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { - default: assert(0 && "Unknown decl kind!"); + default: + CGM.ErrorUnsupported(&D, "decl"); + return; case Decl::ParmVar: assert(0 && "Parmdecls should not be in declstmts!"); case Decl::Function: // void X(); @@ -38,7 +40,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Enum: // enum X; case Decl::EnumConstant: // enum ? { X = ? } case Decl::CXXRecord: // struct/union/class X; [C++] - case Decl::UsingDirective: // using X; [C++] + case Decl::Using: // using X; [C++] + case Decl::UsingShadow: + case Decl::UsingDirective: // using namespace X; [C++] // None of these decls require codegen support. return; @@ -372,7 +376,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { { // Push a cleanup block and restore the stack there. - CleanupScope scope(*this); + DelayedCleanupBlock scope(*this); V = Builder.CreateLoad(Stack, "tmp"); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore); @@ -517,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { - CleanupScope Scope(*this); + DelayedCleanupBlock Scope(*this); QualType BaseElementTy = getContext().getBaseElementType(Array); const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); @@ -528,7 +532,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); } else { - CleanupScope Scope(*this); + DelayedCleanupBlock Scope(*this); EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); } } @@ -541,7 +545,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Constant* F = CGM.GetAddrOfFunction(FD); assert(F && "Could not find function!"); - CleanupScope scope(*this); + DelayedCleanupBlock scope(*this); const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); @@ -562,9 +566,9 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { } if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { - CleanupScope scope(*this); + DelayedCleanupBlock scope(*this); llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V, false); + V = Builder.CreateLoad(V); BuildBlockRelease(V); } } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index adfd005..420e275 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -11,6 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/StmtCXX.h" + +#include "llvm/Intrinsics.h" + #include "CodeGenFunction.h" using namespace clang; using namespace CodeGen; @@ -35,29 +39,158 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { std::vector Args(3, Int8PtrTy); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), - Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } +static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { + // void __cxa_rethrow (); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); +} + +static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { + // void* __cxa_begin_catch (); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(Int8PtrTy, Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); +} + +static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { + // void __cxa_end_catch (); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); +} + +// FIXME: Eventually this will all go into the backend. Set from the target for +// now. +static int using_sjlj_exceptions = 0; + +static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, + false); + + if (using_sjlj_exceptions) + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { + 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(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast(ObjectType->getAs()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggExpr(E, This, false); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + + // 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())); + QualType ResultType = + CopyCtor->getType()->getAs()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + CGF.ErrorUnsupported(E, "uncopyable object"); + } +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, + llvm::Value *E, llvm::Value *N) { + // Store the throw exception in the exception object. + if (!CGF.hasAggregateLLVMType(ObjectType)) { + llvm::Value *Value = E; + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast(ObjectType->getAs()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggregateCopy(This, E, ObjectType); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = E; + + // 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())); + QualType ResultType = + CopyCtor->getType()->getAs()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + llvm::llvm_unreachable("uncopyable object"); + } +} + void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { - // FIXME: Handle rethrows. if (!E->getSubExpr()) { - ErrorUnsupported(E, "rethrow expression"); + Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); return; } QualType ThrowType = E->getSubExpr()->getType(); - // FIXME: We only handle non-class types for now. - if (ThrowType->isRecordType()) { - ErrorUnsupported(E, "throw expression"); - return; - } - // FIXME: Handle cleanup. if (!CleanupEntries.empty()){ - ErrorUnsupported(E, "throw expression"); + ErrorUnsupported(E, "throw expression with cleanup entries"); return; } @@ -71,28 +204,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - // Store the throw exception in the exception object. - if (!hasAggregateLLVMType(ThrowType)) { - llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); - } else { - // FIXME: Handle complex and aggregate expressions. - ErrorUnsupported(E, "throw expression"); - } + CopyObject(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - - llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out); - - // FIXME: Is it OK to use CreateRuntimeVariable for this? - llvm::Constant *TypeInfo = - CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()), - OutName.c_str()); + llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); llvm::CallInst *ThrowCall = @@ -103,3 +219,217 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); } + +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { +#if 1 + EmitStmt(S.getTryBlock()); + if (0) { + getBeginCatchFn(*this); + getEndCatchFn(*this); + getUnwindResumeOrRethrowFn(*this); + CopyObject(*this, QualType(), 0, 0); + } +#else + // FIXME: The below is still just a sketch of the code we need. + // Pointer to the personality function + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); +#if 0 + llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); +#endif + llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); + llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); + +#if 0 + // Push an EH context entry, used for handling rethrows. + PushCleanupBlock(FinallyBlock); +#endif + + // Emit the statements in the try {} block + setInvokeDest(TryHandler); + + EmitStmt(S.getTryBlock()); + + // Jump to end if there is no exception + EmitBranchThroughCleanup(FinallyEnd); + + // Emit the handlers + EmitBlock(TryHandler); + + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector SelectorArgs; + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + llvm::Value *llvm_eh_typeid_for = + CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + + bool HasCatchAll = false; + for (unsigned i = 0; igetExceptionDecl(); + if (CatchParam) { + llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + SelectorArgs.push_back(EHType); + } else { + // null indicates catch all + SelectorArgs.push_back(Null); + HasCatchAll = true; + } + } + + // We use a cleanup unless there was already a catch all. + if (!HasCatchAll) { + SelectorArgs.push_back(Null); + } + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + for (unsigned i = 0; igetExceptionDecl(); + Stmt *CatchBody = C->getHandlerBlock(); + + llvm::BasicBlock *Next = 0; + + if (SelectorArgs[i+2] != Null) { + llvm::BasicBlock *Match = createBasicBlock("match"); + Next = createBasicBlock("catch.next"); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + llvm::Value *Id + = Builder.CreateCall(llvm_eh_typeid_for, + Builder.CreateBitCast(SelectorArgs[i+2], + Int8PtrTy)); + Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), + Match, Next); + EmitBlock(Match); + } + + llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); + llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); + + PushCleanupBlock(MatchEnd); + setInvokeDest(MatchHandler); + + llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); + + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + if (!CatchType.getTypePtr()->isPointerType()) + CatchType = getContext().getPointerType(CatchType); + ExcObject = + Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + // CatchParam is a ParmVarDecl because of the grammar + // construction used to handle this, but for codegen purposes + // we treat this as a local decl. + EmitLocalBlockVarDecl(*CatchParam); +#if 0 + // FIXME: objects with ctors, references + Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); +#else + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + ExcObject, GetAddrOfLocalVar(CatchParam)); +#endif + } + + EmitStmt(CatchBody); + EmitBranchThroughCleanup(FinallyEnd); + + EmitBlock(MatchHandler); + + llvm::Value *Exc = 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(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); + + EmitBlock(MatchEnd); + + // Unfortunately, we also have to generate another EH frame here + // in case this throws. + llvm::BasicBlock *MatchEndHandler = + createBasicBlock("match.end.handler"); + llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + Builder.CreateInvoke(getEndCatchFn(*this), + Cont, MatchEndHandler, + Args.begin(), Args.begin()); + + EmitBlock(Cont); + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + EmitBlock(MatchEndHandler); + Exc = 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(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + if (Next) + EmitBlock(Next); + } + if (!HasCatchAll) + EmitBranchThroughCleanup(FinallyRethrow); + + CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); + + setInvokeDest(PrevLandingPad); + +#if 0 + EmitBlock(FinallyBlock); + + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + // Branch around the rethrow code. + EmitBranch(FinallyEnd); +#endif + + EmitBlock(FinallyRethrow); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + + EmitBlock(FinallyEnd); +#endif +} diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2a544c5..63fca2d 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -137,7 +137,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, const CXXDestructorDecl *Dtor = ClassDecl->getDestructor(getContext()); - CleanupScope scope(*this); + DelayedCleanupBlock scope(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr()); } } @@ -148,8 +148,8 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (BaseClassDecl) { llvm::Value *Derived = Val.getAggregateAddr(); llvm::Value *Base = - GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); + GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); return RValue::get(Base); } } @@ -258,8 +258,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::BlockDeclRefExprClass: return EmitBlockDeclRefLValue(cast(E)); - case Expr::CXXConditionDeclExprClass: - return EmitCXXConditionDeclLValue(cast(E)); case Expr::CXXTemporaryObjectExprClass: case Expr::CXXConstructExprClass: return EmitCXXConstructLValue(cast(E)); @@ -314,9 +312,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, QualType Ty) { - llvm::Value *V = Builder.CreateLoad(Addr, Volatile, "tmp"); + llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp"); + if (Volatile) + Load->setVolatile(true); // Bool can have different representation in memory than in registers. + llvm::Value *V = Load; if (Ty->isBooleanType()) if (V->getType() != llvm::Type::getInt1Ty(VMContext)) V = Builder.CreateTrunc(V, llvm::Type::getInt1Ty(VMContext), "tobool"); @@ -830,6 +831,24 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, return LV; } +static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, + const Expr *E, const FunctionDecl *FD) { + llvm::Value* V = CGF.CGM.GetAddrOfFunction(FD); + if (!FD->hasPrototype()) { + if (const FunctionProtoType *Proto = + FD->getType()->getAs()) { + // Ugly case: for a K&R-style definition, the type of the definition + // isn't the same as the type of a use. Correct for this with a + // bitcast. + QualType NoProtoType = + CGF.getContext().getFunctionNoProtoType(Proto->getResultType()); + NoProtoType = CGF.getContext().getPointerType(NoProtoType); + V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp"); + } + } + return LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType())); +} + LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { const NamedDecl *ND = E->getDecl(); @@ -851,7 +870,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (VD->hasAttr()) { V = Builder.CreateStructGEP(V, 1, "forwarding"); - V = Builder.CreateLoad(V, false); + V = Builder.CreateLoad(V); V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), VD->getNameAsString()); } @@ -863,22 +882,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { return LV; } - if (const FunctionDecl *FD = dyn_cast(ND)) { - llvm::Value* V = CGM.GetAddrOfFunction(FD); - if (!FD->hasPrototype()) { - if (const FunctionProtoType *Proto = - FD->getType()->getAs()) { - // Ugly case: for a K&R-style definition, the type of the definition - // isn't the same as the type of a use. Correct for this with a - // bitcast. - QualType NoProtoType = - getContext().getFunctionNoProtoType(Proto->getResultType()); - NoProtoType = getContext().getPointerType(NoProtoType); - V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp"); - } - } - return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } + if (const FunctionDecl *FD = dyn_cast(ND)) + return EmitFunctionDeclLValue(*this, E, FD); if (E->getQualifier()) { // FIXME: the qualifier check does not seem sufficient here @@ -1165,7 +1170,10 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { if (VarDecl *VD = dyn_cast(ND)) return EmitGlobalVarDeclLValue(*this, E, VD); - + + if (const FunctionDecl *FD = dyn_cast(ND)) + return EmitFunctionDeclLValue(*this, E, FD); + assert(false && "Unhandled member declaration!"); return LValue(); } @@ -1328,8 +1336,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the derived-to-base conversion llvm::Value *Base = - GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl, - BaseClassDecl, /*NullCheckValue=*/false); + GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl, + BaseClassDecl, /*NullCheckValue=*/false); return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } @@ -1340,7 +1348,23 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } case CastExpr::CK_BaseToDerived: { - return EmitUnsupportedLValue(E, "base-to-derived cast lvalue"); + const RecordType *BaseClassTy = + E->getSubExpr()->getType()->getAs(); + CXXRecordDecl *BaseClassDecl = + cast(BaseClassTy->getDecl()); + + const RecordType *DerivedClassTy = E->getType()->getAs(); + CXXRecordDecl *DerivedClassDecl = + cast(DerivedClassTy->getDecl()); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Perform the base-to-derived conversion + llvm::Value *Derived = + GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl, + DerivedClassDecl, /*NullCheckValue=*/false); + + return LValue::MakeAddr(Derived, MakeQualifiers(E->getType())); } case CastExpr::CK_BitCast: { // This must be a reinterpret_cast (or c-style equivalent). @@ -1460,12 +1484,6 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } -LValue -CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E) { - EmitLocalBlockVarDecl(*E->getVarDecl()); - return EmitDeclRefLValue(E); -} - LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp"); EmitCXXConstructExpr(Temp, E); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0e10368..d225d90 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -20,7 +20,6 @@ #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" -#include "llvm/Support/Compiler.h" #include "llvm/Intrinsics.h" using namespace clang; using namespace CodeGen; @@ -30,7 +29,7 @@ using namespace CodeGen; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor { +class AggExprEmitter : public StmtVisitor { CodeGenFunction &CGF; CGBuilderTy &Builder; llvm::Value *DestPtr; @@ -223,6 +222,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } + case CastExpr::CK_DerivedToBaseMemberPointer: case CastExpr::CK_BaseToDerivedMemberPointer: { QualType SrcType = E->getSubExpr()->getType(); @@ -242,16 +242,22 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); // Now See if we need to update the adjustment. - const CXXRecordDecl *SrcDecl = + const CXXRecordDecl *BaseDecl = cast(SrcType->getAs()-> getClass()->getAs()->getDecl()); - const CXXRecordDecl *DstDecl = + const CXXRecordDecl *DerivedDecl = cast(E->getType()->getAs()-> getClass()->getAs()->getDecl()); - - llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DstDecl, SrcDecl); - if (Adj) - SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) + std::swap(DerivedDecl, BaseDecl); + + llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl); + if (Adj) { + if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) + SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); + else + SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + } Builder.CreateStore(SrcAdj, DstAdj, VolatileDest); break; @@ -389,21 +395,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. assert(E->getLHS() && "Must have LHS for aggregate value"); Visit(E->getLHS()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); CGF.EmitBranch(ContBlock); - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); CGF.EmitBlock(RHSBlock); Visit(E->getRHS()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp new file mode 100644 index 0000000..b982c15 --- /dev/null +++ b/lib/CodeGen/CGExprCXX.cpp @@ -0,0 +1,527 @@ +//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===// +// +// 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 code generation of C++ expressions +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + if (!E->isArray()) + return 0; + + QualType T = E->getAllocatedType(); + + const RecordType *RT = T->getAs(); + if (!RT) + return 0; + + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD) + return 0; + + // Check if the class has a trivial destructor. + if (RD->hasTrivialDestructor()) { + // FIXME: Check for a two-argument delete. + return 0; + } + + // Padding is the maximum of sizeof(size_t) and alignof(T) + return std::max(Ctx.getTypeSize(Ctx.getSizeType()), + static_cast(Ctx.getTypeAlign(T))) / 8; +} + +static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, + const CXXNewExpr *E, + llvm::Value *& NumElements) { + QualType Type = E->getAllocatedType(); + uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8; + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + + if (!E->isArray()) + return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes); + + uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E); + + Expr::EvalResult Result; + if (E->getArraySize()->Evaluate(Result, CGF.getContext()) && + !Result.HasSideEffects && Result.Val.isInt()) { + + uint64_t AllocSize = + Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding; + + NumElements = + llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); + + return llvm::ConstantInt::get(SizeTy, AllocSize); + } + + // Emit the array size expression. + NumElements = CGF.EmitScalarExpr(E->getArraySize()); + + // Multiply with the type size. + llvm::Value *V = + CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get(SizeTy, TypeSizeInBytes)); + + // And add the cookie padding if necessary. + if (CookiePadding) + V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding)); + + return V; +} + +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; + } + + QualType AllocType = E->getAllocatedType(); + + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + + return; + } + + // We have a POD type. + if (E->getNumConstructorArgs() == 0) + return; + + assert(E->getNumConstructorArgs() == 1 && + "Can only have one argument to initializer of POD type."); + + const Expr *Init = E->getConstructorArg(0); + + if (!CGF.hasAggregateLLVMType(AllocType)) + CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr, + AllocType.isVolatileQualified(), AllocType); + else if (AllocType->isAnyComplexType()) + CGF.EmitComplexExprIntoAddr(Init, NewPtr, + AllocType.isVolatileQualified()); + else + CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); +} + +llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { + QualType AllocType = E->getAllocatedType(); + FunctionDecl *NewFD = E->getOperatorNew(); + const FunctionProtoType *NewFTy = NewFD->getType()->getAs(); + + CallArgList NewArgs; + + // The allocation size is the first argument. + QualType SizeTy = getContext().getSizeType(); + + llvm::Value *NumElements = 0; + llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements); + + NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); + + // Emit the rest of the arguments. + // FIXME: Ideally, this should just use EmitCallArgs. + CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); + + // First, use the types from the function type. + // We start at 1 here because the first argument (the allocation size) + // has already been emitted. + for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { + QualType ArgType = NewFTy->getArgType(i); + + assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). + getTypePtr() == + getContext().getCanonicalType(NewArg->getType()).getTypePtr() && + "type mismatch in call argument!"); + + NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), + ArgType)); + + } + + // Either we've emitted all the call args, or we have a call to a + // variadic function. + assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && + "Extra arguments in non-variadic function!"); + + // If we still have any arguments, emit them using the type of the argument. + for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); + NewArg != NewArgEnd; ++NewArg) { + QualType ArgType = NewArg->getType(); + NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), + ArgType)); + } + + // Emit the call to new. + RValue RV = + EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), + CGM.GetAddrOfFunction(NewFD), NewArgs, NewFD); + + // If an allocation function is declared with an empty exception specification + // it returns null to indicate failure to allocate storage. [expr.new]p13. + // (We don't need to check for null when there's no new initializer and + // we're allocating a POD type). + bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && + !(AllocType->isPODType() && !E->hasInitializer()); + + llvm::BasicBlock *NewNull = 0; + llvm::BasicBlock *NewNotNull = 0; + llvm::BasicBlock *NewEnd = 0; + + llvm::Value *NewPtr = RV.getScalarVal(); + + if (NullCheckResult) { + NewNull = createBasicBlock("new.null"); + NewNotNull = createBasicBlock("new.notnull"); + NewEnd = createBasicBlock("new.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(NewPtr, + llvm::Constant::getNullValue(NewPtr->getType()), + "isnull"); + + Builder.CreateCondBr(IsNull, NewNull, NewNotNull); + EmitBlock(NewNotNull); + } + + if (uint64_t CookiePadding = CalculateCookiePadding(getContext(), E)) { + uint64_t CookieOffset = + CookiePadding - getContext().getTypeSize(SizeTy) / 8; + + llvm::Value *NumElementsPtr = + Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset); + + NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, + ConvertType(SizeTy)->getPointerTo()); + Builder.CreateStore(NumElements, NumElementsPtr); + + // Now add the padding to the new ptr. + NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, CookiePadding); + } + + NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); + + EmitNewInitializer(*this, E, NewPtr, NumElements); + + if (NullCheckResult) { + Builder.CreateBr(NewEnd); + NewNotNull = Builder.GetInsertBlock(); + EmitBlock(NewNull); + Builder.CreateBr(NewEnd); + EmitBlock(NewEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(NewPtr, NewNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); + + NewPtr = PHI; + } + + return NewPtr; +} + +void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, + llvm::Value *Ptr, + QualType DeleteTy) { + const FunctionProtoType *DeleteFTy = + DeleteFD->getType()->getAs(); + + CallArgList DeleteArgs; + + QualType ArgTy = DeleteFTy->getArgType(0); + llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); + DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); + + if (DeleteFTy->getNumArgs() == 2) { + QualType SizeTy = DeleteFTy->getArgType(1); + uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8; + llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy), + SizeVal); + DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); + } + + // Emit the call to delete. + EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), + DeleteArgs), + CGM.GetAddrOfFunction(DeleteFD), + DeleteArgs, DeleteFD); +} + +void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { + + // Get at the argument before we performed the implicit conversion + // to void*. + const Expr *Arg = E->getArgument(); + while (const ImplicitCastExpr *ICE = dyn_cast(Arg)) { + if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + + QualType DeleteTy = Arg->getType()->getAs()->getPointeeType(); + + llvm::Value *Ptr = EmitScalarExpr(Arg); + + // Null check the pointer. + llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); + llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()), + "isnull"); + + Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); + EmitBlock(DeleteNotNull); + + bool ShouldCallDelete = true; + + // Call the destructor if necessary. + if (const RecordType *RT = DeleteTy->getAs()) { + if (CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + if (!RD->hasTrivialDestructor()) { + const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); + if (E->isArrayForm()) { + QualType SizeTy = getContext().getSizeType(); + uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy), + static_cast(getContext().getTypeAlign(DeleteTy))) / 8; + if (CookiePadding) { + llvm::Type *Ptr8Ty = + llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + uint64_t CookieOffset = + CookiePadding - getContext().getTypeSize(SizeTy) / 8; + llvm::Value *AllocatedObjectPtr = + Builder.CreateConstInBoundsGEP1_64( + Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding); + llvm::Value *NumElementsPtr = + Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + CookieOffset); + NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, + ConvertType(SizeTy)->getPointerTo()); + + llvm::Value *NumElements = + Builder.CreateLoad(NumElementsPtr); + NumElements = + Builder.CreateIntCast(NumElements, + llvm::Type::getInt64Ty(VMContext), false, + "count.tmp"); + EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); + Ptr = AllocatedObjectPtr; + } + } + else if (Dtor->isVirtual()) { + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), + /*isVariadic=*/false); + + llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); + EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0); + + // The dtor took care of deleting the object. + ShouldCallDelete = false; + } else + EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + } + } + } + + if (ShouldCallDelete) + EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy); + + EmitBlock(DeleteEnd); +} + +llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { + QualType Ty = E->getType(); + const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); + if (E->isTypeOperand()) { + Ty = E->getTypeOperand(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType().getNonReferenceType(); + if (const RecordType *RT = Ty->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->isPolymorphic()) + return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + } + return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); + } + Expr *subE = E->getExprOperand(); + Ty = subE->getType(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType().getNonReferenceType(); + if (const RecordType *RT = Ty->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->isPolymorphic()) { + // FIXME: if subE is an lvalue do + LValue Obj = EmitLValue(subE); + llvm::Value *This = Obj.getAddress(); + LTy = LTy->getPointerTo()->getPointerTo(); + llvm::Value *V = Builder.CreateBitCast(This, LTy); + // We need to do a zero check for *p, unless it has NonNullAttr. + // FIXME: PointerType->hasAttr() + bool CanBeZero = false; + if (UnaryOperator *UO = dyn_cast(subE->IgnoreParens())) + if (UO->getOpcode() == UnaryOperator::Deref) + CanBeZero = true; + if (CanBeZero) { + llvm::BasicBlock *NonZeroBlock = createBasicBlock(); + llvm::BasicBlock *ZeroBlock = createBasicBlock(); + + llvm::Value *Zero = llvm::Constant::getNullValue(LTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + NonZeroBlock, ZeroBlock); + EmitBlock(ZeroBlock); + /// Call __cxa_bad_typeid + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + const llvm::FunctionType *FTy; + FTy = llvm::FunctionType::get(ResultType, false); + llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); + Builder.CreateCall(F)->setDoesNotReturn(); + Builder.CreateUnreachable(); + EmitBlock(NonZeroBlock); + } + V = Builder.CreateLoad(V, "vtable"); + V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); + V = Builder.CreateLoad(V); + return V; + } + return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + } + return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); +} + +llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, + const CXXDynamicCastExpr *DCE) { + QualType CastTy = DCE->getTypeAsWritten(); + QualType InnerType = CastTy->getPointeeType(); + QualType ArgTy = DCE->getSubExpr()->getType(); + const llvm::Type *LArgTy = ConvertType(ArgTy); + const llvm::Type *LTy = ConvertType(DCE->getType()); + + bool CanBeZero = false; + bool ToVoid = false; + bool ThrowOnBad = false; + if (CastTy->isPointerType()) { + // FIXME: if PointerType->hasAttr(), we don't set this + CanBeZero = true; + if (InnerType->isVoidType()) + ToVoid = true; + } else { + LTy = LTy->getPointerTo(); + ThrowOnBad = true; + } + + CXXRecordDecl *SrcTy; + QualType Ty = ArgTy; + if (ArgTy.getTypePtr()->isPointerType() + || ArgTy.getTypePtr()->isReferenceType()) + Ty = Ty.getTypePtr()->getPointeeType(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + SrcTy = cast(Ty->getAs()->getDecl()); + + llvm::BasicBlock *ContBlock = createBasicBlock(); + llvm::BasicBlock *NullBlock = 0; + llvm::BasicBlock *NonZeroBlock = 0; + if (CanBeZero) { + NonZeroBlock = createBasicBlock(); + NullBlock = createBasicBlock(); + llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + NonZeroBlock, NullBlock); + EmitBlock(NonZeroBlock); + } + + llvm::BasicBlock *BadCastBlock = 0; + + const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); + + // See if this is a dynamic_cast(void*) + if (ToVoid) { + llvm::Value *This = V; + V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL); + V = Builder.CreateLoad(V, "offset to top"); + This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext)); + V = Builder.CreateInBoundsGEP(This, V); + V = Builder.CreateBitCast(V, LTy); + } else { + /// Call __dynamic_cast + const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext); + const llvm::FunctionType *FTy; + std::vector ArgTys; + const llvm::Type *PtrToInt8Ty + = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrDiffTy); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + CXXRecordDecl *DstTy; + Ty = CastTy.getTypePtr()->getPointeeType(); + CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + DstTy = cast(Ty->getAs()->getDecl()); + + // FIXME: Calculate better hint. + llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); + llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); + llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + V = Builder.CreateBitCast(V, PtrToInt8Ty); + V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), + V, SrcArg, DstArg, hint); + V = Builder.CreateBitCast(V, LTy); + + if (ThrowOnBad) { + BadCastBlock = createBasicBlock(); + + llvm::Value *Zero = llvm::Constant::getNullValue(LTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + ContBlock, BadCastBlock); + EmitBlock(BadCastBlock); + /// Call __cxa_bad_cast + ResultType = llvm::Type::getVoidTy(VMContext); + const llvm::FunctionType *FBadTy; + FBadTy = llvm::FunctionType::get(ResultType, false); + llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); + Builder.CreateCall(F)->setDoesNotReturn(); + Builder.CreateUnreachable(); + } + } + + if (CanBeZero) { + Builder.CreateBr(ContBlock); + EmitBlock(NullBlock); + Builder.CreateBr(ContBlock); + } + EmitBlock(ContBlock); + if (CanBeZero) { + llvm::PHINode *PHI = Builder.CreatePHI(LTy); + PHI->reserveOperandSpace(2); + PHI->addIncoming(V, NonZeroBlock); + PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); + V = PHI; + } + + return V; +} diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 9e81e4f..7fa8ffb 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -18,7 +18,6 @@ #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/Compiler.h" using namespace clang; using namespace CodeGen; @@ -29,7 +28,7 @@ using namespace CodeGen; typedef CodeGenFunction::ComplexPairTy ComplexPairTy; namespace { -class VISIBILITY_HIDDEN ComplexExprEmitter +class ComplexExprEmitter : public StmtVisitor { CodeGenFunction &CGF; CGBuilderTy &Builder; @@ -261,34 +260,18 @@ public: /// load the real and imaginary pieces, returning them as Real/Imag. ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile) { - llvm::SmallString<64> Name(SrcPtr->getName().begin(), - SrcPtr->getName().end()); - llvm::Value *Real=0, *Imag=0; if (!IgnoreReal) { - // FIXME: Clean this up once builder takes Twine/StringRef. - Name += ".realp"; - llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0, - Name.str().str().c_str()); - - Name.pop_back(); // .realp -> .real - // FIXME: Clean this up once builder takes Twine/StringRef. - Real = Builder.CreateLoad(RealPtr, isVolatile, - Name.str().str().c_str()); - Name.resize(Name.size()-4); // .real -> .imagp + llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0, + SrcPtr->getName() + ".realp"); + Real = Builder.CreateLoad(RealP, isVolatile, SrcPtr->getName() + ".real"); } if (!IgnoreImag) { - Name += "imagp"; - - // FIXME: Clean this up once builder takes Twine/StringRef. - llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1, - Name.str().str().c_str()); - - Name.pop_back(); // .imagp -> .imag - // FIXME: Clean this up once builder takes Twine/StringRef. - Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.str().str().c_str()); + llvm::Value *ImagP = Builder.CreateStructGEP(SrcPtr, 1, + SrcPtr->getName() + ".imagp"); + Imag = Builder.CreateLoad(ImagP, isVolatile, SrcPtr->getName() + ".imag"); } return ComplexPairTy(Real, Imag); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 40b845d..9289f78 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -22,14 +22,12 @@ #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" -#include "llvm/Support/Compiler.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; namespace { - -class VISIBILITY_HIDDEN ConstStructBuilder { +class ConstStructBuilder { CodeGenModule &CGM; CodeGenFunction *CGF; @@ -377,7 +375,7 @@ public: } }; -class VISIBILITY_HIDDEN ConstExprEmitter : +class ConstExprEmitter : public StmtVisitor { CodeGenModule &CGM; CodeGenFunction *CGF; @@ -413,9 +411,10 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); - Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1); + // The pointer is 1 + the virtual table offset in bytes. + Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); } else { llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD); @@ -673,7 +672,7 @@ public: if (ILE->getType()->isArrayType()) return EmitArrayInitialization(ILE); - if (ILE->getType()->isStructureType()) + if (ILE->getType()->isRecordType()) return EmitStructInitialization(ILE); if (ILE->getType()->isUnionType()) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index e9bbf35..c1cbecc 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -24,7 +24,6 @@ #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Module.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/CFG.h" #include "llvm/Target/TargetData.h" #include @@ -45,7 +44,7 @@ struct BinOpInfo { }; namespace { -class VISIBILITY_HIDDEN ScalarExprEmitter +class ScalarExprEmitter : public StmtVisitor { CodeGenFunction &CGF; CGBuilderTy &Builder; @@ -141,8 +140,11 @@ public: // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { - if (const EnumConstantDecl *EC = dyn_cast(E->getDecl())) - return llvm::ConstantInt::get(VMContext, EC->getInitVal()); + Expr::EvalResult Result; + if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) { + assert(!Result.HasSideEffects && "Constant declref with side-effect?!"); + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + } return EmitLoadOfLValue(E); } Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) { @@ -167,7 +169,7 @@ public: Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); - Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitMemberExpr(MemberExpr *E); Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); @@ -184,14 +186,14 @@ public: Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } - Value *VisitCastExpr(const CastExpr *E) { + Value *VisitCastExpr(CastExpr *E) { // Make sure to evaluate VLA bounds now so that we have them for later. if (E->getType()->isVariablyModifiedType()) CGF.EmitVLASize(E->getType()); return EmitCastExpr(E); } - Value *EmitCastExpr(const CastExpr *E); + Value *EmitCastExpr(CastExpr *E); Value *VisitCallExpr(const CallExpr *E) { if (E->getCallReturnType()->isReferenceType()) @@ -558,6 +560,17 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { Value* SV = llvm::ConstantVector::get(indices.begin(), indices.size()); return Builder.CreateShuffleVector(V1, V2, SV, "shuffle"); } +Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { + Expr::EvalResult Result; + if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) { + if (E->isArrow()) + CGF.EmitScalarExpr(E->getBase()); + else + EmitLValue(E->getBase()); + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + } + return EmitLoadOfLValue(E); +} Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { TestAndClearIgnoreResultAssign(); @@ -748,23 +761,40 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { return V; } +static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { + const Expr *E = CE->getSubExpr(); + + if (isa(E)) { + // We always assume that 'this' is never null. + return false; + } + + if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { + // And that lvalue casts are never null. + if (ICE->isLvalueCast()) + return false; + } + + return true; +} + // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. -Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { - const Expr *E = CE->getSubExpr(); +Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { + Expr *E = CE->getSubExpr(); QualType DestTy = CE->getType(); CastExpr::CastKind Kind = CE->getCastKind(); if (!DestTy->isVoidType()) TestAndClearIgnoreResultAssign(); + // Since almost all cast kinds apply to scalars, this switch doesn't have + // a default case, so the compiler will warn on a missing case. The cases + // are in the same order as in the CastKind enum. switch (Kind) { - default: - //return CGF.ErrorUnsupported(E, "type of cast"); - break; - case CastExpr::CK_Unknown: + // FIXME: All casts should have a known kind! //assert(0 && "Unknown cast kind!"); break; @@ -775,6 +805,18 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { case CastExpr::CK_NoOp: 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); + } case CastExpr::CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getType()->getAs()->getPointeeType()->getAs(); @@ -787,23 +829,19 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { Value *Src = Visit(const_cast(E)); - bool NullCheckValue = true; - - if (isa(E)) { - // We always assume that 'this' is never null. - NullCheckValue = false; - } else if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { - // And that lvalue casts are never null. - if (ICE->isLvalueCast()) - NullCheckValue = false; - } - return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, - NullCheckValue); + bool NullCheckValue = ShouldNullCheckClassCastValue(CE); + return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, + NullCheckValue); + } + case CastExpr::CK_Dynamic: { + Value *V = Visit(const_cast(E)); + const CXXDynamicCastExpr *DCE = cast(CE); + return CGF.EmitDynamicCast(V, DCE); } - case CastExpr::CK_ToUnion: { + case CastExpr::CK_ToUnion: assert(0 && "Should be unreachable!"); break; - } + case CastExpr::CK_ArrayToPointerDecay: { assert(E->getType()->isArrayType() && "Array to pointer decay must have array source type!"); @@ -828,6 +866,35 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { case CastExpr::CK_NullToMemberPointer: return CGF.CGM.EmitNullConstant(DestTy); + case CastExpr::CK_BaseToDerivedMemberPointer: + case CastExpr::CK_DerivedToBaseMemberPointer: { + Value *Src = Visit(E); + + // See if we need to adjust the pointer. + const CXXRecordDecl *BaseDecl = + cast(E->getType()->getAs()-> + getClass()->getAs()->getDecl()); + const CXXRecordDecl *DerivedDecl = + cast(CE->getType()->getAs()-> + getClass()->getAs()->getDecl()); + if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) + std::swap(DerivedDecl, BaseDecl); + + llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl); + if (Adj) { + if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) + Src = Builder.CreateSub(Src, Adj, "adj"); + else + Src = Builder.CreateAdd(Src, Adj, "adj"); + } + return Src; + } + + case CastExpr::CK_UserDefinedConversion: + case CastExpr::CK_ConstructorConversion: + assert(0 && "Should be unreachable!"); + break; + case CastExpr::CK_IntegralToPointer: { Value *Src = Visit(const_cast(E)); @@ -841,23 +908,14 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); } - case CastExpr::CK_PointerToIntegral: { Value *Src = Visit(const_cast(E)); return Builder.CreatePtrToInt(Src, ConvertType(DestTy)); } - case CastExpr::CK_ToVoid: { CGF.EmitAnyExpr(E, 0, false, true); return 0; } - - case CastExpr::CK_Dynamic: { - Value *V = Visit(const_cast(E)); - const CXXDynamicCastExpr *DCE = cast(CE); - return CGF.EmitDynamicCast(V, DCE); - } - case CastExpr::CK_VectorSplat: { const llvm::Type *DstTy = ConvertType(DestTy); Value *Elt = Visit(const_cast(E)); @@ -879,7 +937,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); return Yay; } + case CastExpr::CK_IntegralCast: + case CastExpr::CK_IntegralToFloating: + case CastExpr::CK_FloatingToIntegral: + case CastExpr::CK_FloatingCast: + return EmitScalarConversion(Visit(E), E->getType(), DestTy); + case CastExpr::CK_MemberPointerToBoolean: { + const MemberPointerType* T = E->getType()->getAs(); + + if (T->getPointeeType()->isFunctionType()) { + // We have a member function pointer. + llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType())); + + CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false); + + // Get the pointer. + llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); + FuncPtr = Builder.CreateLoad(FuncPtr); + + llvm::Value *IsNotNull = + Builder.CreateICmpNE(FuncPtr, + llvm::Constant::getNullValue(FuncPtr->getType()), + "tobool"); + + return IsNotNull; + } + + // We have a regular member pointer. + Value *Ptr = Visit(const_cast(E)); + llvm::Value *IsNotNull = + Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()), + "tobool"); + return IsNotNull; + } } // Handle cases where the source is an non-complex type. @@ -924,7 +1015,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { llvm::Value *V = CGF.GetAddrOfBlockDecl(E); if (E->getType().isObjCGCWeak()) return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V); - return Builder.CreateLoad(V, false, "tmp"); + return Builder.CreateLoad(V, "tmp"); } //===----------------------------------------------------------------------===// @@ -1583,10 +1674,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1633,13 +1724,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1753,7 +1844,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); } - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. @@ -1763,15 +1854,15 @@ VisitConditionalOperator(const ConditionalOperator *E) { else // Perform promotions, to handle cases like "short ?: int" LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); - CGF.PushConditionalTempDestruction(); + CGF.StartConditionalBranch(); CGF.EmitBlock(RHSBlock); Value *RHS = Visit(E->getRHS()); - CGF.PopConditionalTempDestruction(); + CGF.FinishConditionalBranch(); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index b431daa..be772c7 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -747,9 +747,14 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList( std::vector Elements; for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); iter != endIter ; iter++) { - llvm::Constant *protocol = ExistingProtocols[*iter]; - if (!protocol) + llvm::Constant *protocol = 0; + llvm::StringMap::iterator value = + ExistingProtocols.find(*iter); + if (value == ExistingProtocols.end()) { protocol = GenerateEmptyProtocol(*iter); + } else { + protocol = value->getValue(); + } llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol, PtrToInt8Ty); Elements.push_back(Ptr); @@ -1366,8 +1371,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { ConstantStrings.size() + 1); ConstantStrings.push_back(NULLPtr); - const char *StringClass = CGM.getLangOptions().ObjCConstantStringClass; - if (!StringClass) StringClass = "NXConstantString"; + llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass; + if (StringClass.empty()) StringClass = "NXConstantString"; Elements.push_back(MakeConstantString(StringClass, ".objc_static_class_name")); Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 4355e66..2e8ab29 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2993,7 +2993,7 @@ llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder, 4, true); } - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) { @@ -3009,7 +3009,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) { 4, true); } - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { @@ -4516,7 +4516,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName); if (PTGV) - return Builder.CreateLoad(PTGV, false, "tmp"); + return Builder.CreateLoad(PTGV, "tmp"); PTGV = new llvm::GlobalVariable( CGM.getModule(), Init->getType(), false, @@ -4526,7 +4526,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); - return Builder.CreateLoad(PTGV, false, "tmp"); + return Builder.CreateLoad(PTGV, "tmp"); } /// GenerateCategory - Build metadata for a category implementation. @@ -5031,8 +5031,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset( CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { - return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar), - false, "ivar"); + return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar"); } CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( @@ -5187,7 +5186,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, CGM.AddUsedGlobal(Entry); } - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } llvm::Value * @@ -5210,7 +5209,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, CGM.AddUsedGlobal(Entry); } - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } /// EmitMetaClassRef - Return a Value * of the address of _class_t @@ -5220,7 +5219,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()]; if (Entry) - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName); @@ -5236,7 +5235,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } /// GetClass - Return a reference to the class for the given interface @@ -5323,7 +5322,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, CGM.AddUsedGlobal(Entry); } - return Builder.CreateLoad(Entry, false, "tmp"); + return Builder.CreateLoad(Entry, "tmp"); } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. /// objc_assign_ivar (id src, id *dst, ptrdiff_t) diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index a63c832..1a9bc39 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -330,36 +330,6 @@ void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) { } -static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) { - const CXXRecordDecl *RD = dyn_cast(D); - if (!RD || !RD->isDynamicClass()) - return 0; - - 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; - - // FIXME: This doesn't work. If we have an out of line body, that body will - // set the MD to have a body, what we want to know is, was the body present - // inside the declaration of the class. For now, we just avoid the problem - // by pretending there is no key function. - return 0; - if (MD->getBody()) - continue; - - // We found it. - return MD; - } - - return 0; -} - CGRecordLayout * CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, const RecordDecl *D) { @@ -389,7 +359,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); } - const CXXMethodDecl *KeyFunction = GetKeyFunction(D); - - return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction); + return new CGRecordLayout(Ty, Builder.ContainsMemberPointer); } diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp index 79d8664..43fcb31 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRtti.cpp @@ -49,9 +49,8 @@ public: llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRttiName(CGM.getMangleContext(), Ty, Out); - llvm::StringRef Name = Out.str(); + CGM.getMangleContext().mangleCXXRttiName(Ty, OutName); + llvm::StringRef Name = OutName.str(); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; @@ -99,9 +98,8 @@ public: return llvm::Constant::getNullValue(Int8PtrTy); llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), Ty, Out); - llvm::StringRef Name = Out.str(); + CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + llvm::StringRef Name = OutName.str(); C = CGM.getModule().getGlobalVariable(Name); if (C) @@ -194,10 +192,9 @@ public: llvm::Constant *C; llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD), - Out); - llvm::StringRef Name = Out.str(); + CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD), + OutName); + llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; GV = CGM.getModule().getGlobalVariable(Name); @@ -260,13 +257,6 @@ public: return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); } - llvm::Constant *BuildType2(QualType Ty) { - if (const RecordType *RT = Ty.getTypePtr()->getAs()) - if (const CXXRecordDecl *RD = cast(RT->getDecl())) - return Buildclass_type_info(RD); - return BuildType(Ty); - } - bool DecideExtern(QualType Ty) { // For this type, see if all components are never in an anonymous namespace. if (const MemberPointerType *MPT = Ty->getAs()) @@ -297,9 +287,8 @@ public: llvm::Constant *C; llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), Ty, Out); - llvm::StringRef Name = Out.str(); + CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; GV = CGM.getModule().getGlobalVariable(Name); @@ -338,10 +327,10 @@ public: info.push_back(BuildInt(flags)); info.push_back(BuildInt(0)); - info.push_back(BuildType2(PTy)); + info.push_back(BuildType(PTy)); if (PtrMem) - info.push_back(BuildType2(BTy)); + info.push_back(BuildType(BTy)); // We always generate these as hidden, only the name isn't hidden. return finish(info, GV, Name, true, Extern); @@ -351,9 +340,8 @@ public: llvm::Constant *C; llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), Ty, Out); - llvm::StringRef Name = Out.str(); + CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; GV = CGM.getModule().getGlobalVariable(Name); @@ -376,6 +364,11 @@ public: llvm::Constant *BuildType(QualType Ty) { const clang::Type &Type = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); + + if (const RecordType *RT = Ty.getTypePtr()->getAs()) + if (const CXXRecordDecl *RD = cast(RT->getDecl())) + return Buildclass_type_info(RD); + switch (Type.getTypeClass()) { default: { assert(0 && "typeid expression"); @@ -426,7 +419,7 @@ llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { return b.Buildclass_type_info(RD); } -llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) { +llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) { RttiBuilder b(*this); return b.BuildType(Ty); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index b6d7b39..bbd5462 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -153,9 +153,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, } // Keep track of the current cleanup stack depth. - size_t CleanupStackDepth = CleanupEntries.size(); - bool OldDidCallStackSave = DidCallStackSave; - DidCallStackSave = false; + CleanupScope Scope(*this); for (CompoundStmt::const_body_iterator I = S.body_begin(), E = S.body_end()-GetLast; I != E; ++I) @@ -185,10 +183,6 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, RV = EmitAnyExpr(cast(LastStmt), AggLoc); } - DidCallStackSave = OldDidCallStackSave; - - EmitCleanupBlocks(CleanupStackDepth); - return RV; } @@ -294,6 +288,10 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // C99 6.8.4.1: The first substatement is executed if the expression compares // unequal to 0. The condition must be a scalar type. + CleanupScope ConditionScope(*this); + + if (S.getConditionVariable()) + EmitLocalBlockVarDecl(*S.getConditionVariable()); // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. @@ -306,8 +304,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // If the skipped block has no labels in it, just emit the executed block. // This avoids emitting dead code and simplifies the CFG substantially. if (!ContainsLabel(Skipped)) { - if (Executed) + if (Executed) { + CleanupScope ExecutedScope(*this); EmitStmt(Executed); + } return; } } @@ -322,14 +322,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock); // Emit the 'then' code. - EmitBlock(ThenBlock); - EmitStmt(S.getThen()); + EmitBlock(ThenBlock); + { + CleanupScope ThenScope(*this); + EmitStmt(S.getThen()); + } EmitBranch(ContBlock); // Emit the 'else' code if present. if (const Stmt *Else = S.getElse()) { EmitBlock(ElseBlock); - EmitStmt(Else); + { + CleanupScope ElseScope(*this); + EmitStmt(Else); + } EmitBranch(ContBlock); } @@ -347,15 +353,37 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // body of the loop. llvm::BasicBlock *ExitBlock = createBasicBlock("while.end"); llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); + llvm::BasicBlock *CleanupBlock = 0; + llvm::BasicBlock *EffectiveExitBlock = ExitBlock; // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader)); + // C++ [stmt.while]p2: + // When the condition of a while statement is a declaration, the + // scope of the variable that is declared extends from its point + // of declaration (3.3.2) to the end of the while statement. + // [...] + // The object created in a condition is destroyed and created + // with each iteration of the loop. + CleanupScope ConditionScope(*this); + + if (S.getConditionVariable()) { + EmitLocalBlockVarDecl(*S.getConditionVariable()); + + // If this condition variable requires cleanups, create a basic + // block to handle those cleanups. + if (ConditionScope.requiresCleanups()) { + CleanupBlock = createBasicBlock("while.cleanup"); + EffectiveExitBlock = CleanupBlock; + } + } + // Evaluate the conditional in the while header. C99 6.8.5.1: The // evaluation of the controlling expression takes place before each // execution of the loop body. llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); - + // while(1) is common, avoid extra exit blocks. Be sure // to correctly handle break/continue though. bool EmitBoolCondBranch = true; @@ -365,23 +393,39 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // As long as the condition is true, go to the loop body. if (EmitBoolCondBranch) - Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); - + Builder.CreateCondBr(BoolCondVal, LoopBody, EffectiveExitBlock); + // Emit the loop body. - EmitBlock(LoopBody); - EmitStmt(S.getBody()); + { + CleanupScope BodyScope(*this); + EmitBlock(LoopBody); + EmitStmt(S.getBody()); + } BreakContinueStack.pop_back(); - // Cycle to the condition. - EmitBranch(LoopHeader); + if (CleanupBlock) { + // If we have a cleanup block, jump there to perform cleanups + // before looping. + EmitBranch(CleanupBlock); + + // Emit the cleanup block, performing cleanups for the condition + // and then jumping to either the loop header or the exit block. + EmitBlock(CleanupBlock); + ConditionScope.ForceCleanup(); + Builder.CreateCondBr(BoolCondVal, LoopHeader, ExitBlock); + } else { + // Cycle to the condition. + EmitBranch(LoopHeader); + } // Emit the exit block. EmitBlock(ExitBlock, true); + // The LoopHeader typically is just a branch if we skipped emitting // a branch, try to erase it. - if (!EmitBoolCondBranch) + if (!EmitBoolCondBranch && !CleanupBlock) SimplifyForwardingBlocks(LoopHeader); } @@ -435,6 +479,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { void CodeGenFunction::EmitForStmt(const ForStmt &S) { // FIXME: What do we do if the increment (f.e.) contains a stmt expression, // which contains a continue/break? + CleanupScope ForScope(*this); // Evaluate the first part before the loop. if (S.getInit()) @@ -443,18 +488,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // Start the loop with a block that tests the condition. llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - + llvm::BasicBlock *IncBlock = 0; + llvm::BasicBlock *CondCleanup = 0; + llvm::BasicBlock *EffectiveExitBlock = AfterFor; EmitBlock(CondBlock); - // Evaluate the condition if present. If not, treat it as a - // non-zero-constant according to 6.8.5.3p2, aka, true. + // Create a cleanup scope for the condition variable cleanups. + CleanupScope ConditionScope(*this); + + llvm::Value *BoolCondVal = 0; if (S.getCond()) { + // If the for statement has a condition scope, emit the local variable + // declaration. + if (S.getConditionVariable()) { + EmitLocalBlockVarDecl(*S.getConditionVariable()); + + if (ConditionScope.requiresCleanups()) { + CondCleanup = createBasicBlock("for.cond.cleanup"); + EffectiveExitBlock = CondCleanup; + } + } + // As long as the condition is true, iterate the loop. llvm::BasicBlock *ForBody = createBasicBlock("for.body"); // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. - EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor); + BoolCondVal = EvaluateExprAsBool(S.getCond()); + Builder.CreateCondBr(BoolCondVal, ForBody, EffectiveExitBlock); EmitBlock(ForBody); } else { @@ -466,7 +527,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // condition as the continue block. llvm::BasicBlock *ContinueBlock; if (S.getInc()) - ContinueBlock = createBasicBlock("for.inc"); + ContinueBlock = IncBlock = createBasicBlock("for.inc"); else ContinueBlock = CondBlock; @@ -479,18 +540,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { DI->setLocation(S.getSourceRange().getBegin()); DI->EmitRegionStart(CurFn, Builder); } - EmitStmt(S.getBody()); + + { + // Create a separate cleanup scope for the body, in case it is not + // a compound statement. + CleanupScope BodyScope(*this); + EmitStmt(S.getBody()); + } BreakContinueStack.pop_back(); // If there is an increment, emit it next. if (S.getInc()) { - EmitBlock(ContinueBlock); + EmitBlock(IncBlock); EmitStmt(S.getInc()); } // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); + if (CondCleanup) { + // Branch to the cleanup block. + EmitBranch(CondCleanup); + + // Emit the cleanup block, which branches back to the loop body or + // outside of the for statement once it is done. + EmitBlock(CondCleanup); + ConditionScope.ForceCleanup(); + Builder.CreateCondBr(BoolCondVal, CondBlock, AfterFor); + } else + EmitBranch(CondBlock); if (DI) { DI->setLocation(S.getSourceRange().getEnd()); DI->EmitRegionEnd(CurFn, Builder); @@ -686,6 +763,11 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { } void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { + CleanupScope ConditionScope(*this); + + if (S.getConditionVariable()) + EmitLocalBlockVarDecl(*S.getConditionVariable()); + llvm::Value *CondV = EmitScalarExpr(S.getCond()); // Handle nested switch statements. diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp new file mode 100644 index 0000000..5cfc7ef --- /dev/null +++ b/lib/CodeGen/CGTemporaries.cpp @@ -0,0 +1,143 @@ +//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===// +// +// 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 temporaries +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, + llvm::Value *Ptr) { + llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); + + llvm::Value *CondPtr = 0; + + // Check if temporaries need to be conditional. If so, we'll create a + // condition boolean, initialize it to 0 and + if (ConditionalBranchLevel != 0) { + CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond"); + + // 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); + + // Now set it to true. + Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); + } + + LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, + CondPtr)); + + PushCleanupBlock(DtorBlock); +} + +void CodeGenFunction::PopCXXTemporary() { + const CXXLiveTemporaryInfo& Info = LiveTemporaries.back(); + + CleanupBlockInfo CleanupInfo = PopCleanupBlock(); + assert(CleanupInfo.CleanupBlock == Info.DtorBlock && + "Cleanup block mismatch!"); + assert(!CleanupInfo.SwitchBlock && + "Should not have a switch block for temporary cleanup!"); + assert(!CleanupInfo.EndBlock && + "Should not have an end block for temporary cleanup!"); + + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + if (CurBB && !CurBB->getTerminator() && + Info.DtorBlock->getNumUses() == 0) { + CurBB->getInstList().splice(CurBB->end(), Info.DtorBlock->getInstList()); + delete Info.DtorBlock; + } else + EmitBlock(Info.DtorBlock); + + llvm::BasicBlock *CondEnd = 0; + + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (Info.CondPtr) { + llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); + CondEnd = createBasicBlock("cond.dtor.end"); + + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); + Builder.CreateCondBr(Cond, CondBlock, CondEnd); + EmitBlock(CondBlock); + } + + EmitCXXDestructorCall(Info.Temporary->getDestructor(), + Dtor_Complete, Info.ThisPtr); + + if (CondEnd) { + // Reset the condition. to false. + Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), Info.CondPtr); + EmitBlock(CondEnd); + } + + LiveTemporaries.pop_back(); +} + +RValue +CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, + llvm::Value *AggLoc, + bool IsAggLocVolatile, + bool IsInitializer) { + // If we shouldn't destroy the temporaries, just emit the + // child expression. + if (!E->shouldDestroyTemporaries()) + return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); + + // Keep track of the current cleanup stack depth. + size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; + + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + /*IgnoreResult=*/false, IsInitializer); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return RV; +} + +LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( + const CXXExprWithTemporaries *E) { + // If we shouldn't destroy the temporaries, just emit the + // child expression. + if (!E->shouldDestroyTemporaries()) + return EmitLValue(E->getSubExpr()); + + // Keep track of the current cleanup stack depth. + size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; + + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + LValue LV = EmitLValue(E->getSubExpr()); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return LV; +} diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 9be1a3b..715aa4c 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -13,13 +13,15 @@ #include "CodeGenModule.h" #include "CodeGenFunction.h" - +#include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" +#include "llvm/ADT/DenseSet.h" #include using namespace clang; using namespace CodeGen; +namespace { class VtableBuilder { public: /// Index_t - Vtable index type. @@ -52,54 +54,110 @@ private: llvm::DenseMap NonVirtualOffset; llvm::DenseMap VBIndex; - typedef llvm::DenseMap Pures_t; - Pures_t Pures; - typedef std::pair CallOffset; - typedef llvm::DenseMap Thunks_t; - Thunks_t Thunks; - typedef llvm::DenseMap, - CanQualType> > CovariantThunks_t; - CovariantThunks_t CovariantThunks; + /// PureVirtualFunction - Points to __cxa_pure_virtual. + llvm::Constant *PureVirtualFn; + + /// Thunk - Represents a single thunk. + struct Thunk { + Thunk() + : Index(0) { } + + Thunk(uint64_t Index, const ThunkAdjustment &Adjustment) + : Index(Index), Adjustment(Adjustment) { } + + /// Index - The index in the vtable. + uint64_t Index; + + /// Adjustment - The thunk adjustment. + ThunkAdjustment Adjustment; + }; + + /// Thunks - The thunks in a vtable. + typedef llvm::DenseMap ThunksMapTy; + ThunksMapTy Thunks; + + /// CovariantThunk - Represents a single covariant thunk. + struct CovariantThunk { + CovariantThunk() + : Index(0) { } + + CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment, + const ThunkAdjustment &ReturnAdjustment, + CanQualType ReturnType) + : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment), + ReturnType(ReturnType) { } + + // Index - The index in the vtable. + uint64_t Index; + + /// Adjustment - The covariant thunk adjustment. + CovariantThunkAdjustment Adjustment; + + /// ReturnType - The return type of the function. + CanQualType ReturnType; + }; + + /// CovariantThunks - The covariant thunks in a vtable. + typedef llvm::DenseMap CovariantThunksMapTy; + CovariantThunksMapTy CovariantThunks; + + /// PureVirtualMethods - Pure virtual methods. + typedef llvm::DenseSet PureVirtualMethodsSetTy; + PureVirtualMethodsSetTy PureVirtualMethods; + std::vector VCalls; typedef std::pair CtorVtable_t; - // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable - // for use in computing the initializers for the VTT. - llvm::DenseMap &AddressPoints; + // subAddressPoints - Used to hold the AddressPoints (offsets) into the built + // vtable for use in computing the initializers for the VTT. + llvm::DenseMap &subAddressPoints; typedef CXXRecordDecl::method_iterator method_iter; const bool Extern; const uint32_t LLVMPointerWidth; Index_t extra; typedef std::vector > Path_t; - llvm::Constant *cxa_pure; + static llvm::DenseMap& + AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l, + const CXXRecordDecl *c) { + CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l]; + if (oref == 0) + oref = new CodeGenModule::AddrMap_t; + + llvm::DenseMap *&ref = (*oref)[c]; + if (ref == 0) + ref = new llvm::DenseMap; + return *ref; + } + + /// getPureVirtualFn - Return the __cxa_pure_virtual function. + llvm::Constant* getPureVirtualFn() { + if (!PureVirtualFn) { + const llvm::FunctionType *Ty = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + /*isVarArg=*/false); + PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual")); + } + + return PureVirtualFn; + } + public: VtableBuilder(std::vector &meth, const CXXRecordDecl *c, const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm) : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)), rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()), - CGM(cgm), AddressPoints(*new llvm::DenseMap), + CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)), Extern(!l->isInAnonymousNamespace()), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - - // Calculate pointer for ___cxa_pure_virtual. - const llvm::FunctionType *FTy; - std::vector ArgTys; - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual")); } llvm::DenseMap &getIndex() { return Index; } llvm::DenseMap &getVBIndex() { return VBIndex; } - llvm::DenseMap *getAddressPoints() - { return &AddressPoints; } - llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -147,8 +205,6 @@ public: SeenVBase.clear(); } - Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B); - Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B, Index_t Offset = 0) { @@ -194,7 +250,7 @@ public: CXXRecordDecl *D = cast(qD->getAs()->getDecl()); CXXRecordDecl *B = cast(qB->getAs()->getDecl()); if (D != Class) - return VBlookup(D, B); + return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); llvm::DenseMap::iterator i; i = VBIndex.find(B); if (i != VBIndex.end()) @@ -242,22 +298,23 @@ public: CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); QualType nc_ret = MD->getType()->getAs()->getResultType(); CanQualType ret = CGM.getContext().getCanonicalType(nc_ret); - CallOffset ReturnOffset = std::make_pair(0, 0); + ThunkAdjustment ReturnAdjustment; if (oret != ret) { // FIXME: calculate offsets for covariance - if (CovariantThunks.count(OMD)) { - oret = CovariantThunks[OMD].second; - CovariantThunks.erase(OMD); + CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD); + if (i != CovariantThunks.end()) { + oret = i->second.ReturnType; + CovariantThunks.erase(i); } // FIXME: Double check oret Index_t nv = getNVOffset(oret, ret)/8; - ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret)); + ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret)); } Index[GD] = i; submethods[i] = m; if (isPure) - Pures[GD] = 1; - Pures.erase(OGD); + PureVirtualMethods.insert(GD); + PureVirtualMethods.erase(OGD); Thunks.erase(OGD); if (MorallyVirtual || VCall.count(OGD)) { Index_t &idx = VCall[OGD]; @@ -278,35 +335,38 @@ public: (int)VCalls[idx-1], Class->getNameAsCString())); } VCall[GD] = idx; - int64_t O = NonVirtualOffset[GD]; - int v = -((idx+extra+2)*LLVMPointerWidth/8); + int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; + int64_t VirtualAdjustment = + -((idx + extra + 2) * LLVMPointerWidth / 8); + // Optimize out virtual adjustments of 0. if (VCalls[idx-1] == 0) - v = 0; - CallOffset ThisOffset = std::make_pair(O, v); + VirtualAdjustment = 0; + + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + // FIXME: Do we always have to build a covariant thunk to save oret, // which is the containing virtual base class? - if (ReturnOffset.first || ReturnOffset.second) - CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset, - ReturnOffset), - oret); - else if (!isPure && (ThisOffset.first || ThisOffset.second)) - Thunks[GD] = ThisOffset; + if (!ReturnAdjustment.isEmpty()) { + CovariantThunks[GD] = + CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); + } else if (!isPure && !ThisAdjustment.isEmpty()) + Thunks[GD] = Thunk(i, ThisAdjustment); return true; } // FIXME: finish off - int64_t O = VCallOffset[OGD] - OverrideOffset/8; + int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8; - if (O || ReturnOffset.first || ReturnOffset.second) { - CallOffset ThisOffset = std::make_pair(O, 0); + if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) { + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); - if (ReturnOffset.first || ReturnOffset.second) - CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset, - ReturnOffset), - oret); - else if (!isPure) - Thunks[GD] = ThisOffset; + if (!ReturnAdjustment.isEmpty()) { + CovariantThunks[GD] = + CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); + } else if (!isPure) + Thunks[GD] = Thunk(i, ThisAdjustment); } return true; } @@ -316,40 +376,39 @@ public: } void InstallThunks() { - for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); + for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end(); i != e; ++i) { GlobalDecl GD = i->first; const CXXMethodDecl *MD = cast(GD.getDecl()); - assert(!MD->isPure() && "Trying to thunk a pure"); - Index_t idx = Index[GD]; - Index_t nv_O = i->second.first; - Index_t v_O = i->second.second; - submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O); + assert(!MD->isPure() && "Can't thunk pure virtual methods!"); + + const Thunk& Thunk = i->second; + assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); + + submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment); } Thunks.clear(); - for (CovariantThunks_t::iterator i = CovariantThunks.begin(), - e = CovariantThunks.end(); - i != e; ++i) { + + for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(), + e = CovariantThunks.end(); i != e; ++i) { GlobalDecl GD = i->first; const CXXMethodDecl *MD = cast(GD.getDecl()); if (MD->isPure()) continue; - Index_t idx = Index[GD]; - Index_t nv_t = i->second.first.first.first; - Index_t v_t = i->second.first.first.second; - Index_t nv_r = i->second.first.second.first; - Index_t v_r = i->second.first.second.second; - submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r, - v_r); + + const CovariantThunk &Thunk = i->second; + assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); + submethods[Thunk.Index] = + CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment); } CovariantThunks.clear(); - for (Pures_t::iterator i = Pures.begin(), e = Pures.end(); - i != e; ++i) { - GlobalDecl GD = i->first; - Index_t idx = Index[GD]; - submethods[idx] = cxa_pure; + + for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(), + e = PureVirtualMethods.end(); i != e; ++i) { + GlobalDecl GD = *i; + submethods[Index[GD]] = getPureVirtualFn(); } - Pures.clear(); + PureVirtualMethods.clear(); } llvm::Constant *WrapAddrOf(GlobalDecl GD) { @@ -358,10 +417,7 @@ public: if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType())); - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); return wrap(CGM.GetAddrOfFunction(MD, Ty)); } @@ -397,7 +453,7 @@ public: } void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, - bool ForVirtualBase, int64_t CurrentVBaseOffset) { + int64_t CurrentVBaseOffset) { llvm::Constant *m = WrapAddrOf(GD); // If we can find a previously allocated slot for this, reuse it. @@ -413,7 +469,7 @@ public: D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), (int)Index[GD])); if (MD->isPure()) - Pures[GD] = 1; + PureVirtualMethods.insert(GD); if (MorallyVirtual) { VCallOffset[GD] = Offset/8; Index_t &idx = VCall[GD]; @@ -429,8 +485,7 @@ public: } void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset, bool RDisVirtualBase, - int64_t CurrentVBaseOffset) { + Index_t Offset, int64_t CurrentVBaseOffset) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) { const CXXMethodDecl *MD = *mi; @@ -441,12 +496,11 @@ public: // For destructors, add both the complete and the deleting destructor // to the vtable. AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset, - RDisVirtualBase, CurrentVBaseOffset); + CurrentVBaseOffset); AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset, - RDisVirtualBase, CurrentVBaseOffset); - } else - AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset); + } else + AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset); } } @@ -495,7 +549,7 @@ public: D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", RD->getNameAsCString(), Class->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); - AddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; // Now also add the address point for all our primary bases. while (1) { @@ -511,7 +565,7 @@ public: D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", RD->getNameAsCString(), Class->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); - AddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; } } @@ -572,7 +626,7 @@ public: void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, bool updateVBIndex, Index_t current_vbindex, - bool RDisVirtualBase, int64_t CurrentVBaseOffset) { + int64_t CurrentVBaseOffset) { if (!RD->isDynamicClass()) return; @@ -591,21 +645,20 @@ public: if (!PrimaryBaseWasVirtual) Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, - BaseCurrentVBaseOffset); + updateVBIndex, current_vbindex, BaseCurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset); + AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset); } void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, bool updateVBIndex, Index_t current_vbindex, bool RDisVirtualBase, int64_t CurrentVBaseOffset, - bool bottom=false) { + bool bottom) { if (!RD->isDynamicClass()) return; @@ -626,7 +679,7 @@ public: VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, - BaseCurrentVBaseOffset); + BaseCurrentVBaseOffset, false); } D1(printf(" doing vbase entries for %s most derived %s\n", @@ -635,7 +688,7 @@ public: if (RDisVirtualBase || bottom) { Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, - RDisVirtualBase, CurrentVBaseOffset); + CurrentVBaseOffset); } } @@ -718,30 +771,223 @@ public: } }; +} + +/// TypeConversionRequiresAdjustment - Returns whether conversion from a +/// derived type to a base type requires adjustment. +static bool +TypeConversionRequiresAdjustment(ASTContext &Ctx, + const CXXRecordDecl *DerivedDecl, + const CXXRecordDecl *BaseDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + if (!const_cast(DerivedDecl)-> + isDerivedFrom(const_cast(BaseDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return false; + } + + // If we found a virtual base we always want to require adjustment. + if (Paths.getDetectedVirtual()) + return true; + + const CXXBasePath &Path = Paths.front(); + + for (size_t Start = 0, End = Path.size(); Start != End; ++Start) { + const CXXBasePathElement &Element = Path[Start]; + + // Check the base class offset. + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); + + const RecordType *BaseType = Element.Base->getType()->getAs(); + const CXXRecordDecl *Base = cast(BaseType->getDecl()); + + if (Layout.getBaseClassOffset(Base) != 0) { + // This requires an adjustment. + return true; + } + } + + return false; +} + +static bool +TypeConversionRequiresAdjustment(ASTContext &Ctx, + QualType DerivedType, QualType BaseType) { + // Canonicalize the types. + QualType CanDerivedType = Ctx.getCanonicalType(DerivedType); + QualType CanBaseType = Ctx.getCanonicalType(BaseType); + + assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() && + "Types must have same type class!"); + + if (CanDerivedType == CanBaseType) { + // No adjustment needed. + return false; + } + + if (const ReferenceType *RT = dyn_cast(CanDerivedType)) { + CanDerivedType = RT->getPointeeType(); + CanBaseType = cast(CanBaseType)->getPointeeType(); + } else if (const PointerType *PT = dyn_cast(CanDerivedType)) { + CanDerivedType = PT->getPointeeType(); + CanBaseType = cast(CanBaseType)->getPointeeType(); + } else { + assert(false && "Unexpected return type!"); + } + + if (CanDerivedType == CanBaseType) { + // No adjustment needed. + return false; + } + + const CXXRecordDecl *DerivedDecl = + cast(cast(CanDerivedType)->getDecl()); + + const CXXRecordDecl *BaseDecl = + cast(cast(CanBaseType)->getDecl()); + + return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); +} + +void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { + + // Itanium C++ ABI 2.5.2: + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. + // + // 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!"); -VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D, - CXXRecordDecl *B) { - return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); + // 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); + } + + 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; + + bool ShouldAddEntryForMethod = true; + + // Check if this method overrides a method in the primary base. + for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); i != e; ++i) { + const CXXMethodDecl *OverriddenMD = *i; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + assert(OverriddenMD->isCanonicalDecl() && + "Should have the canonical decl of the overridden RD!"); + + if (OverriddenRD == PrimaryBase) { + // Check if converting from the return type of the method to the + // return type of the overridden method requires conversion. + QualType ReturnType = + MD->getType()->getAs()->getResultType(); + QualType OverriddenReturnType = + OverriddenMD->getType()->getAs()->getResultType(); + + if (!TypeConversionRequiresAdjustment(CGM.getContext(), + ReturnType, OverriddenReturnType)) { + // This index is shared between the index in the vtable of the primary + // base class. + if (const CXXDestructorDecl *DD = dyn_cast(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. + ShouldAddEntryForMethod = false; + break; + } + } + } + + if (!ShouldAddEntryForMethod) + 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; } -int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { +uint64_t CGVtableInfo::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 CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); if (I != MethodVtableIndices.end()) return I->second; const CXXRecordDecl *RD = cast(GD.getDecl())->getParent(); - - std::vector methods; - // FIXME: This seems expensive. Can we do a partial job to get - // just this data. - VtableBuilder b(methods, RD, RD, 0, CGM); - D1(printf("vtable %s\n", RD->getNameAsCString())); - b.GenerateVtableForBase(RD); - b.GenerateVtableForVBases(RD); - - MethodVtableIndices.insert(b.getIndex().begin(), - b.getIndex().end()); - + + ComputeMethodVtableIndices(RD); + I = MethodVtableIndices.find(GD); assert(I != MethodVtableIndices.end() && "Did not find index!"); return I->second; @@ -782,22 +1028,25 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, const CXXRecordDecl *RD, uint64_t Offset) { llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); if (LayoutClass != RD) - mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out); + getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName); else - mangleCXXVtable(getMangleContext(), RD, Out); - llvm::StringRef Name = Out.str(); + getMangleContext().mangleCXXVtable(RD, OutName); + llvm::StringRef Name = OutName.str(); std::vector methods; llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name); - if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) + if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) { AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, Offset)]; - else { + // FIXME: We can never have 0 address point. Do this for now so gepping + // retains the same structure. Later, we'll just assert. + if (AddressPoint == 0) + AddressPoint = 1; + } else { VtableBuilder b(methods, RD, LayoutClass, Offset, *this); D1(printf("vtable %s\n", RD->getNameAsCString())); @@ -807,20 +1056,14 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, // then the vtables for all the virtual bases. b.GenerateVtableForVBases(RD, Offset); - CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass]; - if (ref == 0) - ref = new CodeGenModule::AddrMap_t; - - (*ref)[RD] = b.getAddressPoints(); - bool CreateDefinition = true; if (LayoutClass != RD) CreateDefinition = true; else { - // We have to convert it to have a record layout. - Types.ConvertTagDeclType(LayoutClass); - const CGRecordLayout &CGLayout = Types.getCGRecordLayout(LayoutClass); - if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + const ASTRecordLayout &Layout = + getContext().getASTRecordLayout(LayoutClass); + + if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { if (!KeyFunction->getBody()) { // If there is a KeyFunction, and it isn't defined, just build a // reference to the vtable. @@ -862,6 +1105,7 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC, 1); + assert(vtable->getType() == Ptr8Ty); return vtable; } @@ -888,7 +1132,7 @@ class VTTBuilder { int64_t AddressPoint; AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)]; // FIXME: We can never have 0 address point. Do this for now so gepping - // retains the same structure. + // retains the same structure. Later we'll just assert. if (AddressPoint == 0) AddressPoint = 1; D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", @@ -1034,9 +1278,8 @@ llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { return 0; llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXVTT(getMangleContext(), RD, Out); - llvm::StringRef Name = Out.str(); + getMangleContext().mangleCXXVTT(RD, OutName); + llvm::StringRef Name = OutName.str(); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; @@ -1073,10 +1316,9 @@ llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { vtbl = CGM.GenerateVtable(RD, RD); bool CreateDefinition = true; - // We have to convert it to have a record layout. - CGM.getTypes().ConvertTagDeclType(RD); - const CGRecordLayout &CGLayout = CGM.getTypes().getCGRecordLayout(RD); - if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { if (!KeyFunction->getBody()) { // If there is a KeyFunction, and it isn't defined, just build a // reference to the vtable. @@ -1096,3 +1338,31 @@ llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, uint64_t Offset) { return CGM.GenerateVtable(LayoutClass, RD, Offset); } + +void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const CXXRecordDecl *RD = MD->getParent(); + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + // Get the key function. + const CXXMethodDecl *KeyFunction = Layout.getKeyFunction(); + + if (!KeyFunction) { + // If there's no key function, we don't want to emit the vtable here. + return; + } + + // Check if we have the key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + + // If the key function is a destructor, we only want to emit the vtable once, + // so do it for the complete destructor. + if (isa(MD) && GD.getDtorType() != Dtor_Complete) + return; + + // Emit the data. + GenerateClassData(RD); +} + diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 78ae670..5c2b74c 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -17,56 +17,110 @@ #include "llvm/ADT/DenseMap.h" #include "GlobalDecl.h" +namespace llvm { + class Constant; +} + namespace clang { - class CXXMethodDecl; class CXXRecordDecl; - + namespace CodeGen { class CodeGenModule; - + +/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks. +class ThunkAdjustment { +public: + ThunkAdjustment(int64_t NonVirtual, int64_t Virtual) + : NonVirtual(NonVirtual), + Virtual(Virtual) { } + + ThunkAdjustment() + : NonVirtual(0), Virtual(0) { } + + // isEmpty - Return whether this thunk adjustment is empty. + bool isEmpty() const { + return NonVirtual == 0 && Virtual == 0; + } + + /// NonVirtual - The non-virtual adjustment. + int64_t NonVirtual; + + /// Virtual - The virtual adjustment. + int64_t Virtual; +}; + +/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the +/// return pointer for covariant thunks. +class CovariantThunkAdjustment { +public: + CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment, + const ThunkAdjustment &ReturnAdjustment) + : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { } + + CovariantThunkAdjustment() { } + + ThunkAdjustment ThisAdjustment; + ThunkAdjustment ReturnAdjustment; +}; + class CGVtableInfo { 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; - + /// VirtualBaseClassIndicies - Contains the index into the vtable where the /// offsets for virtual bases of a class are stored. typedef llvm::DenseMap VirtualBaseClassIndiciesTy; VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; llvm::DenseMap Vtables; + + /// NumVirtualFunctionPointers - Contains the number of virtual function + /// pointers in the vtable for a given record decl. + llvm::DenseMap NumVirtualFunctionPointers; + + /// 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); + + /// GenerateClassData - Generate all the class data requires to be generated + /// upon definition of a KeyFunction. This includes the vtable, the + /// rtti data structure and the VTT. + void GenerateClassData(const CXXRecordDecl *RD); + public: - CGVtableInfo(CodeGenModule &CGM) + CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } /// getMethodVtableIndex - Return the index (relative to the vtable address - /// point) where the function pointer for the given virtual function is + /// point) where the function pointer for the given virtual function is /// stored. - int64_t getMethodVtableIndex(GlobalDecl GD); - + uint64_t getMethodVtableIndex(GlobalDecl GD); + /// getVirtualBaseOffsetIndex - Return the index (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 getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, + int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); llvm::Constant *getVtable(const CXXRecordDecl *RD); llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset); - /// GenerateClassData - Generate all the class data requires to be generated - /// upon definition of a KeyFunction. This includes the vtable, the - /// rtti data structure and the VTT. - void GenerateClassData(const CXXRecordDecl *RD); -}; + + void MaybeEmitVtable(GlobalDecl GD); +}; + } } #endif diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 10884a7..9281416 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -3,11 +3,9 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangCodeGen CGBlocks.cpp CGBuiltin.cpp - CGCXX.cpp - CGCXXClass.cpp - CGCXXExpr.cpp - CGCXXTemp.cpp CGCall.cpp + CGClass.cpp + CGCXX.cpp CGDebugInfo.cpp CGDecl.cpp CGException.cpp @@ -15,6 +13,7 @@ add_clang_library(clangCodeGen CGExprAgg.cpp CGExprComplex.cpp CGExprConstant.cpp + CGExprCXX.cpp CGExprScalar.cpp CGObjC.cpp CGObjCGNU.cpp @@ -22,6 +21,7 @@ add_clang_library(clangCodeGen CGRecordLayoutBuilder.cpp CGRtti.cpp CGStmt.cpp + CGTemporaries.cpp CGVtable.cpp CodeGenFunction.cpp CodeGenModule.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 475c7bf..6e0a77c 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -29,7 +29,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Builder(cgm.getModule().getContext()), DebugInfo(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), - CXXThisDecl(0) { + CXXThisDecl(0), CXXVTTDecl(0), + ConditionalBranchLevel(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); } @@ -216,6 +217,24 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } +static bool NeedsVTTParameter(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // We don't have any virtual bases, just return early. + if (!MD->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa(MD) && GD.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa(MD) && GD.getDtorType() == Dtor_Base) + return true; + + return false; +} + void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { const FunctionDecl *FD = cast(GD.getDecl()); @@ -235,6 +254,16 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, &getContext().Idents.get("this"), MD->getThisType(getContext())); Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); + + // Check if we need a VTT parameter as well. + if (NeedsVTTParameter(GD)) { + // FIXME: The comment about using a fake decl above applies here too. + QualType T = getContext().getPointerType(getContext().VoidPtrTy); + CXXVTTDecl = + ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), + &getContext().Idents.get("vtt"), T); + Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType())); + } } } @@ -317,6 +346,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, // Destroy the 'this' declaration. if (CXXThisDecl) CXXThisDecl->Destroy(getContext()); + + // Destroy the VTT declaration. + if (CXXVTTDecl) + CXXVTTDecl->Destroy(getContext()); } /// ContainsLabel - Return true if the statement contains a label in it. If diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index d96c355..7f32045 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -133,17 +133,17 @@ public: /// block. CleanupBlockInfo PopCleanupBlock(); - /// CleanupScope - RAII object that will create a cleanup block and set the - /// insert point to that block. When destructed, it sets the insert point to - /// the previous block and pushes a new cleanup entry on the stack. - class CleanupScope { + /// DelayedCleanupBlock - RAII object that will create a cleanup block and set + /// the insert point to that block. When destructed, it sets the insert point + /// to the previous block and pushes a new cleanup entry on the stack. + class DelayedCleanupBlock { CodeGenFunction& CGF; llvm::BasicBlock *CurBB; llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *CleanupExitBB; public: - CleanupScope(CodeGenFunction &cgf) + DelayedCleanupBlock(CodeGenFunction &cgf) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) { CGF.Builder.SetInsertPoint(CleanupEntryBB); @@ -155,7 +155,7 @@ public: return CleanupExitBB; } - ~CleanupScope() { + ~DelayedCleanupBlock() { CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB); // FIXME: This is silly, move this into the builder. if (CurBB) @@ -165,6 +165,50 @@ public: } }; + /// \brief Enters a new scope for capturing cleanups, all of which will be + /// executed once the scope is exited. + class CleanupScope { + CodeGenFunction& CGF; + size_t CleanupStackDepth; + bool OldDidCallStackSave; + bool PerformCleanup; + + CleanupScope(const CleanupScope &); // DO NOT IMPLEMENT + CleanupScope &operator=(const CleanupScope &); // DO NOT IMPLEMENT + + public: + /// \brief Enter a new cleanup scope. + explicit CleanupScope(CodeGenFunction &CGF) + : CGF(CGF), PerformCleanup(true) + { + CleanupStackDepth = CGF.CleanupEntries.size(); + OldDidCallStackSave = CGF.DidCallStackSave; + } + + /// \brief Exit this cleanup scope, emitting any accumulated + /// cleanups. + ~CleanupScope() { + if (PerformCleanup) { + CGF.DidCallStackSave = OldDidCallStackSave; + CGF.EmitCleanupBlocks(CleanupStackDepth); + } + } + + /// \brief Determine whether this scope requires any cleanups. + bool requiresCleanups() const { + return CGF.CleanupEntries.size() > CleanupStackDepth; + } + + /// \brief Force the emission of cleanups now, instead of waiting + /// until this object is destroyed. + void ForceCleanup() { + assert(PerformCleanup && "Already forced cleanup"); + CGF.DidCallStackSave = OldDidCallStackSave; + CGF.EmitCleanupBlocks(CleanupStackDepth); + PerformCleanup = false; + } + }; + /// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup /// blocks that have been added. void EmitCleanupBlocks(size_t OldCleanupStackSize); @@ -176,27 +220,31 @@ public: /// this behavior for branches? void EmitBranchThroughCleanup(llvm::BasicBlock *Dest); - /// PushConditionalTempDestruction - Should be called before a conditional - /// part of an expression is emitted. For example, before the RHS of the - /// expression below is emitted: + /// StartConditionalBranch - Should be called before a conditional part of an + /// expression is emitted. For example, before the RHS of the expression below + /// is emitted: /// /// b && f(T()); /// - /// This is used to make sure that any temporaryes created in the conditional + /// This is used to make sure that any temporaries created in the conditional /// branch are only destroyed if the branch is taken. - void PushConditionalTempDestruction(); + void StartConditionalBranch() { + ++ConditionalBranchLevel; + } - /// PopConditionalTempDestruction - Should be called after a conditional - /// part of an expression has been emitted. - void PopConditionalTempDestruction(); + /// FinishConditionalBranch - Should be called after a conditional part of an + /// expression has been emitted. + void FinishConditionalBranch() { + --ConditionalBranchLevel; + } private: CGDebugInfo *DebugInfo; - /// IndirectBranch - The first time an indirect goto is seen we create a - /// block with an indirect branch. Every time we see the address of a label - /// taken, we add the label to the indirect goto. Every subsequent indirect - /// goto is codegen'd as a jump to the IndirectBranch's basic block. + /// IndirectBranch - The first time an indirect goto is seen we create a block + /// with an indirect branch. Every time we see the address of a label taken, + /// we add the label to the indirect goto. Every subsequent indirect goto is + /// codegen'd as a jump to the IndirectBranch's basic block. llvm::IndirectBrInst *IndirectBranch; /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C @@ -269,10 +317,15 @@ private: /// BlockScopes - Map of which "cleanup scope" scope basic blocks have. BlockScopeMap BlockScopes; - /// CXXThisDecl - When parsing an C++ function, this will hold the implicit - /// 'this' declaration. + /// CXXThisDecl - When generating code for a C++ member function, + /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXThisDecl; + /// CXXVTTDecl - When generating code for a base object constructor or + /// base object destructor with virtual bases, this will hold the implicit + /// VTT parameter. + ImplicitParamDecl *CXXVTTDecl; + /// CXXLiveTemporaryInfo - Holds information about a live C++ temporary. struct CXXLiveTemporaryInfo { /// Temporary - The live temporary. @@ -284,9 +337,9 @@ private: /// DtorBlock - The destructor block. llvm::BasicBlock *DtorBlock; - /// CondPtr - If this is a conditional temporary, this is the pointer to - /// the condition variable that states whether the destructor should be - /// called or not. + /// CondPtr - If this is a conditional temporary, this is the pointer to the + /// condition variable that states whether the destructor should be called + /// or not. llvm::Value *CondPtr; CXXLiveTemporaryInfo(const CXXTemporary *temporary, @@ -298,10 +351,10 @@ private: llvm::SmallVector LiveTemporaries; - /// ConditionalTempDestructionStack - Contains the number of live temporaries - /// when PushConditionalTempDestruction was called. This is used so that - /// we know how many temporaries were created by a certain expression. - llvm::SmallVector ConditionalTempDestructionStack; + /// ConditionalBranchLevel - Contains the nesting level of the current + /// conditional branch. This is used so that we know if a temporary should be + /// destroyed conditionally. + unsigned ConditionalBranchLevel; /// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM @@ -384,15 +437,17 @@ public: /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an /// object pointer to alter the dynamic type of the pointer. Used by /// GenerateCovariantThunk for building thunks. - llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v); + llvm::Value *DynamicTypeAdjust(llvm::Value *V, + const ThunkAdjustment &Adjustment); /// GenerateThunk - Generate a thunk for the given method llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, - bool Extern, int64_t nv, int64_t v); - llvm::Constant *GenerateCovariantThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, bool Extern, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r); + bool Extern, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant * + GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + bool Extern, + const CovariantThunkAdjustment &Adjustment); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); @@ -416,8 +471,8 @@ public: 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 reverse order of their construction. + /// destructor. This is to call destructors on members and base classes in + /// reverse order of their construction. void EmitDtorEpilogue(const CXXDestructorDecl *Dtor, CXXDtorType Type); @@ -461,9 +516,9 @@ public: /// label maps to. llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S); - /// SimplifyForwardingBlocks - If the given basic block is only a - /// branch to another basic block, simplify it. This assumes that no - /// other code could potentially reference the basic block. + /// SimplifyForwardingBlocks - If the given basic block is only a branch to + /// another basic block, simplify it. This assumes that no other code could + /// potentially reference the basic block. void SimplifyForwardingBlocks(llvm::BasicBlock *BB); /// EmitBlock - Emit the given block \arg BB and set it as the insert point, @@ -579,9 +634,9 @@ public: // instruction in LLVM instead once it works well enough. llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty); - // EmitVLASize - Generate code for any VLA size expressions that might occur - // in a variably modified type. If Ty is a VLA, will return the value that - // corresponds to the size in bytes of the VLA type. Will return 0 otherwise. + /// EmitVLASize - Generate code for any VLA size expressions that might occur + /// in a variably modified type. If Ty is a VLA, will return the value that + /// corresponds to the size in bytes of the VLA type. Will return 0 otherwise. /// /// This function can be called with a null (unreachable) insert point. llvm::Value *EmitVLASize(QualType Ty); @@ -594,15 +649,20 @@ public: /// generating code for an C++ member function. llvm::Value *LoadCXXThis(); - /// GetAddressCXXOfBaseClass - This function will add the necessary delta - /// to the load of 'this' and returns address of the base class. + /// GetAddressOfBaseClass - This function will add the necessary delta to the + /// load of 'this' and returns address of the base class. // FIXME. This currently only does a derived to non-virtual base conversion. // Other kinds of conversions will come later. - llvm::Value *GetAddressCXXOfBaseClass(llvm::Value *BaseValue, + llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + bool NullCheckValue); + + llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value, const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, + const CXXRecordDecl *DerivedClassDecl, bool NullCheckValue); - + llvm::Value * GetVirtualCXXBaseClassOffset(llvm::Value *This, const CXXRecordDecl *ClassDecl, @@ -637,10 +697,15 @@ public: void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr); + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); + void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *NumElements, - llvm::Value *ArrayPtr); + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, const ArrayType *Array, @@ -858,7 +923,6 @@ public: LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E); - LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E); LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E); @@ -880,9 +944,8 @@ public: /// result type, and using the given argument list which specifies both the /// LLVM arguments and the types they were derived from. /// - /// \param TargetDecl - If given, the decl of the function in a - /// direct call; used to set attributes on the call (noreturn, - /// etc.). + /// \param TargetDecl - If given, the decl of the function in a direct call; + /// used to set attributes on the call (noreturn, etc.). RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee, const CallArgList &Args, @@ -994,15 +1057,14 @@ public: /// LoadComplexFromAddr - Load a complex number from the specified address. ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile); - /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global - /// for a static block var decl. + /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a + /// static block var decl. llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, - llvm::GlobalValue::LinkageTypes - Linkage); + llvm::GlobalValue::LinkageTypes Linkage); - /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ - /// runtime initialized static block var decl. + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime + /// initialized static block var decl. void EmitStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 195acc5..4b3b122 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" @@ -160,19 +161,13 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) { /// the unmangled name. /// const char *CodeGenModule::getMangledName(const NamedDecl *ND) { - // In C, functions with no attributes never need to be mangled. Fastpath them. - if (!getLangOptions().CPlusPlus && !ND->hasAttrs()) { + if (!getMangleContext().shouldMangleDeclName(ND)) { assert(ND->getIdentifier() && "Attempt to mangle unnamed decl."); return ND->getNameAsCString(); } llvm::SmallString<256> Name; - llvm::raw_svector_ostream Out(Name); - if (!mangleName(getMangleContext(), ND, Out)) { - assert(ND->getIdentifier() && "Attempt to mangle unnamed decl."); - return ND->getNameAsCString(); - } - + getMangleContext().mangleName(ND, Name); Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } @@ -353,8 +348,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, else if (Features.getStackProtectorMode() == LangOptions::SSPReq) F->addFnAttr(llvm::Attribute::StackProtectReq); - if (const AlignedAttr *AA = D->getAttr()) - F->setAlignment(AA->getAlignment()/8); + if (const AlignedAttr *AA = D->getAttr()) { + unsigned width = Context.Target.getCharWidth(); + F->setAlignment(AA->getAlignment() / width); + while ((AA = AA->getNext())) + F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width)); + } // C++ ABI requires 2-byte alignment for member functions. if (F->getAlignment() < 2 && isa(D)) F->setAlignment(2); @@ -551,7 +550,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // cannot be. if (VD->isInAnonymousNamespace()) return true; - if (VD->getStorageClass() == VarDecl::Static) { + if (VD->getLinkage() == VarDecl::InternalLinkage) { // Initializer has side effects? if (VD->getInit() && VD->getInit()->HasSideEffects(Context)) return false; @@ -616,16 +615,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (const CXXMethodDecl *MD = dyn_cast(D)) { - const CXXRecordDecl *RD = MD->getParent(); - // We have to convert it to have a record layout. - Types.ConvertTagDeclType(RD); - const CGRecordLayout &CGLayout = Types.getCGRecordLayout(RD); - // A definition of a KeyFunction, generates all the class data, such - // as vtable, rtti and the VTT. - if (CGLayout.getKeyFunction() == MD) - getVtableInfo().GenerateClassData(RD); - } + if (isa(D)) + getVtableInfo().MaybeEmitVtable(GD); + if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast(D)) @@ -697,143 +689,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, // A called constructor which has no definition or declaration need be // synthesized. else if (const CXXConstructorDecl *CD = dyn_cast(FD)) { - const CXXRecordDecl *ClassDecl = - cast(CD->getDeclContext()); - if (CD->isCopyConstructor(getContext())) - DeferredCopyConstructorToEmit(D); - else if (!ClassDecl->hasUserDeclaredConstructor()) + if (CD->isImplicit()) + DeferredDeclsToEmit.push_back(D); + } else if (const CXXDestructorDecl *DD = dyn_cast(FD)) { + if (DD->isImplicit()) + DeferredDeclsToEmit.push_back(D); + } else if (const CXXMethodDecl *MD = dyn_cast(FD)) { + if (MD->isCopyAssignment() && MD->isImplicit()) DeferredDeclsToEmit.push_back(D); } - else if (isa(FD)) - DeferredDestructorToEmit(D); - else if (const CXXMethodDecl *MD = dyn_cast(FD)) - if (MD->isCopyAssignment()) - DeferredCopyAssignmentToEmit(D); } return F; } -/// Defer definition of copy constructor(s) which need be implicitly defined. -void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) { - const CXXConstructorDecl *CD = - cast(CopyCtorDecl.getDecl()); - const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); - if (ClassDecl->hasTrivialCopyConstructor() || - ClassDecl->hasUserDeclaredCopyConstructor()) - return; - - // First make sure all direct base classes and virtual bases and non-static - // data mebers which need to have their copy constructors implicitly defined - // are defined. 12.8.p7 - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, 0)) - GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - if (CXXConstructorDecl *FieldCopyCtor = - FieldClassDecl->getCopyConstructor(Context, 0)) - GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete); - } - } - DeferredDeclsToEmit.push_back(CopyCtorDecl); -} - -/// Defer definition of copy assignments which need be implicitly defined. -void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) { - const CXXMethodDecl *CD = cast(CopyAssignDecl.getDecl()); - const CXXRecordDecl *ClassDecl = cast(CD->getDeclContext()); - - if (ClassDecl->hasTrivialCopyAssignment() || - ClassDecl->hasUserDeclaredCopyAssignment()) - return; - - // First make sure all direct base classes and virtual bases and non-static - // data mebers which need to have their copy assignments implicitly defined - // are defined. 12.8.p12 - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - const CXXMethodDecl *MD = 0; - if (!BaseClassDecl->hasTrivialCopyAssignment() && - !BaseClassDecl->hasUserDeclaredCopyAssignment() && - BaseClassDecl->hasConstCopyAssignment(getContext(), MD)) - GetAddrOfFunction(MD, 0); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - const CXXMethodDecl *MD = 0; - if (!FieldClassDecl->hasTrivialCopyAssignment() && - !FieldClassDecl->hasUserDeclaredCopyAssignment() && - FieldClassDecl->hasConstCopyAssignment(getContext(), MD)) - GetAddrOfFunction(MD, 0); - } - } - DeferredDeclsToEmit.push_back(CopyAssignDecl); -} - -void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) { - const CXXDestructorDecl *DD = cast(DtorDecl.getDecl()); - const CXXRecordDecl *ClassDecl = cast(DD->getDeclContext()); - if (ClassDecl->hasTrivialDestructor() || - ClassDecl->hasUserDeclaredDestructor()) - return; - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast(Base->getType()->getAs()->getDecl()); - if (const CXXDestructorDecl *BaseDtor = - BaseClassDecl->getDestructor(Context)) - GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs()) { - if ((*Field)->isAnonymousStructOrUnion()) - continue; - CXXRecordDecl *FieldClassDecl - = cast(FieldClassType->getDecl()); - if (const CXXDestructorDecl *FieldDtor = - FieldClassDecl->getDestructor(Context)) - GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete); - } - } - DeferredDeclsToEmit.push_back(DtorDecl); -} - - /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). @@ -982,9 +851,8 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_TemplateInstantiation; } } - - // Static variables get internal linkage. - if (VD->getStorageClass() == VarDecl::Static) + + if (VD->getLinkage() == VarDecl::InternalLinkage) return CodeGenModule::GVA_Internal; return CodeGenModule::GVA_StrongExternal; @@ -1097,7 +965,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); } else if (Linkage == GVA_TemplateInstantiation) GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - else if (!CodeGenOpts.NoCommon && + else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && !D->getAttr()) { GV->setLinkage(llvm::GlobalVariable::CommonLinkage); @@ -1734,6 +1602,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::NamespaceAlias: break; case Decl::CXXConstructor: + // Skip function templates + if (cast(D)->getDescribedFunctionTemplate()) + return; + EmitCXXConstructors(cast(D)); break; case Decl::CXXDestructor: diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c8562d6..78bc4ed 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -231,15 +231,16 @@ public: llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD); /// GenerateRttiNonClass - Generate the rtti information for the given /// non-class type. - llvm::Constant *GenerateRttiNonClass(QualType Ty); + llvm::Constant *GenerateRtti(QualType Ty); + + /// BuildThunk - Build a thunk for the given method. + llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, + const ThunkAdjustment &ThisAdjustment); - /// BuildThunk - Build a thunk for the given method - llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv, - int64_t v); /// BuildCoVariantThunk - Build a thunk for the given method - llvm::Constant *BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r); + llvm::Constant * + BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + const CovariantThunkAdjustment &Adjustment); typedef std::pair CtorVtable_t; typedef llvm::DenseMapsecond; - CGRecordLayouts.clear(); + { + llvm::FoldingSet::iterator + I = FunctionInfos.begin(), E = FunctionInfos.end(); + while (I != E) + delete &*I++; + } + delete TheABIInfo; } /// ConvertType - Convert the specified type to its LLVM form. @@ -197,6 +203,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: // LLVM void type can only be used as the result of a function call. Just // map to the same as char. return llvm::IntegerType::get(getLLVMContext(), 8); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index f447549..2ff602f 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -20,6 +20,7 @@ #include #include "CGCall.h" +#include "CGCXX.h" namespace llvm { class FunctionType; @@ -34,6 +35,8 @@ namespace llvm { namespace clang { class ABIInfo; class ASTContext; + class CXXConstructorDecl; + class CXXDestructorDecl; class CXXMethodDecl; class FieldDecl; class FunctionProtoType; @@ -61,17 +64,9 @@ namespace CodeGen { /// is a member pointer, or a struct that contains a member pointer. bool ContainsMemberPointer; - /// KeyFunction - The key function of the record layout (if one exists), - /// which is the first non-pure virtual function that is not inline at the - /// point of class definition. - /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable. - const CXXMethodDecl *KeyFunction; - public: - CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer, - const CXXMethodDecl *KeyFunction) - : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer), - KeyFunction(KeyFunction) { } + CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer) + : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { } /// getLLVMType - Return llvm type associated with this record. const llvm::Type *getLLVMType() const { @@ -81,10 +76,6 @@ namespace CodeGen { bool containsMemberPointer() const { return ContainsMemberPointer; } - - const CXXMethodDecl *getKeyFunction() const { - return KeyFunction; - } }; /// CodeGenTypes - This class organizes the cross-module state that is used @@ -173,6 +164,12 @@ public: const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info, bool IsVariadic); + + /// 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 CGRecordLayout &getCGRecordLayout(const TagDecl*) const; /// getLLVMFieldNo - Return llvm::StructType element number @@ -192,7 +189,11 @@ public: const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD); const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD); const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD); - + const CGFunctionInfo &getFunctionInfo(const CXXConstructorDecl *D, + CXXCtorType Type); + const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D, + CXXDtorType Type); + // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 0a7124d..d6f7808 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -23,100 +23,111 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "CGVtable.h" using namespace clang; +using namespace CodeGen; namespace { - class VISIBILITY_HIDDEN CXXNameMangler { - MangleContext &Context; - llvm::raw_ostream &Out; - - const CXXMethodDecl *Structor; - unsigned StructorType; - CXXCtorType CtorType; - - llvm::DenseMap Substitutions; - - public: - CXXNameMangler(MangleContext &C, llvm::raw_ostream &os) - : Context(C), Out(os), Structor(0), StructorType(0) { } - - bool mangle(const NamedDecl *D); - void mangleCalloffset(int64_t nv, int64_t v); - void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v); - void mangleCovariantThunk(const FunctionDecl *FD, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r); - void mangleGuardVariable(const VarDecl *D); - - void mangleCXXVtable(const CXXRecordDecl *RD); - void mangleCXXVTT(const CXXRecordDecl *RD); - void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, - const CXXRecordDecl *Type); - void mangleCXXRtti(QualType Ty); - void mangleCXXRttiName(QualType Ty); - void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type); - void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type); - - private: - bool mangleSubstitution(const NamedDecl *ND); - bool mangleSubstitution(QualType T); - bool mangleSubstitution(uintptr_t Ptr); - - bool mangleStandardSubstitution(const NamedDecl *ND); - - void addSubstitution(const NamedDecl *ND) { - ND = cast(ND->getCanonicalDecl()); + +static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { + assert((isa(MD) || isa(MD)) && + "Passed in decl is not a ctor or dtor!"); + + if (const TemplateDecl *TD = MD->getPrimaryTemplate()) { + MD = cast(TD->getTemplatedDecl()); - addSubstitution(reinterpret_cast(ND)); - } - void addSubstitution(QualType T); - void addSubstitution(uintptr_t Ptr); + assert((isa(MD) || isa(MD)) && + "Templated decl is not a ctor or dtor!"); + } - bool mangleFunctionDecl(const FunctionDecl *FD); - - void mangleFunctionEncoding(const FunctionDecl *FD); - void mangleName(const NamedDecl *ND); - void mangleName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleUnqualifiedName(const NamedDecl *ND); - void mangleUnscopedName(const NamedDecl *ND); - void mangleUnscopedTemplateName(const TemplateDecl *ND); - void mangleSourceName(const IdentifierInfo *II); - void mangleLocalName(const NamedDecl *ND); - void mangleNestedName(const NamedDecl *ND); - void mangleNestedName(const TemplateDecl *TD, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void manglePrefix(const DeclContext *DC); - void mangleTemplatePrefix(const TemplateDecl *ND); - void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleQualifiers(Qualifiers Quals); - void mangleType(QualType T); - - // Declare manglers for every type class. + return MD; +} + +/// CXXNameMangler - Manage the mangling of a single name. +class CXXNameMangler { + MangleContext &Context; + llvm::raw_svector_ostream Out; + + const CXXMethodDecl *Structor; + unsigned StructorType; + + llvm::DenseMap Substitutions; + +public: + CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl &Res) + : Context(C), Out(Res), Structor(0), StructorType(0) { } + CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl &Res, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { } + CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl &Res, + const CXXDestructorDecl *D, CXXDtorType Type) + : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { } + + llvm::raw_svector_ostream &getStream() { return Out; } + + void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); + void mangleCallOffset(const ThunkAdjustment &Adjustment); + void mangleNumber(int64_t Number); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleType(QualType T); + +private: + bool mangleSubstitution(const NamedDecl *ND); + bool mangleSubstitution(QualType T); + bool mangleSubstitution(uintptr_t Ptr); + + bool mangleStandardSubstitution(const NamedDecl *ND); + + void addSubstitution(const NamedDecl *ND) { + ND = cast(ND->getCanonicalDecl()); + + addSubstitution(reinterpret_cast(ND)); + } + void addSubstitution(QualType T); + void addSubstitution(uintptr_t Ptr); + + bool mangleFunctionDecl(const FunctionDecl *FD); + + void mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleUnqualifiedName(const NamedDecl *ND); + void mangleUnscopedName(const NamedDecl *ND); + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleSourceName(const IdentifierInfo *II); + void mangleLocalName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void manglePrefix(const DeclContext *DC); + void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleQualifiers(Qualifiers Quals); + + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); #include "clang/AST/TypeNodes.def" - void mangleType(const TagType*); - void mangleBareFunctionType(const FunctionType *T, - bool MangleReturnType); - void mangleExpression(const Expr *E); - void mangleCXXCtorType(CXXCtorType T); - void mangleCXXDtorType(CXXDtorType T); - - void mangleTemplateArgs(const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleTemplateArgumentList(const TemplateArgumentList &L); - void mangleTemplateArgument(const TemplateArgument &A); - - void mangleTemplateParameter(unsigned Index); - }; + void mangleType(const TagType*); + void mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType); + void mangleExpression(const Expr *E); + void mangleCXXCtorType(CXXCtorType T); + void mangleCXXDtorType(CXXDtorType T); + + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgumentList(const TemplateArgumentList &L); + void mangleTemplateArgument(const TemplateArgument &A); + + void mangleTemplateParameter(unsigned Index); +}; } static bool isInCLinkageSpecification(const Decl *D) { @@ -130,132 +141,72 @@ static bool isInCLinkageSpecification(const Decl *D) { return false; } -bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { +bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr()) + return true; + // Clang's "overloadable" attribute extension to C/C++ implies name mangling // (always) as does passing a C++ member function and a function // whose name is not a simple identifier. - if (!FD->hasAttr() && !isa(FD) && - FD->getDeclName().isIdentifier()) { - // C functions are not mangled, and "main" is never mangled. - if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain()) - return false; + const FunctionDecl *FD = dyn_cast(D); + if (FD && (FD->hasAttr() || isa(FD) || + !FD->getDeclName().isIdentifier())) + return true; - // No mangling in an "implicit extern C" header. - if (FD->getLocation().isValid() && - Context.getASTContext().getSourceManager(). - isInExternCSystemHeader(FD->getLocation())) - return false; + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOptions().CPlusPlus) + return false; - // No name mangling in a C linkage specification. - if (isInCLinkageSpecification(FD)) - return false; - } + // No mangling in an "implicit extern C" header. + if (D->getLocation().isValid() && + getASTContext().getSourceManager(). + isInExternCSystemHeader(D->getLocation())) + return false; + + // C functions, "main", and variables at global scope are not + // mangled. + if ((FD && FD->isMain()) || + (!FD && D->getDeclContext()->isTranslationUnit()) || + isInCLinkageSpecification(D)) + return false; - // If we get here, mangle the decl name! - Out << "_Z"; - mangleFunctionEncoding(FD); return true; } -bool CXXNameMangler::mangle(const NamedDecl *D) { +void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { // Any decl can be declared with __asm("foo") on it, and this takes precedence // over all other naming in the .o file. if (const AsmLabelAttr *ALA = D->getAttr()) { // If we have an asm name, then we use it as the mangling. Out << '\01'; // LLVM IR Marker for __asm("foo") Out << ALA->getLabel(); - return true; + return; } // ::= _Z // ::= // ::= - - // FIXME: Actually use a visitor to decode these? + Out << Prefix; if (const FunctionDecl *FD = dyn_cast(D)) - return mangleFunctionDecl(FD); - - if (const VarDecl *VD = dyn_cast(D)) { - if (!Context.getASTContext().getLangOptions().CPlusPlus || - isInCLinkageSpecification(D) || - D->getDeclContext()->isTranslationUnit()) - return false; - - Out << "_Z"; - mangleName(VD); - return true; - } - - return false; -} - -void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D, - CXXCtorType Type) { - assert(!Structor && "Structor already set!"); - Structor = D; - StructorType = Type; - - mangle(D); -} - -void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D, - CXXDtorType Type) { - assert(!Structor && "Structor already set!"); - Structor = D; - StructorType = Type; - - mangle(D); -} - -void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) { - // ::= TV # virtual table - Out << "_ZTV"; - mangleName(RD); -} - -void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) { - // ::= TT # VTT structure - Out << "_ZTT"; - mangleName(RD); -} - -void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD, - int64_t Offset, - const CXXRecordDecl *Type) { - // ::= TC _ - Out << "_ZTC"; - mangleName(RD); - Out << Offset; - Out << "_"; - mangleName(Type); -} - -void CXXNameMangler::mangleCXXRtti(QualType Ty) { - // ::= TI # typeinfo structure - Out << "_ZTI"; - - mangleType(Ty); -} - -void CXXNameMangler::mangleCXXRttiName(QualType Ty) { - // ::= TS # typeinfo name (null terminated byte string) - Out << "_ZTS"; - - mangleType(Ty); -} - -void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { - // ::= GV # Guard variable for one-time - // # initialization - - Out << "_ZGV"; - mangleName(D); + mangleFunctionEncoding(FD); + else + mangleName(cast(D)); } void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // ::= mangleName(FD); + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + // Whether the mangling of a function type includes the return type depends on // the context and the nature of the function. The rules for deciding whether // the return type is included are: @@ -277,7 +228,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { if (!(isa(FD) || isa(FD) || isa(FD))) MangleReturnType = true; - + // Mangle the type of the primary template. FD = PrimaryTemplate->getTemplatedDecl(); } @@ -290,15 +241,16 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { mangleBareFunctionType(FT, MangleReturnType); } -static bool isStdNamespace(const DeclContext *DC) { - if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit()) - return false; - - const NamespaceDecl *NS = cast(DC); +static bool isStdNamespace(const NamespaceDecl *NS) { const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); return II && II->isStr("std"); } +static bool isStdNamespace(const DeclContext *DC) { + return DC->isNamespace() && DC->getParent()->isTranslationUnit() && + isStdNamespace(cast(DC)); +} + static const TemplateDecl * isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { // Check if we have a function template. @@ -315,7 +267,7 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { TemplateArgs = &Spec->getTemplateArgs(); return Spec->getSpecializedTemplate(); } - + return 0; } @@ -328,7 +280,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { const DeclContext *DC = ND->getDeclContext(); while (isa(DC)) DC = DC->getParent(); - + if (DC->isTranslationUnit() || isStdNamespace(DC)) { // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; @@ -341,24 +293,24 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { mangleUnscopedName(ND); return; } - + if (isa(DC)) { mangleLocalName(ND); return; } - + mangleNestedName(ND); } -void CXXNameMangler::mangleName(const TemplateDecl *TD, +void CXXNameMangler::mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { const DeclContext *DC = TD->getDeclContext(); while (isa(DC)) { - assert(cast(DC)->getLanguage() == + assert(cast(DC)->getLanguage() == LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); DC = DC->getParent(); } - + if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); mangleTemplateArgs(TemplateArgs, NumTemplateArgs); @@ -372,7 +324,7 @@ void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { // ::= St # ::std:: if (isStdNamespace(ND->getDeclContext())) Out << "St"; - + mangleUnqualifiedName(ND); } @@ -381,61 +333,39 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { // ::= if (mangleSubstitution(ND)) return; - + mangleUnscopedName(ND->getTemplatedDecl()); addSubstitution(ND); } -void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) { +void CXXNameMangler::mangleNumber(int64_t Number) { + // ::= [n] + if (Number < 0) { + Out << 'n'; + Number = -Number; + } + + Out << Number; +} + +void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) { // ::= h _ // ::= v _ // ::= # non-virtual base override - // ::= _ + // ::= _ // # virtual base override, with vcall offset - if (v == 0) { - Out << "h"; - if (nv < 0) { - Out << "n"; - nv = -nv; - } - Out << nv; - } else { - Out << "v"; - if (nv < 0) { - Out << "n"; - nv = -nv; - } - Out << nv; - Out << "_"; - if (v < 0) { - Out << "n"; - v = -v; - } - Out << v; + if (!Adjustment.Virtual) { + Out << 'h'; + mangleNumber(Adjustment.NonVirtual); + Out << '_'; + return; } - Out << "_"; -} - -void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv, - int64_t v) { - // ::= T - // # base is the nominal target function of thunk - Out << "_ZT"; - mangleCalloffset(nv, v); - mangleFunctionEncoding(FD); -} - - void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r) { - // ::= Tc - // # base is the nominal target function of thunk - // # first call-offset is 'this' adjustment - // # second call-offset is result adjustment - Out << "_ZTc"; - mangleCalloffset(nv_t, v_t); - mangleCalloffset(nv_r, v_r); - mangleFunctionEncoding(FD); + + Out << 'v'; + mangleNumber(Adjustment.NonVirtual); + Out << '_'; + mangleNumber(Adjustment.Virtual); + Out << '_'; } void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { @@ -453,13 +383,13 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { Out << "12_GLOBAL__N_1"; break; } - } + } if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { mangleSourceName(II); break; } - + // We must have an anonymous struct. const TagDecl *TD = cast(ND); if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { @@ -470,12 +400,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { mangleSourceName(D->getDeclName().getAsIdentifierInfo()); break; } - + // Get a unique id for the anonymous struct. uint64_t AnonStructId = Context.getAnonymousStructId(TD); // Mangle it as a source name in the form - // [n] $_ + // [n] $_ // where n is the length of the string. llvm::SmallString<8> Str; Str += "$_"; @@ -525,6 +455,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { cast(ND)->getNumParams()); break; + case DeclarationName::CXXLiteralOperatorName: + // Guessing based on existing ABI. + Out << "ul"; + mangleSourceName(Name.getCXXLiteralIdentifier()); + break; + case DeclarationName::CXXUsingDirective: assert(false && "Can't mangle a using directive name!"); break; @@ -545,29 +481,29 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast(ND)) mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); - + // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); mangleTemplateArgumentList(*TemplateArgs); } else { manglePrefix(ND->getDeclContext()); mangleUnqualifiedName(ND); } - + Out << 'E'; } -void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, +void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // ::= N [] E Out << 'N'; - + mangleTemplatePrefix(TD); mangleTemplateArgs(TemplateArgs, NumTemplateArgs); - + Out << 'E'; } @@ -591,23 +527,23 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { while (isa(DC)) DC = DC->getParent(); - + if (DC->isTranslationUnit()) return; - + if (mangleSubstitution(cast(DC))) return; // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; - if (const TemplateDecl *TD = isTemplate(cast(DC), TemplateArgs)) { + if (const TemplateDecl *TD = isTemplate(cast(DC), TemplateArgs)) { mangleTemplatePrefix(TD); mangleTemplateArgumentList(*TemplateArgs); } else { manglePrefix(DC->getParent()); mangleUnqualifiedName(cast(DC)); } - + addSubstitution(cast(DC)); } @@ -618,12 +554,12 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { if (mangleSubstitution(ND)) return; - + // FIXME: - + manglePrefix(ND->getDeclContext()); mangleUnqualifiedName(ND->getTemplatedDecl()); - + addSubstitution(ND); } @@ -838,6 +774,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { break; case BuiltinType::ObjCId: Out << "11objc_object"; break; case BuiltinType::ObjCClass: Out << "10objc_class"; break; + case BuiltinType::ObjCSel: Out << "13objc_selector"; break; } } @@ -992,7 +929,7 @@ void CXXNameMangler::mangleType(const FixedWidthIntType *T) { void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(); assert(TD && "FIXME: Support dependent template names!"); - + mangleName(TD, T->getArgs(), T->getNumArgs()); } @@ -1001,7 +938,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) { Out << 'N'; const Type *QTy = T->getQualifier()->getAsType(); - if (const TemplateSpecializationType *TST = + if (const TemplateSpecializationType *TST = dyn_cast(QTy)) { if (!mangleSubstitution(QualType(TST, 0))) { TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); @@ -1010,7 +947,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) { mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } - } else if (const TemplateTypeParmType *TTPT = + } else if (const TemplateTypeParmType *TTPT = dyn_cast(QTy)) { // We use the QualType mangle type variant here because it handles // substitutions. @@ -1019,7 +956,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) { assert(false && "Unhandled type!"); mangleSourceName(T->getIdentifier()); - + Out << 'E'; } @@ -1047,7 +984,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { case Expr::DeclRefExprClass: { const Decl *D = cast(E)->getDecl(); - + switch (D->getKind()) { default: assert(false && "Unhandled decl kind!"); case Decl::NonTypeTemplateParm: { @@ -1057,23 +994,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } } - + break; } - - case Expr::UnresolvedDeclRefExprClass: { - const UnresolvedDeclRefExpr *DRE = cast(E); + + case Expr::DependentScopeDeclRefExprClass: { + const DependentScopeDeclRefExpr *DRE = cast(E); const Type *QTy = DRE->getQualifier()->getAsType(); assert(QTy && "Qualifier was not type!"); // ::= sr # dependent name Out << "sr"; mangleType(QualType(QTy, 0)); - + assert(DRE->getDeclName().getNameKind() == DeclarationName::Identifier && "Unhandled decl name kind!"); mangleSourceName(DRE->getDeclName().getAsIdentifierInfo()); - + break; } @@ -1122,13 +1059,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) { // ::= I + E Out << "I"; - - for (unsigned i = 0, e = L.size(); i != e; ++i) { - const TemplateArgument &A = L[i]; - - mangleTemplateArgument(A); - } - + for (unsigned i = 0, e = L.size(); i != e; ++i) + mangleTemplateArgument(L[i]); Out << "E"; } @@ -1136,11 +1068,8 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // ::= I + E Out << "I"; - - for (unsigned i = 0; i != NumTemplateArgs; ++i) { + for (unsigned i = 0; i != NumTemplateArgs; ++i) mangleTemplateArgument(TemplateArgs[i]); - } - Out << "E"; } @@ -1161,14 +1090,12 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { mangleExpression(A.getAsExpr()); Out << 'E'; break; - case TemplateArgument::Integral: + case TemplateArgument::Integral: { // ::= L E # integer literal + const llvm::APSInt *Integral = A.getAsIntegral(); Out << 'L'; - mangleType(A.getIntegralType()); - - const llvm::APSInt *Integral = A.getAsIntegral(); if (A.getIntegralType()->isBooleanType()) { // Boolean values are encoded as 0/1. Out << (Integral->getBoolValue() ? '1' : '0'); @@ -1177,10 +1104,27 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { Out << 'n'; Integral->abs().print(Out, false); } + Out << 'E'; + break; + } + case TemplateArgument::Declaration: { + // ::= L E # external name + // FIXME: Clang produces AST's where pointer-to-member-function expressions + // and pointer-to-function expressions are represented as a declaration not + // an expression; this is not how gcc represents them and this changes the + // mangling. + Out << 'L'; + // References to external entities use the mangled name; if the name would + // not normally be manged then mangle it as unqualified. + // + // FIXME: The ABI specifies that external names here should have _Z, but + // gcc leaves this off. + mangle(cast(A.getAsDecl()), "Z"); Out << 'E'; break; } + } } void CXXNameMangler::mangleTemplateParameter(unsigned Index) { @@ -1198,7 +1142,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { // Try one of the standard substitutions first. if (mangleStandardSubstitution(ND)) return true; - + ND = cast(ND->getCanonicalDecl()); return mangleSubstitution(reinterpret_cast(ND)); } @@ -1208,79 +1152,79 @@ bool CXXNameMangler::mangleSubstitution(QualType T) { if (const RecordType *RT = T->getAs()) return mangleSubstitution(RT->getDecl()); } - + uintptr_t TypePtr = reinterpret_cast(T.getAsOpaquePtr()); return mangleSubstitution(TypePtr); } bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { - llvm::DenseMap::iterator I = + llvm::DenseMap::iterator I = Substitutions.find(Ptr); if (I == Substitutions.end()) return false; - + unsigned SeqID = I->second; if (SeqID == 0) Out << "S_"; else { SeqID--; - + // is encoded in base-36, using digits and upper case letters. char Buffer[10]; char *BufferPtr = Buffer + 9; - + *BufferPtr = 0; if (SeqID == 0) *--BufferPtr = '0'; - + while (SeqID) { assert(BufferPtr > Buffer && "Buffer overflow!"); - + unsigned char c = static_cast(SeqID) % 36; - + *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10); SeqID /= 36; } - + Out << 'S' << BufferPtr << '_'; } - + return true; } static bool isCharType(QualType T) { if (T.isNull()) return false; - + return T->isSpecificBuiltinType(BuiltinType::Char_S) || T->isSpecificBuiltinType(BuiltinType::Char_U); } -/// isCharSpecialization - Returns whether a given type is a template +/// isCharSpecialization - Returns whether a given type is a template /// specialization of a given name with a single argument of type char. static bool isCharSpecialization(QualType T, const char *Name) { if (T.isNull()) return false; - + const RecordType *RT = T->getAs(); if (!RT) return false; - - const ClassTemplateSpecializationDecl *SD = + + const ClassTemplateSpecializationDecl *SD = dyn_cast(RT->getDecl()); if (!SD) return false; if (!isStdNamespace(SD->getDeclContext())) return false; - + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); if (TemplateArgs.size() != 1) return false; - + if (!isCharType(TemplateArgs[0].getAsType())) return false; - + return SD->getIdentifier()->getName() == Name; } @@ -1298,55 +1242,55 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { if (const ClassTemplateDecl *TD = dyn_cast(ND)) { if (!isStdNamespace(TD->getDeclContext())) return false; - + // ::= Sa # ::std::allocator if (TD->getIdentifier()->isStr("allocator")) { Out << "Sa"; return true; } - + // < ::= Sb # ::std::basic_string if (TD->getIdentifier()->isStr("basic_string")) { Out << "Sb"; return true; } } - - if (const ClassTemplateSpecializationDecl *SD = + + if (const ClassTemplateSpecializationDecl *SD = dyn_cast(ND)) { // ::= Ss # ::std::basic_string, // ::std::allocator > if (SD->getIdentifier()->isStr("basic_string")) { const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - + if (TemplateArgs.size() != 3) return false; - + if (!isCharType(TemplateArgs[0].getAsType())) return false; - + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) return false; - + if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator")) return false; Out << "Ss"; return true; } - - // ::= So # ::std::basic_ostream ::= So # ::std::basic_ostream > if (SD->getIdentifier()->isStr("basic_ostream")) { const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - + if (TemplateArgs.size() != 2) return false; - + if (!isCharType(TemplateArgs[0].getAsType())) return false; - + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) return false; @@ -1364,138 +1308,144 @@ void CXXNameMangler::addSubstitution(QualType T) { return; } } - + uintptr_t TypePtr = reinterpret_cast(T.getAsOpaquePtr()); addSubstitution(TypePtr); } void CXXNameMangler::addSubstitution(uintptr_t Ptr) { unsigned SeqID = Substitutions.size(); - - assert(!Substitutions.count(Ptr) && "Substitution already exists!"); - Substitutions[Ptr] = SeqID; -} - -namespace clang { - /// \brief Mangles the name of the declaration D and emits that name to the - /// given output stream. - /// - /// If the declaration D requires a mangled name, this routine will emit that - /// mangled name to \p os and return true. Otherwise, \p os will be unchanged - /// and this routine will return false. In this case, the caller should just - /// emit the identifier of the declaration (\c D->getIdentifier()) as its - /// name. - bool mangleName(MangleContext &Context, const NamedDecl *D, - llvm::raw_ostream &os) { - assert(!isa(D) && - "Use mangleCXXCtor for constructor decls!"); - assert(!isa(D) && - "Use mangleCXXDtor for destructor decls!"); - - PrettyStackTraceDecl CrashInfo(const_cast(D), SourceLocation(), - Context.getASTContext().getSourceManager(), - "Mangling declaration"); - - CXXNameMangler Mangler(Context, os); - if (!Mangler.mangle(D)) - return false; - - os.flush(); - return true; - } - - /// \brief Mangles the a thunk with the offset n for the declaration D and - /// emits that name to the given output stream. - void mangleThunk(MangleContext &Context, const FunctionDecl *FD, - int64_t nv, int64_t v, llvm::raw_ostream &os) { - // FIXME: Hum, we might have to thunk these, fix. - assert(!isa(FD) && - "Use mangleCXXDtor for destructor decls!"); - - CXXNameMangler Mangler(Context, os); - Mangler.mangleThunk(FD, nv, v); - os.flush(); - } - - /// \brief Mangles the a covariant thunk for the declaration D and emits that - /// name to the given output stream. - void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r, - llvm::raw_ostream &os) { - // FIXME: Hum, we might have to thunk these, fix. - assert(!isa(FD) && - "Use mangleCXXDtor for destructor decls!"); - - CXXNameMangler Mangler(Context, os); - Mangler.mangleCovariantThunk(FD, nv_t, v_t, nv_r, v_r); - os.flush(); - } - - /// mangleGuardVariable - Returns the mangled name for a guard variable - /// for the passed in VarDecl. - void mangleGuardVariable(MangleContext &Context, const VarDecl *D, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleGuardVariable(D); - - os.flush(); - } - - void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D, - CXXCtorType Type, llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXCtor(D, Type); - os.flush(); - } - - void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D, - CXXDtorType Type, llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXDtor(D, Type); + assert(!Substitutions.count(Ptr) && "Substitution already exists!"); + Substitutions[Ptr] = SeqID; +} - os.flush(); - } +// - void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXVtable(RD); +/// \brief Mangles the name of the declaration D and emits that name to the +/// given output stream. +/// +/// If the declaration D requires a mangled name, this routine will emit that +/// mangled name to \p os and return true. Otherwise, \p os will be unchanged +/// and this routine will return false. In this case, the caller should just +/// emit the identifier of the declaration (\c D->getIdentifier()) as its +/// name. +void MangleContext::mangleName(const NamedDecl *D, + llvm::SmallVectorImpl &Res) { + assert((isa(D) || isa(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa(D) && !isa(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + CXXNameMangler Mangler(*this, Res); + return Mangler.mangle(D); +} + +void MangleContext::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::SmallVectorImpl &Res) { + CXXNameMangler Mangler(*this, Res, D, Type); + Mangler.mangle(D); +} + +void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::SmallVectorImpl &Res) { + CXXNameMangler Mangler(*this, Res, D, Type); + Mangler.mangle(D); +} + +/// \brief Mangles the a thunk with the offset n for the declaration D and +/// emits that name to the given output stream. +void MangleContext::mangleThunk(const FunctionDecl *FD, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl &Res) { + // FIXME: Hum, we might have to thunk these, fix. + assert(!isa(FD) && + "Use mangleCXXDtor for destructor decls!"); - os.flush(); - } - - void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXVTT(RD); + // ::= T + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZT"; + Mangler.mangleCallOffset(ThisAdjustment); + Mangler.mangleFunctionEncoding(FD); +} + +/// \brief Mangles the a covariant thunk for the declaration D and emits that +/// name to the given output stream. +void +MangleContext::mangleCovariantThunk(const FunctionDecl *FD, + const CovariantThunkAdjustment& Adjustment, + llvm::SmallVectorImpl &Res) { + // FIXME: Hum, we might have to thunk these, fix. + assert(!isa(FD) && + "Use mangleCXXDtor for destructor decls!"); - os.flush(); - } + // ::= Tc + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTc"; + Mangler.mangleCallOffset(Adjustment.ThisAdjustment); + Mangler.mangleCallOffset(Adjustment.ReturnAdjustment); + Mangler.mangleFunctionEncoding(FD); +} - void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD, - int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXCtorVtable(RD, Offset, Type); +/// mangleGuardVariable - Returns the mangled name for a guard variable +/// for the passed in VarDecl. +void MangleContext::mangleGuardVariable(const VarDecl *D, + llvm::SmallVectorImpl &Res) { + // ::= GV # Guard variable for one-time + // # initialization + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZGV"; + Mangler.mangleName(D); +} - os.flush(); - } +void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD, + llvm::SmallVectorImpl &Res) { + // ::= TV # virtual table + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTV"; + Mangler.mangleName(RD); +} - void mangleCXXRtti(MangleContext &Context, QualType Ty, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXRtti(Ty); +void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + llvm::SmallVectorImpl &Res) { + // ::= TT # VTT structure + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTT"; + Mangler.mangleName(RD); +} - os.flush(); - } +void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::SmallVectorImpl &Res) { + // ::= TC _ + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTC"; + Mangler.mangleName(RD); + Mangler.getStream() << Offset; + Mangler.getStream() << "_"; + Mangler.mangleName(Type); +} - void mangleCXXRttiName(MangleContext &Context, QualType Ty, - llvm::raw_ostream &os) { - CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXRttiName(Ty); +void MangleContext::mangleCXXRtti(QualType Ty, + llvm::SmallVectorImpl &Res) { + // ::= TI # typeinfo structure + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTI"; + Mangler.mangleType(Ty); +} - os.flush(); - } +void MangleContext::mangleCXXRttiName(QualType Ty, + llvm::SmallVectorImpl &Res) { + // ::= TS # typeinfo name (null terminated byte string) + CXXNameMangler Mangler(*this, Res); + Mangler.getStream() << "_ZTS"; + Mangler.mangleType(Ty); } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 458708f..65b1d9f 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -23,7 +23,7 @@ #include "llvm/ADT/DenseMap.h" namespace llvm { - class raw_ostream; + template class SmallVectorImpl; } namespace clang { @@ -34,50 +34,59 @@ namespace clang { class NamedDecl; class VarDecl; - class MangleContext { - ASTContext &Context; - - llvm::DenseMap AnonStructIds; +namespace CodeGen { + class CovariantThunkAdjustment; + class ThunkAdjustment; + +/// MangleContext - Context for tracking state which persists across multiple +/// calls to the C++ name mangler. +class MangleContext { + ASTContext &Context; - public: - explicit MangleContext(ASTContext &Context) + llvm::DenseMap AnonStructIds; + +public: + explicit MangleContext(ASTContext &Context) : Context(Context) { } - - ASTContext &getASTContext() const { return Context; } - - uint64_t getAnonymousStructId(const TagDecl *TD) { - std::pair::iterator, bool> Result = + + ASTContext &getASTContext() const { return Context; } + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair::iterator, bool> Result = AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); - return Result.first->second; - } - }; + return Result.first->second; + } + + /// @name Mangler Entry Points + /// @{ - bool mangleName(MangleContext &Context, const NamedDecl *D, - llvm::raw_ostream &os); - void mangleThunk(MangleContext &Context, const FunctionDecl *FD, - int64_t n, int64_t vn, llvm::raw_ostream &os); - void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD, - int64_t nv_t, int64_t v_t, - int64_t nv_r, int64_t v_r, - llvm::raw_ostream &os); - void mangleGuardVariable(MangleContext &Context, const VarDecl *D, - llvm::raw_ostream &os); - void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD, - llvm::raw_ostream &os); - void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, - llvm::raw_ostream &os); - void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD, - int64_t Offset, const CXXRecordDecl *Type, - llvm::raw_ostream &os); - void mangleCXXRtti(MangleContext &Context, QualType T, - llvm::raw_ostream &os); - void mangleCXXRttiName(MangleContext &Context, QualType T, - llvm::raw_ostream &os); - void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D, - CXXCtorType Type, llvm::raw_ostream &os); - void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D, - CXXDtorType Type, llvm::raw_ostream &os); + bool shouldMangleDeclName(const NamedDecl *D); + + void mangleName(const NamedDecl *D, llvm::SmallVectorImpl &); + void mangleThunk(const FunctionDecl *FD, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl &); + void mangleCovariantThunk(const FunctionDecl *FD, + const CovariantThunkAdjustment& Adjustment, + llvm::SmallVectorImpl &); + void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl &); + void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl &); + void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl &); + void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::SmallVectorImpl &); + void mangleCXXRtti(QualType T, llvm::SmallVectorImpl &); + void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl &); + void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::SmallVectorImpl &); + void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::SmallVectorImpl &); + + /// @} +}; + +} } #endif diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 1d8f31d..017059d 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -22,13 +22,11 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Target/TargetData.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/OwningPtr.h" using namespace clang; - namespace { - class VISIBILITY_HIDDEN CodeGeneratorImpl : public CodeGenerator { + class CodeGeneratorImpl : public CodeGenerator { Diagnostic &Diags; llvm::OwningPtr TD; ASTContext *Ctx; diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index ba0bc66..2bc6175 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -771,7 +771,7 @@ void X86_64ABIInfo::classify(QualType Ty, // reference. if (hasNonTrivialDestructorOrCopyConstructor(RT)) return; - + const RecordDecl *RD = RT->getDecl(); // Assume variable sized types are passed in memory. @@ -782,6 +782,32 @@ void X86_64ABIInfo::classify(QualType Ty, // Reset Lo class, this will be recomputed. Current = NoClass; + + // If this is a C++ record, classify the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + assert(!i->isVirtual() && !i->getType()->isDependentType() && + "Unexpected base class!"); + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + + // Classify this field. + // + // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a + // single eightbyte, each is classified separately. Each eightbyte gets + // initialized to class NO_CLASS. + Class FieldLo, FieldHi; + uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base); + classify(i->getType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + } + + // Classify the fields one at a time, merging the results. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index ea75c34..8a57d14 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -17,6 +17,23 @@ using namespace clang::driver; +void arg_iterator::SkipToNextArg() { + for (; Current != Args.end(); ++Current) { + // Done if there are no filters. + if (!Id0.isValid()) + break; + + // Otherwise require a match. + const Option &O = (*Current)->getOption(); + if (O.matches(Id0) || + (Id1.isValid() && O.matches(Id1)) || + (Id2.isValid() && O.matches(Id2))) + break; + } +} + +// + ArgList::ArgList(arglist_type &_Args) : Args(_Args) { } @@ -98,95 +115,46 @@ void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { } } -void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0)) { - A->claim(); - A->render(*this, Output); - } - } -} - -void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) { - A->claim(); - A->render(*this, Output); - } - } -} - void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0) || A->getOption().matches(Id1) || - A->getOption().matches(Id2)) { - A->claim(); - A->render(*this, Output); - } - } -} - -void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0)) { - A->claim(); - for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - Output.push_back(A->getValue(*this, i)); - } + for (arg_iterator it = filtered_begin(Id0, Id1, Id2), + ie = filtered_end(); it != ie; ++it) { + it->claim(); + it->render(*this, Output); } } void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, - OptSpecifier Id1) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) { - A->claim(); - for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - Output.push_back(A->getValue(*this, i)); - } + OptSpecifier Id1, OptSpecifier Id2) const { + for (arg_iterator it = filtered_begin(Id0, Id1, Id2), + ie = filtered_end(); it != ie; ++it) { + it->claim(); + for (unsigned i = 0, e = it->getNumValues(); i != e; ++i) + Output.push_back(it->getValue(*this, i)); } } void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, const char *Translation, bool Joined) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0)) { - A->claim(); - - if (Joined) { - std::string Value = Translation; - Value += A->getValue(*this, 0); - Output.push_back(MakeArgString(Value.c_str())); - } else { - Output.push_back(Translation); - Output.push_back(A->getValue(*this, 0)); - } + for (arg_iterator it = filtered_begin(Id0), + ie = filtered_end(); it != ie; ++it) { + it->claim(); + + if (Joined) { + Output.push_back(MakeArgString(llvm::StringRef(Translation) + + it->getValue(*this, 0))); + } else { + Output.push_back(Translation); + Output.push_back(it->getValue(*this, 0)); } } } void ArgList::ClaimAllArgs(OptSpecifier Id0) const { - // FIXME: Make fast. - for (const_iterator it = begin(), ie = end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(Id0)) - A->claim(); - } + for (arg_iterator it = filtered_begin(Id0), + ie = filtered_end(); it != ie; ++it) + it->claim(); } const char *ArgList::MakeArgString(const llvm::Twine &T) const { diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp index 672fe04..13f84c0 100644 --- a/lib/Driver/CC1Options.cpp +++ b/lib/Driver/CC1Options.cpp @@ -8,19 +8,14 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/CC1Options.h" -#include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" - +#include "clang/Driver/OptTable.h" +using namespace clang; using namespace clang::driver; using namespace clang::driver::options; using namespace clang::driver::cc1options; static OptTable::Info CC1InfoTable[] = { - // The InputOption info - { "", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID }, - // The UnknownOption info - { "", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID }, - #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index ffa627a..b819cda 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -85,9 +85,16 @@ bool Compilation::CleanupFileList(const ArgStringList &Files, for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); it != ie; ++it) { + llvm::sys::Path P(*it); std::string Error; + if (!P.isRegularFile()) { + // If we have a special file in our list, i.e. /dev/null + // then don't call eraseFromDisk() and just continue. + continue; + } + if (P.eraseFromDisk(false, &Error)) { // Failure is only failure if the file doesn't exist. There is a // race condition here due to the limited interface of diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index b40dc27..87357cf 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -965,10 +965,9 @@ void Driver::BuildJobs(Compilation &C) const { if (isa(Opt)) { bool DuplicateClaimed = false; - // FIXME: Use iterator. - for (ArgList::const_iterator it = C.getArgs().begin(), - ie = C.getArgs().end(); it != ie; ++it) { - if ((*it)->isClaimed() && (*it)->getOption().matches(&Opt)) { + for (arg_iterator it = C.getArgs().filtered_begin(&Opt), + ie = C.getArgs().filtered_end(); it != ie; ++it) { + if ((*it)->isClaimed()) { DuplicateClaimed = true; break; } diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp index eddaee0..d1af95c 100644 --- a/lib/Driver/DriverOptions.cpp +++ b/lib/Driver/DriverOptions.cpp @@ -15,11 +15,6 @@ using namespace clang::driver; using namespace clang::driver::options; static OptTable::Info InfoTable[] = { - // The InputOption info - { "", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID }, - // The UnknownOption info - { "", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID }, - #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 5f0551b..eb165cf 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -130,13 +130,9 @@ void Clang::AddPreprocessingOptions(const Driver &D, // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. - // - // FIXME: Use iterator. - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (!A->getOption().matches(options::OPT_clang_i_Group)) - continue; + for (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = it; if (A->getOption().matches(options::OPT_include)) { // Use PCH if the user requested it, except for C++ (for now). @@ -209,7 +205,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. // // FIXME: tblgen this. -static llvm::StringRef getARMTargetCPU(const ArgList &Args) { +static const char *getARMTargetCPU(const ArgList &Args) { // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. @@ -370,7 +366,8 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back(ABIName); // Set the CPU based on -march= and -mcpu=. - CmdArgs.push_back(Args.MakeArgString("-mcpu=" + getARMTargetCPU(Args))); + CmdArgs.push_back("-mcpu"); + CmdArgs.push_back(getARMTargetCPU(Args)); // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. @@ -421,15 +418,15 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. - CmdArgs.push_back("-soft-float"); - CmdArgs.push_back("-float-abi=soft"); + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi=soft"); } else if (FloatABI == "softfp") { // Floating point operations are hard, but argument passing is soft. - CmdArgs.push_back("-float-abi=soft"); + CmdArgs.push_back("-mfloat-abi=soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); - CmdArgs.push_back("-float-abi=hard"); + CmdArgs.push_back("-mfloat-abi=hard"); } } @@ -440,12 +437,12 @@ void Clang::AddX86TargetArgs(const ArgList &Args, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) - CmdArgs.push_back("--disable-red-zone"); + CmdArgs.push_back("-disable-red-zone"); if (Args.hasFlag(options::OPT_msoft_float, options::OPT_mno_soft_float, false)) - CmdArgs.push_back("--no-implicit-float"); + CmdArgs.push_back("-no-implicit-float"); const char *CPUName = 0; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { @@ -479,29 +476,25 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } if (CPUName) { - CmdArgs.push_back("--mcpu"); + CmdArgs.push_back("-mcpu"); CmdArgs.push_back(CPUName); } - // FIXME: Use iterator. - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(options::OPT_m_x86_Features_Group)) { - llvm::StringRef Name = A->getOption().getName(); + for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), + ie = Args.filtered_end(); it != ie; ++it) { + llvm::StringRef Name = it->getOption().getName(); + it->claim(); - // Skip over "-m". - assert(Name.startswith("-m") && "Invalid feature name."); - Name = Name.substr(2); + // Skip over "-m". + assert(Name.startswith("-m") && "Invalid feature name."); + Name = Name.substr(2); - bool IsNegative = Name.startswith("no-"); - if (IsNegative) - Name = Name.substr(3); + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); - A->claim(); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); - } + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } @@ -707,39 +700,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else Model = getToolChain().GetDefaultRelocationModel(); } - CmdArgs.push_back("--relocation-model"); - CmdArgs.push_back(Model); + if (llvm::StringRef(Model) != "pic") { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(Model); + } // Infer the __PIC__ value. // // FIXME: This isn't quite right on Darwin, which always sets // __PIC__=2. if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) { - if (Args.hasArg(options::OPT_fPIC)) - CmdArgs.push_back("-pic-level=2"); - else - CmdArgs.push_back("-pic-level=1"); + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(Args.hasArg(options::OPT_fPIC) ? "2" : "1"); } + if (!Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants)) + CmdArgs.push_back("-no-merge-all-constants"); + + // LLVM Code Generator Options. - if (Args.hasArg(options::OPT_ftime_report)) - CmdArgs.push_back("--time-passes"); // FIXME: Set --enable-unsafe-fp-math. if (Args.hasFlag(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) - CmdArgs.push_back("--disable-fp-elim"); + CmdArgs.push_back("-mdisable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, - options::OPT_fno_zero_initialized_in_bss, - true)) - CmdArgs.push_back("--nozero-initialized-in-bss"); + options::OPT_fno_zero_initialized_in_bss)) + CmdArgs.push_back("-mno-zero-initialized-in-bss"); if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm)) - CmdArgs.push_back("--asm-verbose"); - if (Args.hasArg(options::OPT_fdebug_pass_structure)) - CmdArgs.push_back("--debug-pass=Structure"); - if (Args.hasArg(options::OPT_fdebug_pass_arguments)) - CmdArgs.push_back("--debug-pass=Arguments"); - if (!Args.hasFlag(options::OPT_fmerge_all_constants, - options::OPT_fno_merge_all_constants)) - CmdArgs.push_back("--no-merge-all-constants"); + CmdArgs.push_back("-masm-verbose"); + if (Args.hasArg(options::OPT_fdebug_pass_structure)) { + CmdArgs.push_back("-mdebug-pass"); + CmdArgs.push_back("Structure"); + } + if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { + CmdArgs.push_back("-mdebug-pass"); + CmdArgs.push_back("Arguments"); + } // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more @@ -751,15 +747,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_mkernel)); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) - CmdArgs.push_back("--unwind-tables=1"); - else - CmdArgs.push_back("--unwind-tables=0"); + CmdArgs.push_back("-munwind-tables"); + + if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { + CmdArgs.push_back("-mlimit-float-precision"); + CmdArgs.push_back(A->getValue(Args)); + } // FIXME: Handle -mtune=. (void) Args.hasArg(options::OPT_mtune_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { - CmdArgs.push_back("-code-model"); + CmdArgs.push_back("-mcode-model"); CmdArgs.push_back(A->getValue(Args)); } @@ -785,11 +784,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().IsMathErrnoDefault())) CmdArgs.push_back("-fno-math-errno"); - if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { - CmdArgs.push_back("--limit-float-precision"); - CmdArgs.push_back(A->getValue(Args)); - } - Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_MQ)) || @@ -865,7 +859,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (Args.hasArg(options::OPT__relocatable_pch)) - CmdArgs.push_back("--relocatable-pch"); + CmdArgs.push_back("-relocatable-pch"); if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { CmdArgs.push_back("-fconstant-string-class"); @@ -873,13 +867,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Pass -fmessage-length=. + CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { - A->render(Args, CmdArgs); + CmdArgs.push_back(A->getValue(Args)); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. unsigned N = llvm::sys::Process::StandardErrColumns(); - CmdArgs.push_back("-fmessage-length"); CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); } @@ -931,30 +925,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks"); } + // -fexceptions=0 is default. if (needsExceptions(Args, InputType, getToolChain().getTriple())) CmdArgs.push_back("-fexceptions"); - else - CmdArgs.push_back("-fexceptions=0"); // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) CmdArgs.push_back("-fno-rtti"); // -fsigned-char is default. - if (!Args.hasFlag(options::OPT_fsigned_char, - options::OPT_funsigned_char, + if (!Args.hasFlag(options::OPT_fsigned_char, options::OPT_funsigned_char, isSignedCharDefault(getToolChain().getTriple()))) - CmdArgs.push_back("-fsigned-char=0"); + CmdArgs.push_back("-fno-signed-char"); // -fms-extensions=0 is default. - if (Args.hasFlag(options::OPT_fms_extensions, - options::OPT_fno_ms_extensions, + if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); // -fnext-runtime is default. - if (!Args.hasFlag(options::OPT_fnext_runtime, - options::OPT_fgnu_runtime, + if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, getToolChain().getTriple().getOS() == llvm::Triple::Darwin)) CmdArgs.push_back("-fgnu-runtime"); @@ -1092,15 +1082,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Explicitly warn that these options are unsupported, even though // we are allowing compilation to continue. - // FIXME: Use iterator. - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(options::OPT_pg)) { - A->claim(); - D.Diag(clang::diag::warn_drv_clang_unsupported) - << A->getAsString(Args); - } + for (arg_iterator it = Args.filtered_begin(options::OPT_pg), + ie = Args.filtered_end(); it != ie; ++it) { + it->claim(); + D.Diag(clang::diag::warn_drv_clang_unsupported) << it->getAsString(Args); } // Claim some arguments which clang supports automatically. @@ -1113,15 +1098,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Claim some arguments which clang doesn't support, but we don't // care to warn the user about. - - // FIXME: Use iterator. - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(options::OPT_clang_ignored_f_Group) || - A->getOption().matches(options::OPT_clang_ignored_m_Group)) - A->claim(); - } + Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); + Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); } void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, @@ -1394,18 +1372,13 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, // used to inhibit the default -fno-builtin-str{cat,cpy}. // // FIXME: Should we grow a better way to deal with "removing" args? - // - // FIXME: Use iterator. - for (ArgList::const_iterator it = Args.begin(), - ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(options::OPT_f_Group) || - A->getOption().matches(options::OPT_fsyntax_only)) { - if (!A->getOption().matches(options::OPT_fbuiltin_strcat) && - !A->getOption().matches(options::OPT_fbuiltin_strcpy)) { - A->claim(); - A->render(Args, CmdArgs); - } + for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group, + options::OPT_fsyntax_only), + ie = Args.filtered_end(); it != ie; ++it) { + if (!it->getOption().matches(options::OPT_fbuiltin_strcat) && + !it->getOption().matches(options::OPT_fbuiltin_strcpy)) { + it->claim(); + it->render(Args, CmdArgs); } } } else diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 750286b..3397677 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -135,6 +135,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("CC", TY_CXX) .Case("cp", TY_CXX) .Case("hh", TY_CXXHeader) + .Case("hpp", TY_CXXHeader) .Case("ads", TY_Ada) .Case("adb", TY_Ada) .Case("ast", TY_AST) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index e3cd6dd..f647c8a 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -14,25 +14,28 @@ #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/PCHReader.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" -#include "llvm/Support/Compiler.h" +#include "llvm/LLVMContext.h" #include "llvm/System/Path.h" - using namespace clang; -ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { +ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); } -ASTUnit::~ASTUnit() { +ASTUnit::~ASTUnit() { if (tempFile) llvm::sys::Path(getPCHFileName()).eraseFromDisk(); - + // The ASTUnit object owns the DiagnosticClient. delete Diags.getClient(); } @@ -41,7 +44,7 @@ namespace { /// \brief Gathers information from PCHReader that will be used to initialize /// a Preprocessor. -class VISIBILITY_HIDDEN PCHInfoCollector : public PCHReaderListener { +class PCHInfoCollector : public PCHReaderListener { LangOptions &LangOpt; HeaderSearch &HSI; std::string &TargetTriple; @@ -171,3 +174,90 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, return AST.take(); } + +namespace { + +class NullAction : public ASTFrontendAction { + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); + } + +public: + virtual bool hasCodeCompletionSupport() const { return false; } +}; + +} + +ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, + Diagnostic &Diags, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + // Create the compiler instance to use for building the AST. + CompilerInstance Clang(&llvm::getGlobalContext(), false); + llvm::OwningPtr AST; + NullAction Act; + + Clang.getInvocation() = CI; + + Clang.setDiagnostics(&Diags); + Clang.setDiagnosticClient(Diags.getClient()); + + // Create the target instance. + Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), + Clang.getTargetOpts())); + if (!Clang.hasTarget()) + goto error; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + + assert(Clang.getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST && + "FIXME: AST inputs not yet supported here!"); + + // Create the AST unit. + // + // FIXME: Use the provided diagnostic client. + AST.reset(new ASTUnit()); + + // Create a file manager object to provide access to and cache the filesystem. + Clang.setFileManager(&AST->getFileManager()); + + // Create the source manager. + Clang.setSourceManager(&AST->getSourceManager()); + + // Create the preprocessor. + Clang.createPreprocessor(); + + if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + /*IsAST=*/false)) + goto error; + + Act.Execute(); + + // Steal the created context and preprocessor, and take back the source and + // file managers. + AST->Ctx.reset(Clang.takeASTContext()); + AST->PP.reset(Clang.takePreprocessor()); + Clang.takeSourceManager(); + Clang.takeFileManager(); + + Act.EndSourceFile(); + + Clang.takeDiagnosticClient(); + Clang.takeDiagnostics(); + + return AST.take(); + +error: + Clang.takeSourceManager(); + Clang.takeFileManager(); + Clang.takeDiagnosticClient(); + Clang.takeDiagnostics(); + return 0; +} diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index ede3d47..5df1ece 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -30,7 +30,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PathDiagnosticClients.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" @@ -62,7 +61,7 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix, namespace { - class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer { + class AnalysisConsumer : public ASTConsumer { public: typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); @@ -312,7 +311,8 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, } -static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, +static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D, GRTransferFuncs* tf) { llvm::OwningPtr TF(tf); @@ -327,10 +327,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl * return; GRExprEngine Eng(mgr); - - Eng.setTransferFunctions(tf); - Eng.RegisterInternalChecks(); // FIXME: Internal checks should just - // automatically register. if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); @@ -339,6 +335,8 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl * if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); + + Eng.setTransferFunctions(tf); // Set the graph auditor. llvm::OwningPtr Auditor; @@ -455,26 +453,8 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { - if (!D) - return; - - C.DisplayFunction(D); - llvm::OwningPtr TF(CreateCallInliner(mgr.getASTContext())); - - // Construct the analysis engine. - GRExprEngine Eng(mgr); - - Eng.setTransferFunctions(TF.get()); - Eng.RegisterInternalChecks(); - RegisterAppleChecks(Eng, *D); - - // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getStackFrame(D)); - - // Visualize the exploded graph. - if (mgr.shouldVisualizeGraphviz()) - Eng.ViewGraph(mgr.shouldTrimGraph()); + ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext())); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index bc56029..9dc109d 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -25,12 +25,9 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/StandardPasses.h" #include "llvm/Support/Timer.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" @@ -39,10 +36,11 @@ using namespace clang; using namespace llvm; namespace { - class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer { + class BackendConsumer : public ASTConsumer { BackendAction Action; - CodeGenOptions CodeGenOpts; - TargetOptions TargetOpts; + const CodeGenOptions &CodeGenOpts; + const LangOptions &LangOpts; + const TargetOptions &TargetOpts; llvm::raw_ostream *AsmOutStream; llvm::formatted_raw_ostream FormattedOutStream; ASTContext *Context; @@ -78,10 +76,12 @@ namespace { public: BackendConsumer(BackendAction action, Diagnostic &Diags, const LangOptions &langopts, const CodeGenOptions &compopts, - const TargetOptions &targetopts, const std::string &infile, - llvm::raw_ostream* OS, LLVMContext& C) : + const TargetOptions &targetopts, bool TimePasses, + const std::string &infile, llvm::raw_ostream *OS, + LLVMContext& C) : Action(action), CodeGenOpts(compopts), + LangOpts(langopts), TargetOpts(targetopts), AsmOutStream(OS), LLVMIRGeneration("LLVM IR Generation Time"), @@ -94,8 +94,7 @@ namespace { FormattedOutStream.setStream(*AsmOutStream, formatted_raw_ostream::PRESERVE_STREAM); - // Enable -time-passes if -ftime-report is enabled. - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesIsEnabled = TimePasses; } ~BackendConsumer() { @@ -109,7 +108,7 @@ namespace { virtual void Initialize(ASTContext &Ctx) { Context = &Ctx; - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.startTimer(); Gen->Initialize(Ctx); @@ -118,7 +117,7 @@ namespace { ModuleProvider = new ExistingModuleProvider(TheModule); TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.stopTimer(); } @@ -127,24 +126,24 @@ namespace { Context->getSourceManager(), "LLVM IR generation of declaration"); - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.startTimer(); Gen->HandleTopLevelDecl(D); - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.stopTimer(); } virtual void HandleTranslationUnit(ASTContext &C) { { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.startTimer(); Gen->HandleTranslationUnit(C); - if (CodeGenOpts.TimePasses) + if (llvm::TimePassesIsEnabled) LLVMIRGeneration.stopTimer(); } @@ -215,11 +214,50 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { return false; } + // FIXME: Expose these capabilities via actual APIs!!!! Aside from just + // being gross, this is also totally broken if we ever care about + // concurrency. + std::vector BackendArgs; + BackendArgs.push_back("clang"); // Fake program name. + if (CodeGenOpts.AsmVerbose) + BackendArgs.push_back("-asm-verbose"); + if (!CodeGenOpts.CodeModel.empty()) { + BackendArgs.push_back("-code-model"); + BackendArgs.push_back(CodeGenOpts.CodeModel.c_str()); + } + if (!CodeGenOpts.DebugPass.empty()) { + BackendArgs.push_back("-debug-pass"); + BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); + } + if (CodeGenOpts.DisableFPElim) + BackendArgs.push_back("-disable-fp-elim"); + if (!CodeGenOpts.FloatABI.empty()) { + BackendArgs.push_back("-float-abi"); + BackendArgs.push_back(CodeGenOpts.FloatABI.c_str()); + } + if (!CodeGenOpts.LimitFloatPrecision.empty()) { + BackendArgs.push_back("-limit-float-precision"); + BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); + } + if (CodeGenOpts.NoZeroInitializedInBSS) + BackendArgs.push_back("-nozero-initialized-in-bss"); + if (CodeGenOpts.SoftFloat) + BackendArgs.push_back("-soft-float"); + BackendArgs.push_back("-relocation-model"); + BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str()); + if (llvm::TimePassesIsEnabled) + BackendArgs.push_back("-time-passes"); + if (CodeGenOpts.UnwindTables) + BackendArgs.push_back("-unwind-tables"); + BackendArgs.push_back(0); + llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, + (char**) &BackendArgs[0]); + std::string FeaturesStr; if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { SubtargetFeatures Features; Features.setCPU(TargetOpts.CPU); - for (std::vector::iterator + for (std::vector::const_iterator it = TargetOpts.Features.begin(), ie = TargetOpts.Features.end(); it != ie; ++it) Features.AddFeature(*it); @@ -306,7 +344,7 @@ void BackendConsumer::CreatePasses() { llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, CodeGenOpts.UnitAtATime, CodeGenOpts.UnrollLoops, - CodeGenOpts.SimplifyLibCalls, + /*SimplifyLibCalls=*/!LangOpts.NoBuiltin, /*HaveExceptions=*/true, InliningPass); } @@ -318,7 +356,7 @@ void BackendConsumer::EmitAssembly() { if (!TheModule || !TheTargetData) return; - TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0); + TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); // Make sure IR generation is happy with the module. This is // released by the module provider. @@ -375,9 +413,10 @@ ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, const LangOptions &LangOpts, const CodeGenOptions &CodeGenOpts, const TargetOptions &TargetOpts, + bool TimePasses, const std::string& InFile, llvm::raw_ostream* OS, LLVMContext& C) { return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, - TargetOpts, InFile, OS, C); + TargetOpts, TimePasses, InFile, OS, C); } diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 3f0f430..03123d3 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangFrontend HTMLPrint.cpp InitHeaderSearch.cpp InitPreprocessor.cpp + LangStandards.cpp PCHReader.cpp PCHReaderDecl.cpp PCHReaderStmt.cpp diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 339a1c4..7296246 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -22,7 +22,6 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -40,7 +39,7 @@ using namespace clang::io; //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN PTHEntry { +class PTHEntry { Offset TokenData, PPCondData; public: @@ -54,7 +53,7 @@ public: }; -class VISIBILITY_HIDDEN PTHEntryKeyVariant { +class PTHEntryKeyVariant { union { const FileEntry* FE; const char* Path; }; enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind; struct stat *StatBuf; @@ -105,7 +104,7 @@ public: } }; -class VISIBILITY_HIDDEN FileEntryPTHEntryInfo { +class FileEntryPTHEntryInfo { public: typedef PTHEntryKeyVariant key_type; typedef key_type key_type_ref; @@ -169,7 +168,7 @@ typedef llvm::DenseMap IDMap; typedef llvm::StringMap CachedStrsTy; namespace { -class VISIBILITY_HIDDEN PTHWriter { +class PTHWriter { IDMap IM; llvm::raw_fd_ostream& Out; Preprocessor& PP; @@ -483,7 +482,8 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) { if (!B) continue; FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); - Lexer L(FID, SM, LOpts); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer L(FID, FromFile, SM, LOpts); PM.insert(FE, LexTokens(L)); } @@ -577,7 +577,7 @@ public: }; namespace { -class VISIBILITY_HIDDEN PTHIdentifierTableTrait { +class PTHIdentifierTableTrait { public: typedef PTHIdKey* key_type; typedef key_type key_type_ref; diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 0365761..1083d5e 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -27,7 +27,9 @@ #include "llvm/LLVMContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" #include "llvm/System/Path.h" +#include "llvm/System/Program.h" using namespace clang; CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, @@ -255,6 +257,16 @@ void CompilerInstance::createCodeCompletionConsumer() { getFrontendOpts().DebugCodeCompletionPrinter, getFrontendOpts().ShowMacrosInCodeCompletion, llvm::outs())); + + if (CompletionConsumer->isOutputBinary() && + llvm::sys::Program::ChangeStdoutToBinary()) { + getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); + CompletionConsumer.reset(); + } +} + +void CompilerInstance::createFrontendTimer() { + FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); } CodeCompleteConsumer * @@ -321,7 +333,7 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, &OutputPathName); if (!OS) { // FIXME: Don't fail this way. - llvm::errs() << "ERROR: " << Error << "\n"; + llvm::errs() << "error: " << Error << "\n"; ::exit(1); } @@ -353,16 +365,16 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, OutFile = "-"; } - llvm::raw_fd_ostream *OS = + llvm::OwningPtr OS( new llvm::raw_fd_ostream(OutFile.c_str(), Error, - (Binary ? llvm::raw_fd_ostream::F_Binary : 0)); - if (!OS) + (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); + if (!Error.empty()) return 0; if (ResultPathName) *ResultPathName = OutFile; - return OS; + return OS.take(); } // Initialization Utilities diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b4a79c6..c537507 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -8,20 +8,32 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInvocation.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/PCHReader.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" using namespace clang; -void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, - const llvm::SmallVectorImpl &Args) { -} - static const char *getAnalysisName(Analyses Kind) { switch (Kind) { default: llvm::llvm_unreachable("Unknown analysis store!"); #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ - case NAME: return CMDFLAG; + case NAME: return "-" CMDFLAG; #include "clang/Frontend/Analyses.def" } } @@ -56,6 +68,10 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { } } +//===----------------------------------------------------------------------===// +// Serialization (to args) +//===----------------------------------------------------------------------===// + static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector &Res) { for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) @@ -93,7 +109,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, if (Opts.EnableExperimentalChecks) Res.push_back("-analyzer-experimental-checks"); if (Opts.EnableExperimentalInternalChecks) - Res.push_back("-analyzer-experimental-internal-checls"); + Res.push_back("-analyzer-experimental-internal-checks"); } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, @@ -106,20 +122,56 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-disable-red-zone"); if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); - // NoCommon is only derived. + if (Opts.NoCommon) + Res.push_back("-fno-common"); if (Opts.NoImplicitFloat) Res.push_back("-no-implicit-float"); if (Opts.OptimizeSize) { assert(Opts.OptimizationLevel == 2 && "Invalid options!"); Res.push_back("-Os"); - } else if (Opts.OptimizationLevel == 0) - Res.push_back("-O" + Opts.OptimizationLevel); + } else if (Opts.OptimizationLevel != 0) + Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); + if (!Opts.MainFileName.empty()) { + Res.push_back("-main-file-name"); + Res.push_back(Opts.MainFileName); + } // SimplifyLibCalls is only derived. // TimePasses is only derived. // UnitAtATime is unused. // UnrollLoops is only derived. // VerifyModule is only derived. // Inlining is only derived. + + if (Opts.AsmVerbose) + Res.push_back("-masm-verbose"); + if (!Opts.CodeModel.empty()) { + Res.push_back("-mcode-model"); + Res.push_back(Opts.CodeModel); + } + if (!Opts.DebugPass.empty()) { + Res.push_back("-mdebug-pass"); + Res.push_back(Opts.DebugPass); + } + if (Opts.DisableFPElim) + Res.push_back("-mdisable-fp-elim"); + if (!Opts.FloatABI.empty()) { + Res.push_back("-mfloat-abi"); + Res.push_back(Opts.FloatABI); + } + if (!Opts.LimitFloatPrecision.empty()) { + Res.push_back("-mlimit-float-precision"); + Res.push_back(Opts.LimitFloatPrecision); + } + if (Opts.NoZeroInitializedInBSS) + Res.push_back("-mno-zero-initialized-bss"); + if (Opts.SoftFloat) + Res.push_back("-msoft-float"); + if (Opts.UnwindTables) + Res.push_back("-munwind-tables"); + if (Opts.RelocationModel != "pic") { + Res.push_back("-mrelocation-model"); + Res.push_back(Opts.RelocationModel); + } } static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, @@ -178,18 +230,18 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, static const char *getInputKindName(FrontendOptions::InputKind Kind) { switch (Kind) { - case FrontendOptions::IK_None: break; - case FrontendOptions::IK_AST: return "ast"; - case FrontendOptions::IK_Asm: return "assembler-with-cpp"; - case FrontendOptions::IK_C: return "c"; - case FrontendOptions::IK_CXX: return "c++"; - case FrontendOptions::IK_ObjC: return "objective-c"; - case FrontendOptions::IK_ObjCXX: return "objective-c++"; - case FrontendOptions::IK_OpenCL: return "cl"; - case FrontendOptions::IK_PreprocessedC: return "cpp-output"; - case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output"; - case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output"; - case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output"; + case FrontendOptions::IK_None: break; + case FrontendOptions::IK_AST: return "ast"; + case FrontendOptions::IK_Asm: return "assembler-with-cpp"; + case FrontendOptions::IK_C: return "c"; + case FrontendOptions::IK_CXX: return "c++"; + case FrontendOptions::IK_ObjC: return "objective-c"; + case FrontendOptions::IK_ObjCXX: return "objective-c++"; + case FrontendOptions::IK_OpenCL: return "cl"; + case FrontendOptions::IK_PreprocessedC: return "cpp-output"; + case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output"; + case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output"; + case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; } llvm::llvm_unreachable("Unexpected language kind!"); @@ -247,7 +299,7 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); if (Opts.ShowStats) - Res.push_back("-stats"); + Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); @@ -305,13 +357,13 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, /// User specified include entries. for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; - if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied)) + if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) llvm::llvm_report_error("Invalid option set!"); if (E.IsUserSupplied) { if (E.Group == frontend::After) { Res.push_back("-idirafter"); } else if (E.Group == frontend::Quoted) { - Res.push_back("-iquoted"); + Res.push_back("-iquote"); } else if (E.Group == frontend::System) { Res.push_back("-isystem"); } else { @@ -391,8 +443,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-lax-vector-conversions"); if (Opts.AltiVec) Res.push_back("-faltivec"); - Res.push_back("-fexceptions"); - Res.push_back(Opts.Exceptions ? "1" : "0"); + if (Opts.Exceptions) + Res.push_back("-fexceptions"); if (!Opts.Rtti) Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) @@ -406,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.POSIXThreads) Res.push_back("-pthread"); if (Opts.Blocks) - Res.push_back("-fblocks=1"); + Res.push_back("-fblocks"); if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); if (!Opts.MathErrno) @@ -425,12 +477,13 @@ static void LangOptsToArgs(const LangOptions &Opts, } if (Opts.ObjCGCBitmapPrint) Res.push_back("-print-ivar-layout"); - Res.push_back("-faccess-control"); - Res.push_back(Opts.AccessControl ? "1" : "0"); - Res.push_back("-fsigned-char"); - Res.push_back(Opts.CharIsSigned ? "1" : "0"); - Res.push_back("-fshort-wchar"); - Res.push_back(Opts.ShortWChar ? "1" : "0"); + // FIXME: Don't forget to update when the default changes! + if (Opts.AccessControl) + Res.push_back("-faccess-control"); + if (!Opts.CharIsSigned) + Res.push_back("-fno-signed-char"); + if (Opts.ShortWChar) + Res.push_back("-fshort-wchar"); if (!Opts.ElideConstructors) Res.push_back("-fno-elide-constructors"); if (Opts.getGCMode() != LangOptions::NonGC) { @@ -444,7 +497,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.getVisibilityMode() != LangOptions::Default) { Res.push_back("-fvisibility"); if (Opts.getVisibilityMode() == LangOptions::Hidden) { - Res.push_back("default"); + Res.push_back("hidden"); } else { assert(Opts.getVisibilityMode() == LangOptions::Protected && "Invalid visibility!"); @@ -455,15 +508,11 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-stack-protector"); Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); } - if (Opts.getMainFileName()) { - Res.push_back("-main-file-name"); - Res.push_back(Opts.getMainFileName()); - } if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { Res.push_back("-ftemplate-depth"); Res.push_back(llvm::utostr(Opts.InstantiationDepth)); } - if (Opts.ObjCConstantStringClass) { + if (!Opts.ObjCConstantStringClass.empty()) { Res.push_back("-fconstant-string-class"); Res.push_back(Opts.ObjCConstantStringClass); } @@ -472,28 +521,34 @@ static void LangOptsToArgs(const LangOptions &Opts, static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, std::vector &Res) { for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) - Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first); + Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") + + Opts.Macros[i].first); for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { + // FIXME: We need to avoid reincluding the implicit PCH and PTH includes. Res.push_back("-include"); Res.push_back(Opts.Includes[i]); } for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) { Res.push_back("-imacros"); - Res.push_back(Opts.Includes[i]); + Res.push_back(Opts.MacroIncludes[i]); } if (!Opts.UsePredefines) Res.push_back("-undef"); if (!Opts.ImplicitPCHInclude.empty()) { - Res.push_back("-implicit-pch-include"); + Res.push_back("-include-pch"); Res.push_back(Opts.ImplicitPCHInclude); } if (!Opts.ImplicitPTHInclude.empty()) { - Res.push_back("-implicit-pth-include"); + Res.push_back("-include-pth"); Res.push_back(Opts.ImplicitPTHInclude); } if (!Opts.TokenCache.empty()) { - Res.push_back("-token-cache"); - Res.push_back(Opts.TokenCache); + if (Opts.ImplicitPTHInclude.empty()) { + Res.push_back("-token-cache"); + Res.push_back(Opts.TokenCache); + } else + assert(Opts.ImplicitPTHInclude == Opts.TokenCache && + "Unsupported option combination!"); } } @@ -520,7 +575,7 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-triple"); Res.push_back(Opts.Triple); if (!Opts.CPU.empty()) { - Res.push_back("-target-cpu"); + Res.push_back("-mcpu"); Res.push_back(Opts.CPU); } if (!Opts.ABI.empty()) { @@ -545,3 +600,663 @@ void CompilerInvocation::toArgs(std::vector &Res) { PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); TargetOptsToArgs(getTargetOpts(), Res); } + +//===----------------------------------------------------------------------===// +// Deserialization (to args) +//===----------------------------------------------------------------------===// + +using namespace clang::driver; +using namespace clang::driver::cc1options; + +static llvm::StringRef getLastArgValue(ArgList &Args, cc1options::ID ID, + llvm::StringRef Default = "") { + if (Arg *A = Args.getLastArg(ID)) + return A->getValue(Args); + return Default; +} + +static int getLastArgIntValue(ArgList &Args, cc1options::ID ID, + int Default, Diagnostic &Diags) { + Arg *A = Args.getLastArg(ID); + if (!A) + return Default; + + int Res = Default; + if (llvm::StringRef(A->getValue(Args)).getAsInteger(10, Res)) + Diags.Report(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(Args); + + return Res; +} + +static std::vector +getAllArgValues(ArgList &Args, cc1options::ID ID) { + llvm::SmallVector Values; + Args.AddAllArgValues(Values, ID); + return std::vector(Values.begin(), Values.end()); +} + +// + +static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + + Opts.AnalysisList.clear(); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \ + if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME); +#include "clang/Frontend/Analyses.def" + + if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisStores Value = llvm::StringSwitch(Name) +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumStores); + // FIXME: Error handling. + if (Value == NumStores) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisStoreOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisConstraints Value = llvm::StringSwitch(Name) +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumConstraints); + // FIXME: Error handling. + if (Value == NumConstraints) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisConstraintsOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisDiagClients Value = llvm::StringSwitch(Name) +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ + .Case(CMDFLAG, PD_##NAME) +#include "clang/Frontend/Analyses.def" + .Default(NUM_ANALYSIS_DIAG_CLIENTS); + // FIXME: Error handling. + if (Value == NUM_ANALYSIS_DIAG_CLIENTS) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisDiagOpt = Value; + } + + Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); + Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); + Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); + Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); + Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); + Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); + Opts.EnableExperimentalInternalChecks = + Args.hasArg(OPT_analyzer_experimental_internal_checks); + Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); +} + +static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + // -Os implies -O2 + if (Args.hasArg(OPT_Os)) + Opts.OptimizationLevel = 2; + else { + Opts.OptimizationLevel = getLastArgIntValue(Args, OPT_O, 0, Diags); + if (Opts.OptimizationLevel > 3) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; + Opts.OptimizationLevel = 3; + } + } + + // We must always run at least the always inlining pass. + Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining + : CodeGenOptions::OnlyAlwaysInlining; + + Opts.DebugInfo = Args.hasArg(OPT_g); + Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); + Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); + Opts.NoCommon = Args.hasArg(OPT_fno_common); + Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); + Opts.OptimizeSize = Args.hasArg(OPT_Os); + Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + + Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); + Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model); + Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass); + Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); + Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi); + Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision); + Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.SoftFloat = Args.hasArg(OPT_msoft_float); + Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); + Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); + + Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); + + // FIXME: Put elsewhere? +#ifdef NDEBUG + Opts.VerifyModule = 0; +#else + Opts.VerifyModule = 1; +#endif +} + +static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.OutputFile = getLastArgValue(Args, OPT_dependency_file); + Opts.Targets = getAllArgValues(Args, OPT_MT); + Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); + Opts.UsePhonyTargets = Args.hasArg(OPT_MP); +} + +static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + Opts.IgnoreWarnings = Args.hasArg(OPT_w); + Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); + Opts.Pedantic = Args.hasArg(OPT_pedantic); + Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); + Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); + Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics); + Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column); + Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); + Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); + Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); + Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); + Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information); + Opts.Warnings = getAllArgValues(Args, OPT_W); +} + +static FrontendOptions::InputKind +ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { + using namespace cc1options; + Opts.ProgramAction = frontend::ParseSyntaxOnly; + if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { + switch (A->getOption().getID()) { + default: + assert(0 && "Invalid option in group!"); + case OPT_ast_dump: + Opts.ProgramAction = frontend::ASTDump; break; + case OPT_ast_print: + Opts.ProgramAction = frontend::ASTPrint; break; + case OPT_ast_print_xml: + Opts.ProgramAction = frontend::ASTPrintXML; break; + case OPT_ast_view: + Opts.ProgramAction = frontend::ASTView; break; + case OPT_dump_raw_tokens: + Opts.ProgramAction = frontend::DumpRawTokens; break; + case OPT_dump_record_layouts: + Opts.ProgramAction = frontend::DumpRecordLayouts; break; + case OPT_dump_tokens: + Opts.ProgramAction = frontend::DumpTokens; break; + case OPT_S: + Opts.ProgramAction = frontend::EmitAssembly; break; + case OPT_emit_llvm_bc: + Opts.ProgramAction = frontend::EmitBC; break; + case OPT_emit_html: + Opts.ProgramAction = frontend::EmitHTML; break; + case OPT_emit_llvm: + Opts.ProgramAction = frontend::EmitLLVM; break; + case OPT_emit_llvm_only: + Opts.ProgramAction = frontend::EmitLLVMOnly; break; + case OPT_fixit: + Opts.ProgramAction = frontend::FixIt; break; + case OPT_emit_pch: + Opts.ProgramAction = frontend::GeneratePCH; break; + case OPT_emit_pth: + Opts.ProgramAction = frontend::GeneratePTH; break; + case OPT_parse_noop: + Opts.ProgramAction = frontend::ParseNoop; break; + case OPT_parse_print_callbacks: + Opts.ProgramAction = frontend::ParsePrintCallbacks; break; + case OPT_fsyntax_only: + Opts.ProgramAction = frontend::ParseSyntaxOnly; break; + case OPT_print_decl_contexts: + Opts.ProgramAction = frontend::PrintDeclContext; break; + case OPT_E: + Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_rewrite_blocks: + Opts.ProgramAction = frontend::RewriteBlocks; break; + case OPT_rewrite_macros: + Opts.ProgramAction = frontend::RewriteMacros; break; + case OPT_rewrite_objc: + Opts.ProgramAction = frontend::RewriteObjC; break; + case OPT_rewrite_test: + Opts.ProgramAction = frontend::RewriteTest; break; + case OPT_analyze: + Opts.ProgramAction = frontend::RunAnalysis; break; + case OPT_Eonly: + Opts.ProgramAction = frontend::RunPreprocessorOnly; break; + } + } + if (const Arg *A = Args.getLastArg(OPT_plugin)) { + Opts.ProgramAction = frontend::PluginAction; + Opts.ActionName = A->getValue(Args); + } + + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { + Opts.CodeCompletionAt = + ParsedSourceLocation::FromString(A->getValue(Args)); + if (Opts.CodeCompletionAt.FileName.empty()) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + Opts.DebugCodeCompletionPrinter = + !Args.hasArg(OPT_no_code_completion_debug_printer); + Opts.DisableFree = Args.hasArg(OPT_disable_free); + Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only); + + Opts.FixItLocations.clear(); + for (arg_iterator it = Args.filtered_begin(OPT_fixit_at), + ie = Args.filtered_end(); it != ie; ++it) { + const char *Loc = it->getValue(Args); + ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc); + + if (PSL.FileName.empty()) { + Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc; + continue; + } + + Opts.FixItLocations.push_back(PSL); + } + + Opts.OutputFile = getLastArgValue(Args, OPT_o); + Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); + Opts.ShowStats = Args.hasArg(OPT_print_stats); + Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); + + FrontendOptions::InputKind DashX = FrontendOptions::IK_None; + if (const Arg *A = Args.getLastArg(OPT_x)) { + DashX = llvm::StringSwitch(A->getValue(Args)) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c++", FrontendOptions::IK_CXX) + .Case("objective-c", FrontendOptions::IK_ObjC) + .Case("objective-c++", FrontendOptions::IK_ObjCXX) + .Case("cpp-output", FrontendOptions::IK_PreprocessedC) + .Case("assembler-with-cpp", FrontendOptions::IK_Asm) + .Case("c++-cpp-output", FrontendOptions::IK_PreprocessedCXX) + .Case("objective-c-cpp-output", FrontendOptions::IK_PreprocessedObjC) + .Case("objective-c++-cpp-output", FrontendOptions::IK_PreprocessedObjCXX) + .Case("c-header", FrontendOptions::IK_C) + .Case("objective-c-header", FrontendOptions::IK_ObjC) + .Case("c++-header", FrontendOptions::IK_CXX) + .Case("objective-c++-header", FrontendOptions::IK_ObjCXX) + .Case("ast", FrontendOptions::IK_AST) + .Default(FrontendOptions::IK_None); + if (DashX == FrontendOptions::IK_None) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + // '-' is the default input if none is given. + std::vector Inputs = getAllArgValues(Args, OPT_INPUT); + Opts.Inputs.clear(); + if (Inputs.empty()) + Inputs.push_back("-"); + for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { + FrontendOptions::InputKind IK = DashX; + if (IK == FrontendOptions::IK_None) { + IK = FrontendOptions::getInputKindForExtension( + llvm::StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Remove this hack. + if (i == 0) + DashX = IK; + } + Opts.Inputs.push_back(std::make_pair(IK, Inputs[i])); + } + + return DashX; +} + +static std::string GetBuiltinIncludePath(const char *Argv0, + void *MainAddr) { + llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); + + if (!P.isEmpty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang//include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + P.appendComponent("include"); + } + + return P.str(); +} + +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, + const char *Argv0, void *MainAddr) { + using namespace cc1options; + Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); + Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.BuiltinIncludePath = ""; + // FIXME: Add an option for this, its a slow call. + if (!Args.hasArg(OPT_nobuiltininc)) + Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr); + + // Add -I... and -F... options in order. + for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Angled, true, + /*IsFramework=*/ it->getOption().matches(OPT_F)); + + // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. + llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. + for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, + OPT_iwithprefixbefore), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_iprefix)) + Prefix = it->getValue(Args); + else if (it->getOption().matches(OPT_iwithprefix)) + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::System, false, false); + else + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::Angled, false, false); + } + + for (arg_iterator it = Args.filtered_begin(OPT_idirafter), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::After, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_iquote), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Quoted, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::System, true, false); + + // FIXME: Need options for the various environment variables! +} + +static void ParseLangArgs(LangOptions &Opts, ArgList &Args, + FrontendOptions::InputKind IK, + Diagnostic &Diags) { + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend soley on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + if (IK == FrontendOptions::IK_Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK == FrontendOptions::IK_ObjC || + IK == FrontendOptions::IK_ObjCXX || + IK == FrontendOptions::IK_PreprocessedObjC || + IK == FrontendOptions::IK_PreprocessedObjCXX) { + Opts.ObjC1 = Opts.ObjC2 = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { + LangStd = llvm::StringSwitch(A->getValue(Args)) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, LangStandard::lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(LangStandard::lang_unspecified); + if (LangStd == LangStandard::lang_unspecified) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK) { + case FrontendOptions::IK_None: + case FrontendOptions::IK_AST: + assert(0 && "Invalid input kind!"); + case FrontendOptions::IK_OpenCL: + LangStd = LangStandard::lang_opencl; + break; + case FrontendOptions::IK_Asm: + case FrontendOptions::IK_C: + case FrontendOptions::IK_PreprocessedC: + case FrontendOptions::IK_ObjC: + case FrontendOptions::IK_PreprocessedObjC: + LangStd = LangStandard::lang_gnu99; + break; + case FrontendOptions::IK_CXX: + case FrontendOptions::IK_PreprocessedCXX: + case FrontendOptions::IK_ObjCXX: + case FrontendOptions::IK_PreprocessedObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.BCPLComment = Std.hasBCPLComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.LaxVectorConversions = 1; + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + + if (Opts.CPlusPlus) + Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); + + if (Args.hasArg(OPT_fobjc_gc_only)) + Opts.setGCMode(LangOptions::GCOnly); + else if (Args.hasArg(OPT_fobjc_gc)) + Opts.setGCMode(LangOptions::HybridGC); + + if (Args.hasArg(OPT_print_ivar_layout)) + Opts.ObjCGCBitmapPrint = 1; + + if (Args.hasArg(OPT_faltivec)) + Opts.AltiVec = 1; + + if (Args.hasArg(OPT_pthread)) + Opts.POSIXThreads = 1; + + llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility, + "default"); + if (Vis == "default") + Opts.setVisibilityMode(LangOptions::Default); + else if (Vis == "hidden") + Opts.setVisibilityMode(LangOptions::Hidden); + else if (Vis == "protected") + Opts.setVisibilityMode(LangOptions::Protected); + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + + Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; + if (Args.hasArg(OPT_trigraphs)) + Opts.Trigraphs = 1; + + Opts.DollarIdents = !Opts.AsmPreprocessor; + if (Args.hasArg(OPT_fdollars_in_identifiers)) + Opts.DollarIdents = 1; + + Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); + Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); + if (Args.hasArg(OPT_fno_lax_vector_conversions)) + Opts.LaxVectorConversions = 0; + Opts.Exceptions = Args.hasArg(OPT_fexceptions); + Opts.Rtti = !Args.hasArg(OPT_fno_rtti); + Opts.Blocks = Args.hasArg(OPT_fblocks); + Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); + Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); + Opts.Freestanding = Args.hasArg(OPT_ffreestanding); + Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); + Opts.AccessControl = Args.hasArg(OPT_faccess_control); + Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); + Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno); + Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, + Diags); + Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); + Opts.ObjCConstantStringClass = getLastArgValue(Args, + OPT_fconstant_string_class); + Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); + Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); + Opts.Static = Args.hasArg(OPT_static_define); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. + unsigned Opt = + Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); + Opts.Optimize = Opt != 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInline = !Opt; + + unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags); + switch (SSP) { + default: + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; + break; + case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; + case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; + case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; + } +} + +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); + Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); + if (const Arg *A = Args.getLastArg(OPT_token_cache)) + Opts.TokenCache = A->getValue(Args); + else + Opts.TokenCache = Opts.ImplicitPTHInclude; + Opts.UsePredefines = !Args.hasArg(OPT_undef); + + // Add macros from the command line. + for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_D)) + Opts.addMacroDef(it->getValue(Args)); + else + Opts.addMacroUndef(it->getValue(Args)); + } + + Opts.MacroIncludes = getAllArgValues(Args, OPT_imacros); + + // Add the ordered list of -includes. + for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, + OPT_include_pth), + ie = Args.filtered_end(); it != ie; ++it) { + // PCH is handled specially, we need to extra the original include path. + if (it->getOption().matches(OPT_include_pch)) { + std::string OriginalFile = + PCHReader::getOriginalSourceFile(it->getValue(Args)); + + // FIXME: Don't fail like this. + if (OriginalFile.empty()) + exit(1); + + Opts.Includes.push_back(OriginalFile); + } else + Opts.Includes.push_back(it->getValue(Args)); + } +} + +static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.ShowCPP = !Args.hasArg(OPT_dM); + Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); + Opts.ShowLineMarkers = !Args.hasArg(OPT_P); + Opts.ShowComments = Args.hasArg(OPT_C); + Opts.ShowMacroComments = Args.hasArg(OPT_CC); +} + +static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.ABI = getLastArgValue(Args, OPT_target_abi); + Opts.CPU = getLastArgValue(Args, OPT_mcpu); + Opts.Triple = getLastArgValue(Args, OPT_triple); + Opts.Features = getAllArgValues(Args, OPT_target_feature); + + // Use the host triple if unspecified. + if (Opts.Triple.empty()) + Opts.Triple = llvm::sys::getHostTriple(); +} + +// + +void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, + const char **ArgBegin, + const char **ArgEnd, + const char *Argv0, + void *MainAddr, + Diagnostic &Diags) { + // Parse the arguments. + llvm::OwningPtr Opts(createCC1OptTable()); + unsigned MissingArgIndex, MissingArgCount; + llvm::OwningPtr Args( + Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Issue errors on unknown arguments. + for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + + ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); + ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags); + ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); + ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); + FrontendOptions::InputKind DashX = + ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args, + Argv0, MainAddr); + if (DashX != FrontendOptions::IK_AST) + ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args); + ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); + ParseTargetArgs(Res.getTargetOpts(), *Args); +} diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index c7f9359..478c339 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -21,14 +21,13 @@ #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include using namespace clang; namespace { -class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks { +class DependencyFileCallback : public PPCallbacks { std::vector Files; llvm::StringSet<> FilesSet; const Preprocessor *PP; diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp index 26bb6cc..e7a66b1 100644 --- a/lib/Frontend/DiagChecker.cpp +++ b/lib/Frontend/DiagChecker.cpp @@ -149,7 +149,8 @@ static void FindExpectedDiags(Preprocessor &PP, FileID FID = PP.getSourceManager().getMainFileID(); // Create a lexer to lex all the tokens of the main file in raw mode. - Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID); + Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions()); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index ff63a0d..91c946c 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -21,7 +21,7 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {} +FrontendAction::FrontendAction() : Instance(0) {} FrontendAction::~FrontendAction() {} @@ -144,8 +144,11 @@ void FrontendAction::Execute() { return; } - llvm::TimeRegion Timer(CurrentTimer); - ExecuteAction(); + if (CI.hasFrontendTimer()) { + llvm::TimeRegion Timer(CI.getFrontendTimer()); + ExecuteAction(); + } + else ExecuteAction(); } void FrontendAction::EndSourceFile() { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 7a7537b..27e194e 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -170,7 +170,8 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), - CI.getCodeGenOpts(), CI.getTargetOpts(), InFile, + CI.getCodeGenOpts(), CI.getTargetOpts(), + CI.getFrontendOpts().ShowTimers, InFile, OS.take(), CI.getLLVMContext()); } @@ -192,14 +193,15 @@ void DumpRawTokensAction::ExecuteAction() { SourceManager &SM = PP.getSourceManager(); // Start lexing the specified input file. - Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); RawLex.SetKeepWhitespaceMode(true); Token RawTok; RawLex.LexFromRawLexer(RawTok); while (RawTok.isNot(tok::eof)) { PP.DumpToken(RawTok, true); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; RawLex.LexFromRawLexer(RawTok); } } @@ -212,7 +214,7 @@ void DumpTokensAction::ExecuteAction() { do { PP.Lex(Tok); PP.DumpToken(Tok, true); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } while (Tok.isNot(tok::eof)); } @@ -222,8 +224,7 @@ void GeneratePTHAction::ExecuteAction() { CI.getFrontendOpts().OutputFile == "-") { // FIXME: Don't fail this way. // FIXME: Verify that we can actually seek in the given file. - llvm::errs() << "ERROR: PTH requires an seekable file for output!\n"; - ::exit(1); + llvm::llvm_report_error("PTH requires a seekable file for output!"); } llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index 0e4f83f..6251bac 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -20,16 +20,13 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Basic/FileManager.h" #include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/System/Path.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include using namespace clang; -using namespace llvm; namespace { - class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer { + class PCHGenerator : public SemaConsumer { const Preprocessor &PP; const char *isysroot; llvm::raw_ostream *Out; @@ -62,7 +59,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { // Write the PCH contents into a buffer std::vector Buffer; - BitstreamWriter Stream(Buffer); + llvm::BitstreamWriter Stream(Buffer); PCHWriter Writer(Stream); // Emit the PCH file diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 3ba7abf..93421ca 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -21,7 +21,6 @@ #include "clang/Rewrite/HTMLRewrite.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -34,7 +33,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient { +class HTMLDiagnostics : public PathDiagnosticClient { llvm::sys::Path Directory, FilePrefix; bool createdDir, noDir; const Preprocessor &PP; diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index d19ae98..a40a569 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -170,9 +170,8 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, const char *Dir32, const char *Dir64, const llvm::Triple &triple) { - // Add the common dirs + // Add the base dir AddPath(Base, System, true, false, false); - AddPath(Base + "/backward", System, true, false, false); // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); @@ -181,6 +180,9 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false); else AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false); + + // Add the backward dir + AddPath(Base + "/backward", System, true, false, false); } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, @@ -194,7 +196,15 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, // FIXME: This probably should goto to some platform utils place. #ifdef _MSC_VER + // Read registry string. + // This also supports a means to look for high-versioned keys by use + // of a $VERSION placeholder in the key path. + // $VERSION in the key path is a placeholder for the version number, + // causing the highest value path to be searched for and used. + // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". + // There can be additional characters in the component. Only the numberic + // characters are compared. bool getSystemRegistryString(const char *keyPath, const char *valueName, char *value, size_t maxLength) { HKEY hRootKey = NULL; @@ -202,6 +212,7 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, const char* subKey = NULL; DWORD valueType; DWORD valueSize = maxLength - 1; + long lResult; bool returnValue = false; if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { hRootKey = HKEY_CLASSES_ROOT; @@ -221,13 +232,80 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, } else return(false); - long lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); - if (lResult == ERROR_SUCCESS) { - lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, - (LPBYTE)value, &valueSize); - if (lResult == ERROR_SUCCESS) - returnValue = true; - RegCloseKey(hKey); + const char *placeHolder = strstr(subKey, "$VERSION"); + char bestName[256]; + bestName[0] = '\0'; + // If we have a $VERSION placeholder, do the highest-version search. + if (placeHolder) { + const char *keyEnd = placeHolder - 1; + const char *nextKey = placeHolder; + // Find end of previous key. + while ((keyEnd > subKey) && (*keyEnd != '\\')) + keyEnd--; + // Find end of key containing $VERSION. + while (*nextKey && (*nextKey != '\\')) + nextKey++; + size_t partialKeyLength = keyEnd - subKey; + char partialKey[256]; + if (partialKeyLength > sizeof(partialKey)) + partialKeyLength = sizeof(partialKey); + strncpy(partialKey, subKey, partialKeyLength); + partialKey[partialKeyLength] = '\0'; + HKEY hTopKey = NULL; + lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey); + if (lResult == ERROR_SUCCESS) { + char keyName[256]; + int bestIndex = -1; + double bestValue = 0.0; + DWORD index, size = sizeof(keyName) - 1; + for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } + size = sizeof(keyName) - 1; + } + // If we found the highest versioned key, open the key and get the value. + if (bestIndex != -1) { + // Append rest of key. + strncat(bestName, nextKey, sizeof(bestName) - 1); + bestName[sizeof(bestName) - 1] = '\0'; + // Open the chosen key path remainder. + lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } + } + RegCloseKey(hTopKey); + } + } + else { + lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } } return(returnValue); } @@ -240,35 +318,13 @@ bool getSystemRegistryString(const char *, const char *, char *, size_t) { // Get Visual Studio installation directory. bool getVisualStudioDir(std::string &path) { + char vsIDEInstallDir[256]; // Try the Windows registry first. - char vs80IDEInstallDir[256]; - char vs90IDEInstallDir[256]; - const char* vsIDEInstallDir = NULL; - bool has80 = getSystemRegistryString( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0", - "InstallDir", vs80IDEInstallDir, sizeof(vs80IDEInstallDir) - 1); - bool has90 = getSystemRegistryString( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0", - "InstallDir", vs90IDEInstallDir, sizeof(vs90IDEInstallDir) - 1); + bool hasVCDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", + "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); // If we have both vc80 and vc90, pick version we were compiled with. - if (has80 && has90) { - #ifdef _MSC_VER - #if (_MSC_VER >= 1500) // VC90 - vsIDEInstallDir = vs90IDEInstallDir; - #elif (_MSC_VER == 1400) // VC80 - vsIDEInstallDir = vs80IDEInstallDir; - #else - vsIDEInstallDir = vs90IDEInstallDir; - #endif - #else - vsIDEInstallDir = vs90IDEInstallDir; - #endif - } - else if (has90) - vsIDEInstallDir = vs90IDEInstallDir; - else if (has80) - vsIDEInstallDir = vs80IDEInstallDir; - if (vsIDEInstallDir && *vsIDEInstallDir) { + if (hasVCDir && vsIDEInstallDir[0]) { char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); if (p) *p = '\0'; @@ -307,6 +363,21 @@ bool getVisualStudioDir(std::string &path) { return(false); } + // Get Windows SDK installation directory. +bool getWindowsSDKDir(std::string &path) { + char windowsSDKInstallDir[256]; + // Try the Windows registry. + bool hasSDKDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasSDKDir && windowsSDKInstallDir[0]) { + path = windowsSDKInstallDir; + return(true); + } + return(false); +} + void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); @@ -324,10 +395,14 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { case llvm::Triple::Win32: { std::string VSDir; + std::string WindowsSDKDir; if (getVisualStudioDir(VSDir)) { AddPath(VSDir + "\\VC\\include", System, false, false, false); - AddPath(VSDir + "\\VC\\PlatformSDK\\Include", - System, false, false, false); + if (getWindowsSDKDir(WindowsSDKDir)) + AddPath(WindowsSDKDir, System, false, false, false); + else + AddPath(VSDir + "\\VC\\PlatformSDK\\Include", + System, false, false, false); } else { // Default install paths. @@ -489,6 +564,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple) { + if (Lang.CPlusPlus) + AddDefaultCPlusPlusIncludePaths(triple); + AddDefaultCIncludePaths(triple); // Add the default framework include paths on Darwin. @@ -496,9 +574,6 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, AddPath("/System/Library/Frameworks", System, true, false, true); AddPath("/Library/Frameworks", System, true, false, true); } - - if (Lang.CPlusPlus) - AddDefaultCPlusPlusIncludePaths(triple); } /// RemoveDuplicates - If there are duplicate directory entries in the specified diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index b77c240..972c21f 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -388,13 +388,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf); DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf); + DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); + DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Buf); DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf); + DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Buf); DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf); DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Buf); DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf); + DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Buf); DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf); + DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Buf); DefineType("__WINT_TYPE__", TI.getWIntType(), Buf); + DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Buf); + DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Buf); DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat()); DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat()); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp new file mode 100644 index 0000000..771a58c --- /dev/null +++ b/lib/Frontend/LangStandards.cpp @@ -0,0 +1,44 @@ +//===--- LangStandards.cpp - Language Standard Definitions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/LangStandard.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; +using namespace clang::frontend; + +#define LANGSTANDARD(id, name, desc, features) \ + static LangStandard Lang_##id = { name, desc, features }; +#include "clang/Frontend/LangStandards.def" + +const LangStandard &LangStandard::getLangStandardForKind(Kind K) { + switch (K) { + default: + llvm::llvm_unreachable("Invalid language kind!"); + case lang_unspecified: + llvm::llvm_report_error("getLangStandardForKind() on unspecified kind"); +#define LANGSTANDARD(id, name, desc, features) \ + case lang_##id: return Lang_##id; +#include "clang/Frontend/LangStandards.def" + } +} + +const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) { + Kind K = llvm::StringSwitch(Name) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(lang_unspecified); + if (K == lang_unspecified) + return 0; + + return &getLangStandardForKind(K); +} + + diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index c9679b7..cb96bcb 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -31,7 +31,6 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/System/Path.h" @@ -357,7 +356,7 @@ Expr *PCHReader::ReadTypeExpr() { namespace { -class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait { +class PCHMethodPoolLookupTrait { PCHReader &Reader; public: @@ -465,7 +464,7 @@ typedef OnDiskChainedHashTable PCHMethodPoolLookupTable; namespace { -class VISIBILITY_HIDDEN PCHIdentifierLookupTrait { +class PCHIdentifierLookupTrait { PCHReader &Reader; // If we know the IdentifierInfo in advance, it is here and we will @@ -676,7 +675,7 @@ bool PCHReader::ParseLineTable(llvm::SmallVectorImpl &Record) { namespace { -class VISIBILITY_HIDDEN PCHStatData { +class PCHStatData { public: const bool hasStat; const ino_t ino; @@ -692,7 +691,7 @@ public: : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {} }; -class VISIBILITY_HIDDEN PCHStatLookupTrait { +class PCHStatLookupTrait { public: typedef const char *external_key_type; typedef const char *internal_key_type; @@ -740,7 +739,7 @@ class VISIBILITY_HIDDEN PCHStatLookupTrait { /// /// This cache is very similar to the stat cache used by pretokenized /// headers. -class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache { +class PCHStatCache : public StatSysCallCache { typedef OnDiskChainedHashTable CacheTy; CacheTy *Cache; @@ -1554,6 +1553,12 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { if (unsigned ObjCClassRedef = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); +#if 0 + // FIXME. Accommodate for this in several PCH/Index tests + if (unsigned ObjCSelRedef + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) + Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); +#endif if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) Context->setBlockDescriptorType(GetType(String)); if (unsigned String @@ -2155,6 +2160,7 @@ QualType PCHReader::GetType(pch::TypeID ID) { case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break; case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break; case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break; + case pch::PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break; } assert(!T.isNull() && "Unknown predefined type"); @@ -2583,6 +2589,10 @@ PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { return Context->DeclarationNames.getCXXOperatorName( (OverloadedOperatorKind)Record[Idx++]); + case DeclarationName::CXXLiteralOperatorName: + return Context->DeclarationNames.getCXXLiteralOperatorName( + GetIdentifierInfo(Record, Idx)); + case DeclarationName::CXXUsingDirective: return DeclarationName::getUsingDirectiveName(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 6a92a2d..03f3b4767 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -441,6 +441,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(AnalyzerNoReturn); STRING_ATTR(Annotate); STRING_ATTR(AsmLabel); + SIMPLE_ATTR(BaseCheck); case Attr::Blocks: New = ::new (*Context) BlocksAttr( @@ -461,6 +462,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(Deprecated); UNSIGNED_ATTR(Destructor); SIMPLE_ATTR(FastCall); + SIMPLE_ATTR(Final); case Attr::Format: { std::string Type = ReadString(Record, Idx); @@ -484,6 +486,7 @@ Attr *PCHReader::ReadAttributes() { } SIMPLE_ATTR(GNUInline); + SIMPLE_ATTR(Hiding); case Attr::IBOutletKind: New = ::new (*Context) IBOutletAttr(); @@ -517,6 +520,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(CFReturnsRetained); SIMPLE_ATTR(NSReturnsRetained); SIMPLE_ATTR(Overloadable); + SIMPLE_ATTR(Override); SIMPLE_ATTR(Packed); UNSIGNED_ATTR(PragmaPack); SIMPLE_ATTR(Pure); diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 01af67d..00734a0 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -177,6 +177,7 @@ unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) { unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); + S->setConditionVariable(cast_or_null(Reader.GetDecl(Record[Idx++]))); S->setCond(cast(StmtStack[StmtStack.size() - 3])); S->setThen(StmtStack[StmtStack.size() - 2]); S->setElse(StmtStack[StmtStack.size() - 1]); @@ -187,6 +188,7 @@ unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + S->setConditionVariable(cast_or_null(Reader.GetDecl(Record[Idx++]))); S->setCond(cast(StmtStack[StmtStack.size() - 2])); S->setBody(StmtStack.back()); S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -208,6 +210,7 @@ unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) { unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) { VisitStmt(S); + S->setConditionVariable(cast_or_null(Reader.GetDecl(Record[Idx++]))); S->setCond(cast_or_null(StmtStack[StmtStack.size() - 2])); S->setBody(StmtStack.back()); S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -228,6 +231,7 @@ unsigned PCHStmtReader::VisitForStmt(ForStmt *S) { VisitStmt(S); S->setInit(StmtStack[StmtStack.size() - 4]); S->setCond(cast_or_null(StmtStack[StmtStack.size() - 3])); + S->setConditionVariable(cast_or_null(Reader.GetDecl(Record[Idx++]))); S->setInc(cast_or_null(StmtStack[StmtStack.size() - 2])); S->setBody(StmtStack.back()); S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 8a45ebc..e79f9c9 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -33,7 +33,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Path.h" #include @@ -44,7 +43,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN PCHTypeWriter { + class PCHTypeWriter { PCHWriter &Writer; PCHWriter::RecordData &Record; @@ -781,7 +780,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { namespace { // Trait used for the on-disk hash table of stat cache results. -class VISIBILITY_HIDDEN PCHStatCacheTrait { +class PCHStatCacheTrait { public: typedef const char * key_type; typedef key_type key_type_ref; @@ -1359,7 +1358,7 @@ uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context, namespace { // Trait used for the on-disk hash table used in the method pool. -class VISIBILITY_HIDDEN PCHMethodPoolTrait { +class PCHMethodPoolTrait { PCHWriter &Writer; public: @@ -1561,7 +1560,7 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN PCHIdentifierTableTrait { +class PCHIdentifierTableTrait { PCHWriter &Writer; Preprocessor &PP; @@ -1764,6 +1763,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { AddString(cast(Attr)->getLabel(), Record); break; + case Attr::BaseCheck: + break; + case Attr::Blocks: Record.push_back(cast(Attr)->getType()); // FIXME: stable break; @@ -1792,6 +1794,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { break; case Attr::FastCall: + case Attr::Final: break; case Attr::Format: { @@ -1816,6 +1819,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { } case Attr::GNUInline: + case Attr::Hiding: case Attr::IBOutletKind: case Attr::Malloc: case Attr::NoDebug: @@ -1836,6 +1840,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case Attr::CFReturnsRetained: case Attr::NSReturnsRetained: case Attr::Overloadable: + case Attr::Override: break; case Attr::PragmaPack: @@ -1989,6 +1994,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddTypeRef(Context.getsigjmp_bufType(), Record); AddTypeRef(Context.ObjCIdRedefinitionType, Record); AddTypeRef(Context.ObjCClassRedefinitionType, Record); +#if 0 + // FIXME. Accommodate for this in several PCH/Indexer tests + AddTypeRef(Context.ObjCSelRedefinitionType, Record); +#endif AddTypeRef(Context.getRawBlockdescriptorType(), Record); AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); Stream.EmitRecord(pch::SPECIAL_TYPES, Record); @@ -2204,6 +2213,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break; case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break; case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break; + case BuiltinType::ObjCSel: ID = pch::PREDEF_TYPE_OBJC_SEL; break; case BuiltinType::UndeducedAuto: assert(0 && "Should not see undeduced auto here"); break; @@ -2274,6 +2284,10 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { Record.push_back(Name.getCXXOverloadedOperator()); break; + case DeclarationName::CXXLiteralOperatorName: + AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record); + break; + case DeclarationName::CXXUsingDirective: // No extra data to emit break; diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 78a56db..27b83ed 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -170,6 +170,7 @@ void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) { void PCHStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); Writer.WriteSubStmt(S->getCond()); Writer.WriteSubStmt(S->getThen()); Writer.WriteSubStmt(S->getElse()); @@ -180,6 +181,7 @@ void PCHStmtWriter::VisitIfStmt(IfStmt *S) { void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); Writer.WriteSubStmt(S->getCond()); Writer.WriteSubStmt(S->getBody()); Writer.AddSourceLocation(S->getSwitchLoc(), Record); @@ -191,6 +193,7 @@ void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) { void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) { VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); Writer.WriteSubStmt(S->getCond()); Writer.WriteSubStmt(S->getBody()); Writer.AddSourceLocation(S->getWhileLoc(), Record); @@ -211,6 +214,7 @@ void PCHStmtWriter::VisitForStmt(ForStmt *S) { VisitStmt(S); Writer.WriteSubStmt(S->getInit()); Writer.WriteSubStmt(S->getCond()); + Writer.AddDeclRef(S->getConditionVariable(), Record); Writer.WriteSubStmt(S->getInc()); Writer.WriteSubStmt(S->getBody()); Writer.AddSourceLocation(S->getForLoc(), Record); diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 6bcf39a..80ee2c2 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -16,10 +16,8 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Casting.h" -#include "llvm/System/Path.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" using namespace clang; @@ -32,7 +30,7 @@ namespace clang { } namespace { - class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient { + class PlistDiagnostics : public PathDiagnosticClient { std::vector BatchedDiags; const std::string OutputFile; const LangOptions &LangOpts; diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index deb5498..c5dc979 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -305,14 +305,16 @@ namespace { } virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + FullExprArg CondVal, DeclPtrTy CondVar, + StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); } - virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) { + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + DeclPtrTy CondVar) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); } @@ -325,7 +327,8 @@ namespace { } virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, StmtArg Body) { + FullExprArg Cond, DeclPtrTy CondVar, + StmtArg Body) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); } @@ -338,8 +341,10 @@ namespace { } virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - ExprArg Third, SourceLocation RParenLoc, + StmtArg First, FullExprArg Second, + DeclPtrTy SecondVar, + FullExprArg Third, + SourceLocation RParenLoc, StmtArg Body) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index b5d59c0..0bcbd4f 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -65,7 +65,8 @@ static void LexRawTokensFromMainFile(Preprocessor &PP, // Create a lexer to lex all the tokens of the main file in raw mode. Even // though it is in raw mode, it will not return comments. - Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); // Switch on comment lexing because we really do want them. RawLex.SetCommentRetentionState(true); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 06955e5..710fa55 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -2627,7 +2627,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - ID, QualType()/*UNUSED*/, 0, VarDecl::Extern); + ID, getProtocolType(), 0, VarDecl::Extern); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation()); Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, Context->getPointerType(DRE->getType()), diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index 4a3c0bf..c0977b5 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -25,7 +24,7 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - class VISIBILITY_HIDDEN StmtXML : public StmtVisitor { + class StmtXML : public StmtVisitor { DocumentXML& Doc; //static const char *getOpcodeStr(UnaryOperator::Opcode Op); @@ -61,8 +60,6 @@ namespace { Doc.PrintDecl(*DI); } } else { - if (CXXConditionDeclExpr* CCDE = dyn_cast(S)) - Doc.PrintDecl(CCDE->getVarDecl()); for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i) DumpSubTree(*i); diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index 34bc3c7..fdf2ec8 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -20,20 +20,29 @@ using namespace clang; /// void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { - llvm::SmallString<100> StrC; - Info.FormatDiagnostic(StrC); - std::string Str(StrC.begin(), StrC.end()); + llvm::SmallString<100> Buf; + Info.FormatDiagnostic(Buf); switch (Level) { default: assert(0 && "Diagnostic not handled during diagnostic buffering!"); case Diagnostic::Note: - Notes.push_back(std::make_pair(Info.getLocation(), Str)); + Notes.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; case Diagnostic::Warning: - Warnings.push_back(std::make_pair(Info.getLocation(), Str)); + Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; case Diagnostic::Error: case Diagnostic::Fatal: - Errors.push_back(std::make_pair(Info.getLocation(), Str)); + Errors.push_back(std::make_pair(Info.getLocation(), Buf.str())); break; } } + +void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const { + // FIXME: Flush the diagnostics in order. + for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str())); + for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str())); + for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str())); +} diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp index 2891aec..99ec910 100644 --- a/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -164,12 +164,14 @@ static void FindExpectedDiags(Preprocessor &PP, DiagList &ExpectedNotes) { // Create a raw lexer to pull all the comments out of the main file. We don't // want to look in #include'd headers for expected-error strings. - FileID FID = PP.getSourceManager().getMainFileID(); - if (PP.getSourceManager().getMainFileID().isInvalid()) + SourceManager &SM = PP.getSourceManager(); + FileID FID = SM.getMainFileID(); + if (SM.getMainFileID().isInvalid()) return; // Create a lexer to lex all the tokens of the main file in raw mode. - Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index ccaf349..15b6eaa 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -214,18 +214,20 @@ typedef __uint_least8_t uint_fast8_t; /* C99 7.18.1.4 Integer types capable of holding object pointers. */ #define __stdint_join3(a,b,c) a ## b ## c -#define __stdint_exjoin3(a,b,c) __stdint_join3(a,b,c) + +#define __intn_t(n) __stdint_join3( int, n, _t) +#define __uintn_t(n) __stdint_join3(uint, n, _t) #ifndef __intptr_t_defined -typedef __stdint_exjoin3( int, __INTPTR_WIDTH__, _t) intptr_t; +typedef __intn_t(__INTPTR_WIDTH__) intptr_t; #define __intptr_t_defined #endif -typedef __stdint_exjoin3(uint, __INTPTR_WIDTH__, _t) uintptr_t; +typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t; /* C99 7.18.1.5 Greatest-width integer types. */ -typedef __stdint_exjoin3( int, __INTMAX_WIDTH__, _t) intmax_t; -typedef __stdint_exjoin3(uint, __INTMAX_WIDTH__, _t) uintmax_t; +typedef __intn_t(__INTMAX_WIDTH__) intmax_t; +typedef __uintn_t(__INTMAX_WIDTH__) uintmax_t; /* C99 7.18.4 Macros for minimum-width integer constants. * @@ -602,57 +604,44 @@ typedef __stdint_exjoin3(uint, __INTMAX_WIDTH__, _t) uintmax_t; /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ +#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN) +#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX) +#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX) -#define INTPTR_MIN __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MIN) -#define INTPTR_MAX __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MAX) -#define UINTPTR_MAX __stdint_exjoin3(UINT, __INTPTR_WIDTH__, _MAX) - -#if __POINTER_WIDTH__ == 64 - -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#define SIZE_MAX UINT64_MAX - -#elif __POINTER_WIDTH__ == 32 - -#define PTRDIFF_MIN INT32_MIN -#define PTRDIFF_MAX INT32_MAX -#define SIZE_MAX UINT32_MAX - -#elif __POINTER_WIDTH__ == 16 - -#define PTRDIFF_MIN INT16_MIN -#define PTRDIFF_MAX INT16_MAX -#define SIZE_MAX UINT16_MAX - -#else -#error "unknown or unset pointer width!" -#endif +#define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__) +#define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__) +#define UINTPTR_MAX __UINTN_MAX(__INTPTR_WIDTH__) +#define PTRDIFF_MIN __INTN_MIN(__PTRDIFF_WIDTH__) +#define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__) +#define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__) /* C99 7.18.2.5 Limits of greatest-width integer types. */ -#define INTMAX_MIN __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MIN) -#define INTMAX_MAX __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MAX) -#define UINTMAX_MAX __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _MAX) +#define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__) +#define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__) +#define UINTMAX_MAX __UINTN_MAX(__INTMAX_WIDTH__) /* C99 7.18.3 Limits of other integer types. */ -#define SIG_ATOMIC_MIN INT32_MIN -#define SIG_ATOMIC_MAX INT32_MAX -#define WINT_MIN INT32_MIN -#define WINT_MAX INT32_MAX +#define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) +#define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__) +#define WINT_MIN __INTN_MIN(__WINT_WIDTH__) +#define WINT_MAX __INTN_MAX(__WINT_WIDTH__) /* FIXME: if we ever support a target with unsigned wchar_t, this should be * 0 .. Max. */ #ifndef WCHAR_MAX -#define WCHAR_MAX __WCHAR_MAX__ +#define WCHAR_MAX __INTN_MAX(__WCHAR_WIDTH__) #endif #ifndef WCHAR_MIN -#define WCHAR_MIN (-__WCHAR_MAX__-1) +#define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__) #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) __stdint_exjoin3( INT, __INTMAX_WIDTH__, _C(v)) -#define UINTMAX_C(v) __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _C(v)) +#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v)) +#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v)) + +#define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v) +#define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v) #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp index 300a469..fb3529d 100644 --- a/lib/Index/Analyzer.cpp +++ b/lib/Index/Analyzer.cpp @@ -23,7 +23,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/Support/Compiler.h" using namespace clang; using namespace idx; @@ -33,7 +32,7 @@ namespace { // DeclEntityAnalyzer Implementation //===----------------------------------------------------------------------===// -class VISIBILITY_HIDDEN DeclEntityAnalyzer : public TranslationUnitHandler { +class DeclEntityAnalyzer : public TranslationUnitHandler { Entity Ent; TULocationHandler &TULocHandler; @@ -57,7 +56,7 @@ public: // RefEntityAnalyzer Implementation //===----------------------------------------------------------------------===// -class VISIBILITY_HIDDEN RefEntityAnalyzer : public TranslationUnitHandler { +class RefEntityAnalyzer : public TranslationUnitHandler { Entity Ent; TULocationHandler &TULocHandler; @@ -87,7 +86,7 @@ public: /// \brief Accepts an ObjC method and finds all message expressions that this /// method may respond to. -class VISIBILITY_HIDDEN RefSelectorAnalyzer : public TranslationUnitHandler { +class RefSelectorAnalyzer : public TranslationUnitHandler { Program &Prog; TULocationHandler &TULocHandler; @@ -219,7 +218,7 @@ public: /// \brief Accepts an ObjC message expression and finds all methods that may /// respond to it. -class VISIBILITY_HIDDEN MessageAnalyzer : public TranslationUnitHandler { +class MessageAnalyzer : public TranslationUnitHandler { Program &Prog; TULocationHandler &TULocHandler; diff --git a/lib/Index/DeclReferenceMap.cpp b/lib/Index/DeclReferenceMap.cpp index 366cf1b..d6e30ab 100644 --- a/lib/Index/DeclReferenceMap.cpp +++ b/lib/Index/DeclReferenceMap.cpp @@ -15,13 +15,12 @@ #include "clang/Index/DeclReferenceMap.h" #include "clang/Index/ASTLocation.h" #include "ASTVisitor.h" -#include "llvm/Support/Compiler.h" using namespace clang; using namespace idx; namespace { -class VISIBILITY_HIDDEN RefMapper : public ASTVisitor { +class RefMapper : public ASTVisitor { DeclReferenceMap::MapTy ⤅ public: diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index ed905f3..c7379f7 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -19,14 +19,13 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/SourceManager.h" -#include "llvm/Support/Compiler.h" using namespace clang; using namespace idx; namespace { /// \brief Base for the LocResolver classes. Mostly does source range checking. -class VISIBILITY_HIDDEN LocResolverBase { +class LocResolverBase { protected: ASTContext &Ctx; SourceLocation Loc; @@ -83,7 +82,7 @@ public: /// \brief Searches a statement for the ASTLocation that corresponds to a source /// location. -class VISIBILITY_HIDDEN StmtLocResolver : public LocResolverBase, +class StmtLocResolver : public LocResolverBase, public StmtVisitor { Decl * const Parent; @@ -100,7 +99,7 @@ public: /// \brief Searches a declaration for the ASTLocation that corresponds to a /// source location. -class VISIBILITY_HIDDEN DeclLocResolver : public LocResolverBase, +class DeclLocResolver : public LocResolverBase, public DeclVisitor { public: diff --git a/lib/Index/SelectorMap.cpp b/lib/Index/SelectorMap.cpp index 325b371..0f11e31 100644 --- a/lib/Index/SelectorMap.cpp +++ b/lib/Index/SelectorMap.cpp @@ -14,13 +14,12 @@ #include "clang/Index/SelectorMap.h" #include "ASTVisitor.h" -#include "llvm/Support/Compiler.h" using namespace clang; using namespace idx; namespace { -class VISIBILITY_HIDDEN SelMapper : public ASTVisitor { +class SelMapper : public ASTVisitor { SelectorMap::SelMethMapTy &SelMethMap; SelectorMap::SelRefMapTy &SelRefMap; diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index f4a4432..52a7a04 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -95,13 +95,11 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. -Lexer::Lexer(FileID FID, Preprocessor &PP) +Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), Features(PP.getLangOptions()) { - const llvm::MemoryBuffer *InputFile = PP.getSourceManager().getBuffer(FID); - InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(), InputFile->getBufferEnd()); @@ -129,9 +127,9 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &features, /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexRawToken'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. -Lexer::Lexer(FileID FID, const SourceManager &SM, const LangOptions &features) +Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile, + const SourceManager &SM, const LangOptions &features) : FileLoc(SM.getLocForStartOfFile(FID)), Features(features) { - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(), FromFile->getBufferEnd()); @@ -163,7 +161,8 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc, // Create the lexer as if we were going to lex the file normally. FileID SpellingFID = SM.getFileID(SpellingLoc); - Lexer *L = new Lexer(SpellingFID, PP); + const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID); + Lexer *L = new Lexer(SpellingFID, InputFile, PP); // Now that the lexer is created, change the start/end locations so that we // just lex the subsection of the file that we want. This is lexing from a diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 42dd75e..ab66942 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -375,46 +375,34 @@ NumericLiteralParser(const char *begin, const char *end, continue; // Success. case 'i': if (PP.getLangOptions().Microsoft) { + if (isFPConstant || isUnsigned || isLong || isLongLong) break; + // Allow i8, i16, i32, i64, and i128. if (s + 1 != ThisTokEnd) { switch (s[1]) { case '8': s += 2; // i8 suffix isMicrosoftInteger = true; - continue; + break; case '1': - s += 2; - if (s == ThisTokEnd) break; - if (*s == '6') s++; // i16 suffix - else if (*s == '2') { - if (++s == ThisTokEnd) break; - if (*s == '8') s++; // i128 suffix + if (s + 2 == ThisTokEnd) break; + if (s[2] == '6') s += 3; // i16 suffix + else if (s[2] == '2') { + if (s + 3 == ThisTokEnd) break; + if (s[3] == '8') s += 4; // i128 suffix } isMicrosoftInteger = true; - continue; + break; case '3': - s += 2; - if (s == ThisTokEnd) break; - if (*s == '2') s++; // i32 suffix + if (s + 2 == ThisTokEnd) break; + if (s[2] == '2') s += 3; // i32 suffix isMicrosoftInteger = true; - continue; + break; case '6': - s += 2; - if (s == ThisTokEnd) break; - if (*s == '4') s++; // i64 suffix + if (s + 2 == ThisTokEnd) break; + if (s[2] == '4') s += 3; // i64 suffix isMicrosoftInteger = true; - continue; - case 'f': // FP Suffix for "float" - case 'F': - if (!isFPConstant) break; // Error for integer constant. - if (isFloat || isLong) break; // FF, LF invalid. - isFloat = true; - if (isImaginary) break; // Cannot be repeated. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), - diag::ext_imaginary_constant); - isImaginary = true; - s++; - continue; // Success. + break; default: break; } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index dc7d95e..9caca33 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -16,6 +16,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/APInt.h" using namespace clang; @@ -1111,7 +1112,9 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, } // Finally, if all is good, enter the new file! - EnterSourceFile(FID, CurDir); + if (EnterSourceFile(FID, CurDir)) + Diag(FilenameTok, diag::err_pp_error_opening_file) + << std::string(SourceMgr.getFileEntryForID(FID)->getName()); } /// HandleIncludeNextDirective - Implements #include_next. diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 41ed991..8a61d7b 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -63,9 +63,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { //===----------------------------------------------------------------------===// /// EnterSourceFile - Add a source file to the top of the include stack and -/// start lexing tokens from it instead of the current buffer. Return true -/// on failure. -void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { +/// start lexing tokens from it instead of the current buffer. +bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -73,10 +72,19 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { MaxIncludeStackDepth = IncludeMacroStack.size(); if (PTH) { - if (PTHLexer *PL = PTH->CreateLexer(FID)) - return EnterSourceFileWithPTH(PL, CurDir); + if (PTHLexer *PL = PTH->CreateLexer(FID)) { + EnterSourceFileWithPTH(PL, CurDir); + return false; + } } - EnterSourceFileWithLexer(new Lexer(FID, *this), CurDir); + + // Get the MemoryBuffer for this FID, if it fails, we fail. + const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); + if (InputFile == 0) + return true; + + EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); + return false; } /// EnterSourceFileWithLexer - Add a source file to the top of the include stack diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index d6a73cc..a64008a 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -285,7 +285,7 @@ SourceLocation PTHLexer::getSourceLocation() { /// to map from FileEntry objects managed by FileManager to offsets within /// the PTH file. namespace { -class VISIBILITY_HIDDEN PTHFileData { +class PTHFileData { const uint32_t TokenOff; const uint32_t PPCondOff; public: @@ -297,7 +297,7 @@ public: }; -class VISIBILITY_HIDDEN PTHFileLookupCommonTrait { +class PTHFileLookupCommonTrait { public: typedef std::pair internal_key_type; @@ -318,7 +318,7 @@ public: } }; -class VISIBILITY_HIDDEN PTHFileLookupTrait : public PTHFileLookupCommonTrait { +class PTHFileLookupTrait : public PTHFileLookupCommonTrait { public: typedef const FileEntry* external_key_type; typedef PTHFileData data_type; @@ -340,7 +340,7 @@ public: } }; -class VISIBILITY_HIDDEN PTHStringLookupTrait { +class PTHStringLookupTrait { public: typedef uint32_t data_type; @@ -597,7 +597,7 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) { //===----------------------------------------------------------------------===// namespace { -class VISIBILITY_HIDDEN PTHStatData { +class PTHStatData { public: const bool hasStat; const ino_t ino; @@ -613,7 +613,7 @@ public: : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {} }; -class VISIBILITY_HIDDEN PTHStatLookupTrait : public PTHFileLookupCommonTrait { +class PTHStatLookupTrait : public PTHFileLookupCommonTrait { public: typedef const char* external_key_type; // const char* typedef PTHStatData data_type; @@ -646,7 +646,7 @@ public: } }; -class VISIBILITY_HIDDEN PTHStatCache : public StatSysCallCache { +class PTHStatCache : public StatSysCallCache { typedef OnDiskChainedHashTable CacheTy; CacheTy Cache; diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index dde4bc8..df48e3a 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -17,11 +17,13 @@ using namespace clang; AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, + IdentifierInfo *sName, SourceLocation sLoc, IdentifierInfo *pName, SourceLocation pLoc, ActionBase::ExprTy **ExprList, unsigned numArgs, - AttributeList *n, bool declspec) - : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc), - NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) { + AttributeList *n, bool declspec, bool cxx0x) + : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), + ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) { if (numArgs == 0) Args = 0; @@ -59,13 +61,16 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("mode", AT_mode) .Case("used", AT_used) .Case("alias", AT_alias) + .Case("align", AT_aligned) + .Case("final", AT_final) .Case("cdecl", AT_cdecl) .Case("const", AT_const) - .Case("packed", AT_packed) - .Case("malloc", AT_malloc) + .Case("blocks", AT_blocks) .Case("format", AT_format) + .Case("hiding", AT_hiding) + .Case("malloc", AT_malloc) + .Case("packed", AT_packed) .Case("unused", AT_unused) - .Case("blocks", AT_blocks) .Case("aligned", AT_aligned) .Case("cleanup", AT_cleanup) .Case("nodebug", AT_nodebug) @@ -76,15 +81,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("section", AT_section) .Case("stdcall", AT_stdcall) .Case("annotate", AT_annotate) - .Case("noreturn", AT_noreturn) - .Case("noinline", AT_noinline) .Case("fastcall", AT_fastcall) .Case("iboutlet", AT_IBOutlet) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("override", AT_override) .Case("sentinel", AT_sentinel) .Case("NSObject", AT_nsobject) .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) .Case("destructor", AT_destructor) @@ -103,6 +110,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("transparent_union", AT_transparent_union) .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) + .Case("carries_dependency", AT_carries_dependency) .Case("ns_returns_retained", AT_ns_returns_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("reqd_work_group_size", AT_reqd_wg_size) diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 7681eac..aa0b89b 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, Scope *S, const CXXScopeSpec *SS, - bool isClassName) { + bool isClassName, TypeTy *ObjectType) { if (TypeNameInfo *TI = II.getFETokenInfo()) if (TI->isTypeName) return TI; diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index c34653e..b9314d2 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -37,7 +37,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams)); else // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, - move(TemplateParams), 0, 0); + move(TemplateParams), 0, 0, + /*IsDefinition*/true); HandleMemberFunctionDefaultArgs(D, FnD); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2bfda30..b13dc73 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1,3 +1,4 @@ + //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // The LLVM Compiler Infrastructure @@ -45,7 +46,7 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { return Actions.ActOnTypeName(CurScope, DeclaratorInfo); } -/// ParseAttributes - Parse a non-empty attributes list. +/// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: /// attribute @@ -81,8 +82,8 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { /// attributes are very simple in practice. Until we find a bug, I don't see /// a pressing need to implement the 2 token lookahead. -AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { - assert(Tok.is(tok::kw___attribute) && "Not an attribute list!"); +AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { + assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); AttributeList *CurrAttr = 0; @@ -121,7 +122,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, ParmName, ParmLoc, 0, 0, CurrAttr); } else if (Tok.is(tok::comma)) { ConsumeToken(); @@ -145,8 +146,10 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName, - ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + AttrNameLoc, ParmName, ParmLoc, + ArgExprs.take(), ArgExprs.size(), + CurrAttr); } } } else { // not an identifier @@ -155,7 +158,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // parse a possibly empty comma separated list of expressions // __attribute__(( nonnull() )) ConsumeParen(); // ignore the right paren loc for now - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); break; case tok::kw_char: @@ -175,7 +178,7 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // If it's a builtin type name, eat it and expect a rparen // __attribute__(( vec_type_hint(char) )) ConsumeToken(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); if (Tok.is(tok::r_paren)) ConsumeParen(); @@ -203,20 +206,21 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, - SourceLocation(), ArgExprs.take(), ArgExprs.size(), + AttrNameLoc, 0, SourceLocation(), ArgExprs.take(), + ArgExprs.size(), CurrAttr); } break; } } } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); - SourceLocation Loc = Tok.getLocation();; + SourceLocation Loc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SkipUntil(tok::r_paren, false); } @@ -254,15 +258,15 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { OwningExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { ExprTy* ExprList = ArgExpr.take(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), &ExprList, 1, CurrAttr, true); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(), - 0, 0, CurrAttr, true); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr, true); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -281,7 +285,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) // FIXME: Support these properly! continue; - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, CurrAttr, true); } return CurrAttr; @@ -304,26 +308,36 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + CXX0XAttributeList Attr) { DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; case tok::kw_namespace: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; SingleDecl = ParseNamespace(Context, DeclEnd); break; case tok::kw_using: - SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd); + SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr); break; case tok::kw_static_assert: + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - return ParseSimpleDeclaration(Context, DeclEnd); + return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList); } - + // This routine returns a DeclGroup, if the thing we parsed only contains a // single decl, convert it now. return Actions.ConvertDeclToDeclGroup(SingleDecl); @@ -337,9 +351,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AttributeList *Attr) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + if (Attr) + DS.AddAttributes(Attr); ParseDeclarationSpecifiers(DS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -422,7 +439,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // short x, __attribute__((common)) var; -> declarator if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); D.AddAttributes(AttrList, Loc); } @@ -491,7 +508,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); D.AddAttributes(AttrList, Loc); } @@ -988,7 +1005,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - DS.AddAttributes(ParseAttributes()); + DS.AddAttributes(ParseGNUAttributes()); continue; // Microsoft declspec support. @@ -1522,7 +1539,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // Attributes are only allowed here on successive declarators. if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.D.AddAttributes(AttrList, Loc); } @@ -1543,7 +1560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // If attributes exist after the declarator, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.D.AddAttributes(AttrList, Loc); } @@ -1667,7 +1684,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, AttributeList *AttrList = 0; // If attributes exist after struct contents, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); Actions.ActOnFields(CurScope, RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(), @@ -1702,7 +1719,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AttributeList *Attr = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + Attr = ParseGNUAttributes(); CXXScopeSpec SS; if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { @@ -1833,7 +1850,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { AttributeList *Attr = 0; // If attributes exist after the identifier list, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + Attr = ParseGNUAttributes(); // FIXME: where do they do? Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, EnumConstantDecls.data(), EnumConstantDecls.size(), @@ -2049,8 +2066,20 @@ bool Parser::isDeclarationSpecifier() { /// [GNU] attributes [ only if AttributesAllowed=true ] /// type-qualifier-list type-qualifier /// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ] +/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq +/// if CXX0XAttributesAllowed = true /// -void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, + bool CXX0XAttributesAllowed) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + SourceLocation Loc = Tok.getLocation(); + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + if (CXX0XAttributesAllowed) + DS.AddAttributes(Attr.AttrList); + else + Diag(Loc, diag::err_attributes_not_allowed); + } + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -2075,14 +2104,14 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { case tok::kw___cdecl: case tok::kw___stdcall: case tok::kw___fastcall: - if (AttributesAllowed) { + if (GNUAttributesAllowed) { DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; } goto DoneWithTypeQuals; case tok::kw___attribute: - if (AttributesAllowed) { - DS.AddAttributes(ParseAttributes()); + if (GNUAttributesAllowed) { + DS.AddAttributes(ParseGNUAttributes()); continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! @@ -2221,7 +2250,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // // [GNU] Retricted references are allowed. // [GNU] Attributes on references are allowed. - ParseTypeQualifierListOpt(DS); + // [C++0x] Attributes on references are not allowed. + ParseTypeQualifierListOpt(DS, true, false); D.ExtendWithDeclSpec(DS); if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { @@ -2362,6 +2392,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) { assert(D.isPastIdentifier() && "Haven't past the location of the identifier yet?"); + // Don't parse attributes unless we have an identifier. + if (D.getIdentifier() && getLang().CPlusPlus + && isCXX0XAttributeSpecifier(true)) { + SourceLocation AttrEndLoc; + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + D.AddAttributes(Attr.AttrList, AttrEndLoc); + } + while (1) { if (Tok.is(tok::l_paren)) { // The paren may be part of a C++ direct initializer, eg. "int x(1);". @@ -2413,7 +2451,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { AttributeList *AttrList = 0; bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // We require that the argument list (if this is a non-grouping paren) be // present even if the attribute list was empty. @@ -2618,7 +2656,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse GNU attributes, if present. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParmDecl.AddAttributes(AttrList, Loc); } @@ -2722,6 +2760,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, bool hasAnyExceptionSpec = false; llvm::SmallVector Exceptions; llvm::SmallVector ExceptionRanges; + if (getLang().CPlusPlus) { // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, false /*no attributes*/); @@ -2842,6 +2881,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) { + Attr = ParseCXX0XAttributes(); + } + // Remember that we parsed the empty array type. OwningExprResult NumElements(Actions); D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, @@ -2855,6 +2900,11 @@ void Parser::ParseBracketDeclarator(Declarator &D) { ConsumeToken(); SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } // If there was an error parsing the assignment-expression, recover. if (ExprRes.isInvalid()) @@ -2922,6 +2972,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); + //FIXME: Use these + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + // Remember that we parsed a array type, and remember its features. D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 914bfc9..505a4d8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -69,7 +69,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, attrTok = Tok; // FIXME: save these somewhere. - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); } if (Tok.is(tok::equal)) { @@ -97,8 +97,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, PP.getSourceManager(), "parsing namespace"); - while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) - ParseExternalDeclaration(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); + } // Leave the namespace scope. NamespaceScope.Exit(); @@ -175,15 +179,27 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + Attr = ParseCXX0XAttributes(); + } + if (Tok.isNot(tok::l_brace)) { - ParseDeclarationOrFunctionDefinition(); + ParseDeclarationOrFunctionDefinition(Attr.AttrList); return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, SourceLocation()); } + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParseExternalDeclaration(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + ParseExternalDeclaration(Attr); } SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); @@ -193,7 +209,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + CXX0XAttributeList Attr) { assert(Tok.is(tok::kw_using) && "Not using token"); // Eat 'using'. @@ -206,9 +223,14 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, if (Tok.is(tok::kw_namespace)) // Next token after 'using' is 'namespace' so it must be using-directive - return ParseUsingDirective(Context, UsingLoc, DeclEnd); + return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList); + + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; // Otherwise, it must be using-declaration. + // Ignore illegal attributes (the caller should already have issued an error. return ParseUsingDeclaration(Context, UsingLoc, DeclEnd); } @@ -224,7 +246,8 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, /// Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd) { + SourceLocation &DeclEnd, + AttributeList *Attr) { assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token"); // Eat 'namespace'. @@ -239,7 +262,6 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - AttributeList *AttrList = 0; IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); @@ -257,17 +279,20 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, IdentLoc = ConsumeToken(); // Parse (optional) attributes (most likely GNU strong-using extension). - if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + bool GNUAttr = false; + if (Tok.is(tok::kw___attribute)) { + GNUAttr = true; + Attr = addAttributeLists(Attr, ParseGNUAttributes()); + } // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, - AttrList ? diag::err_expected_semi_after_attribute_list : + GNUAttr ? diag::err_expected_semi_after_attribute_list : diag::err_expected_semi_after_namespace_name, "", tok::semi); return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS, - IdentLoc, NamespcName, AttrList); + IdentLoc, NamespcName, Attr); } /// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that @@ -323,7 +348,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // Parse (optional) attributes (most likely GNU strong-using extension). if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // Eat ';'. DeclEnd = Tok.getLocation(); @@ -538,14 +563,20 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ConsumeToken(); } - AttributeList *Attr = 0; + AttributeList *AttrList = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) - Attr = ParseAttributes(); + AttrList = ParseGNUAttributes(); // If declspecs exist after tag, parse them. if (Tok.is(tok::kw___declspec)) - Attr = ParseMicrosoftDeclSpec(Attr); + AttrList = ParseMicrosoftDeclSpec(AttrList); + + // If C++0x attributes exist here, parse them. + // FIXME: Are we consistent with the ordering of parsing of different + // styles of attributes? + if (isCXX0XAttributeSpecifier()) + AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList); if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) { // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but @@ -683,7 +714,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Diag(StartLoc, diag::err_anon_type_definition) << DeclSpec::getSpecifierName(TagType); - // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); if (TemplateId) @@ -720,7 +750,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr); + AttrList); } else if (TUK == Action::TUK_Reference) { TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), @@ -775,7 +805,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr, + AttrList, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); @@ -793,7 +823,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, TagType, StartLoc, SS, Name, - NameLoc, Attr); + NameLoc, AttrList); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Action::TUK_Definition) { @@ -804,7 +834,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS, - Name, NameLoc, Attr, AS, + Name, NameLoc, AttrList, AS, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0), @@ -1055,8 +1085,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } + CXX0XAttributeList AttrList; + // Optional C++0x attribute-specifier + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + AttrList = ParseCXX0XAttributes(); + } + if (Tok.is(tok::kw_using)) { // FIXME: Check for template aliases + + if (AttrList.HasAttr) + Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed) + << AttrList.Range; // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -1077,6 +1117,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + DS.AddAttributes(AttrList.AttrList); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); Action::MultiTemplateParamsArg TemplateParams(Actions, @@ -1103,6 +1144,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } + // If attributes exist after the declarator, but before an '{', parse them. + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + DeclaratorInfo.AddAttributes(AttrList, Loc); + } + // function-definition: if (Tok.is(tok::l_brace) || (DeclaratorInfo.isFunctionDeclarator() && @@ -1139,7 +1187,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, bool Deleted = false; while (1) { - // member-declarator: // declarator pure-specifier[opt] // declarator constant-initializer[opt] @@ -1177,7 +1224,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If attributes exist after the declarator, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1197,6 +1244,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, move(TemplateParams), BitfieldSize.release(), Init.release(), + /*IsDefinition*/Deleted, Deleted); } if (ThisDecl) @@ -1227,7 +1275,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Attributes are only allowed on the second declarator. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1326,7 +1374,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, AttributeList *AttrList = 0; // If attributes exist after class contents, parse them. if (Tok.is(tok::kw___attribute)) - AttrList = ParseAttributes(); // FIXME: where should I put them? + AttrList = ParseGNUAttributes(); // FIXME: where should I put them? Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl, LBraceLoc, RBraceLoc); @@ -1573,3 +1621,173 @@ void Parser::PopParsingClass() { ClassStack.top()->NestedClasses.push_back(Victim); Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope(); } + +/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only +/// parses standard attributes. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) + && "Not a C++0x attribute list"); + + SourceLocation StartLoc = Tok.getLocation(), Loc; + AttributeList *CurrAttr = 0; + + ConsumeBracket(); + ConsumeBracket(); + + if (Tok.is(tok::comma)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + ConsumeToken(); + } + + while (Tok.is(tok::identifier) || Tok.is(tok::comma)) { + // attribute not present + if (Tok.is(tok::comma)) { + ConsumeToken(); + continue; + } + + IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); + SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); + + // scoped attribute + if (Tok.is(tok::coloncolon)) { + ConsumeToken(); + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + SkipUntil(tok::r_square, tok::comma, true, true); + continue; + } + + ScopeName = AttrName; + ScopeLoc = AttrLoc; + + AttrName = Tok.getIdentifierInfo(); + AttrLoc = ConsumeToken(); + } + + bool AttrParsed = false; + // No scoped names are supported; ideally we could put all non-standard + // attributes into namespaces. + if (!ScopeName) { + switch(AttributeList::getKind(AttrName)) + { + // No arguments + case AttributeList::AT_base_check: + case AttributeList::AT_carries_dependency: + case AttributeList::AT_final: + case AttributeList::AT_hiding: + case AttributeList::AT_noreturn: + case AttributeList::AT_override: { + if (Tok.is(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments) + << AttrName->getName(); + break; + } + + CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, CurrAttr, false, + true); + AttrParsed = true; + break; + } + + // One argument; must be a type-id or assignment-expression + case AttributeList::AT_aligned: { + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments) + << AttrName->getName(); + break; + } + SourceLocation ParamLoc = ConsumeParen(); + + OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); + + MatchRHSPunctuation(tok::r_paren, ParamLoc); + + ExprVector ArgExprs(Actions); + ArgExprs.push_back(ArgExpr.release()); + CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, CurrAttr, + false, true); + + AttrParsed = true; + break; + } + + // Silence warnings + default: break; + } + } + + // Skip the entire parameter clause, if any + if (!AttrParsed && Tok.is(tok::l_paren)) { + ConsumeParen(); + // SkipUntil maintains the balancedness of tokens. + SkipUntil(tok::r_paren, false); + } + } + + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + Loc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare)) + SkipUntil(tok::r_square, false); + + CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true); + return Attr; +} + +/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]] +/// attribute. +/// +/// FIXME: Simply returns an alignof() expression if the argument is a +/// type. Ideally, the type should be propagated directly into Sema. +/// +/// [C++0x] 'align' '(' type-id ')' +/// [C++0x] 'align' '(' assignment-expression ')' +Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { + if (isTypeIdInParens()) { + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + SourceLocation TypeLoc = Tok.getLocation(); + TypeTy *Ty = ParseTypeName().get(); + SourceRange TypeRange(Start, Tok.getLocation()); + return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty, + TypeRange); + } else + return ParseConstantExpression(); +} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index d2b3b84..f780cf1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -413,12 +413,12 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { /// Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - bool parseParenAsExprList){ + TypeTy *TypeOfCast) { bool NotCastExpr; OwningExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, - parseParenAsExprList); + TypeOfCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); @@ -538,7 +538,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - bool parseParenAsExprList){ + TypeTy *TypeOfCast) { OwningExprResult Res(Actions); tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -563,7 +563,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - parseParenAsExprList, CastTy, RParenLoc); + TypeOfCast, CastTy, RParenLoc); if (Res.isInvalid()) return move(Res); switch (ParenExprType) { @@ -1047,7 +1047,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, // operands. EnterExpressionEvaluationContext Unevaluated(Actions, Action::Unevaluated); - Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, + Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, + 0/*TypeOfCast*/, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); @@ -1304,7 +1305,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { /// Parser::OwningExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - bool parseAsExprList, TypeTy *&CastTy, + TypeTy *TypeOfCast, TypeTy *&CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); @@ -1315,7 +1316,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - OwningStmtResult Stmt(ParseCompoundStatement(true)); + OwningStmtResult Stmt(ParseCompoundStatement(0, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. @@ -1365,7 +1366,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false, false, true); + Result = ParseCastExpression(false, false, CastTy); if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(CurScope, OpenLoc, CastTy, RParenLoc, move(Result)); @@ -1374,15 +1375,15 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); - } else if (parseAsExprList) { + } else if (TypeOfCast) { // Parse the expression-list. ExprVector ArgExprs(Actions); CommaLocsTy CommaLocs; if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; - Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), - move_arg(ArgExprs)); + Result = Actions.ActOnParenOrParenListExpr(OpenLoc, Tok.getLocation(), + move_arg(ArgExprs), TypeOfCast); } } else { Result = ParseExpression(); @@ -1503,7 +1504,7 @@ void Parser::ParseBlockId() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1565,7 +1566,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } @@ -1586,7 +1587,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index b2ecc9e..52003e6 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -124,7 +124,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, break; } - if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) { + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && + TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) << TemplateName.getSourceRange(); @@ -148,7 +149,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TPA.Commit(); TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, - ObjectType); + ObjectType, EnteringContext); if (!Template) break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, @@ -326,6 +327,24 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /*ObjectType=*/0, Name)) return ExprError(); + + // This is only the direct operand of an & operator if it is not + // followed by a postfix-expression suffix. + if (isAddressOfOperand) { + switch (Tok.getKind()) { + case tok::l_square: + case tok::l_paren: + case tok::arrow: + case tok::period: + case tok::plusplus: + case tok::minusminus: + isAddressOfOperand = false; + break; + + default: + break; + } + } return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren), isAddressOfOperand); @@ -531,7 +550,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { CommaLocs.data(), RParenLoc); } -/// ParseCXXCondition - if/switch/while/for condition expression. +/// ParseCXXCondition - if/switch/while condition expression. /// /// condition: /// expression @@ -539,11 +558,20 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// -Parser::OwningExprResult Parser::ParseCXXCondition() { - if (!isCXXConditionDeclaration()) - return ParseExpression(); // expression - - SourceLocation StartLoc = Tok.getLocation(); +/// \param ExprResult if the condition was parsed as an expression, the +/// parsed expression. +/// +/// \param DeclResult if the condition was parsed as a declaration, the +/// parsed declaration. +/// +/// \returns true if there was a parsing, false otherwise. +bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult) { + if (!isCXXConditionDeclaration()) { + ExprResult = ParseExpression(); // expression + DeclResult = DeclPtrTy(); + return ExprResult.isInvalid(); + } // type-specifier-seq DeclSpec DS; @@ -559,7 +587,7 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { OwningExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi); - return ExprError(); + return true; } DeclaratorInfo.setAsmLabel(AsmLabel.release()); DeclaratorInfo.SetRangeEnd(Loc); @@ -568,21 +596,28 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } + // Type-check the declaration itself. + Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(CurScope, + DeclaratorInfo); + DeclResult = Dcl.get(); + ExprResult = ExprError(); + // '=' assignment-expression - if (Tok.isNot(tok::equal)) - return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator)); - SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult AssignExpr(ParseAssignmentExpression()); - if (AssignExpr.isInvalid()) - return ExprError(); - - return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc, - DeclaratorInfo,EqualLoc, - move(AssignExpr)); + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = ConsumeToken(); + OwningExprResult AssignExpr(ParseAssignmentExpression()); + if (!AssignExpr.isInvalid()) + Actions.AddInitializerToDecl(DeclResult, move(AssignExpr)); + } else { + // FIXME: C++0x allows a braced-init-list + Diag(Tok, diag::err_expected_equal_after_declarator); + } + + return false; } /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. @@ -757,6 +792,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, switch (Id.getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, Template); break; @@ -774,7 +810,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, - TemplateName, ObjectType); + TemplateName, ObjectType, + EnteringContext); TNK = TNK_Dependent_template_name; if (!Template.get()) return true; @@ -813,7 +850,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, return true; if (Id.getKind() == UnqualifiedId::IK_Identifier || - Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) { + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. TemplateIdAnnotation *TemplateId @@ -996,6 +1034,26 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); return false; } + + // Parse a literal-operator-id. + // + // literal-operator-id: [C++0x 13.5.8] + // operator "" identifier + + if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) { + if (Tok.getLength() != 2) + Diag(Tok.getLocation(), diag::err_operator_string_not_empty); + ConsumeStringToken(); + + if (Tok.isNot(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected_ident); + return true; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + Result.setLiteralOperatorId(II, KeywordLoc, ConsumeToken()); + return false; + } // Parse a conversion-function-id. // @@ -1010,7 +1068,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse the type-specifier-seq. DeclSpec DS; - if (ParseCXXTypeSpecifierSeq(DS)) + if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; // Parse the conversion-declarator, which is merely a sequence of @@ -1111,12 +1169,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) return true; - // If we have an operator-function-id and the next token is a '<', we may - // have a + // If we have an operator-function-id or a literal-operator-id and the next + // token is a '<', we may have a // // template-id: // operator-function-id < template-argument-list[opt] > - if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId && + if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || + Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), EnteringContext, ObjectType, @@ -1152,7 +1211,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Note that this is a destructor name. Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, - CurScope, &SS); + CurScope, &SS, false, ObjectType); if (!Ty) { if (ObjectType) Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 5ba1dd1..295625a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -282,7 +282,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. - allTUVariables.push_back(ParseDeclarationOrFunctionDefinition()); + allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0)); continue; } @@ -759,7 +759,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); + MethodAttrs = ParseGNUAttributes(); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); DeclPtrTy Result @@ -791,7 +791,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - ArgInfo.ArgAttrs = ParseAttributes(); + ArgInfo.ArgAttrs = ParseGNUAttributes(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing argument name. @@ -835,7 +835,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // If attributes exist after the method, parse them. AttributeList *MethodAttrs = 0; if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) - MethodAttrs = ParseAttributes(); + MethodAttrs = ParseGNUAttributes(); if (KeyIdents.size() == 0) return DeclPtrTy(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 7637382..c87010e 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -78,6 +78,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { const char *SemiError = 0; OwningStmtResult Res(Actions); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. @@ -98,14 +102,15 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(); + return ParseLabeledStatement(Attr.AttrList); } // PASS THROUGH. default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd); + DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd, + Attr); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -114,6 +119,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return StmtError(); } + // FIXME: Use the attributes // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -129,47 +135,50 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(); + return ParseCaseStatement(Attr.AttrList); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(); + return ParseDefaultStatement(Attr.AttrList); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(); + return ParseCompoundStatement(Attr.AttrList); case tok::semi: // C99 6.8.3p3: expression[opt] ';' return Actions.ActOnNullStmt(ConsumeToken()); case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(); + return ParseIfStatement(Attr.AttrList); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(); + return ParseSwitchStatement(Attr.AttrList); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(); + return ParseWhileStatement(Attr.AttrList); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(); + Res = ParseDoStatement(Attr.AttrList); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(); + return ParseForStatement(Attr.AttrList); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(); + Res = ParseGotoStatement(Attr.AttrList); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(); + Res = ParseContinueStatement(Attr.AttrList); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(); + Res = ParseBreakStatement(Attr.AttrList); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(); + Res = ParseReturnStatement(Attr.AttrList); SemiError = "return"; break; case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; bool msAsm = false; Res = ParseAsmStatement(msAsm); if (msAsm) return move(Res); @@ -178,7 +187,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(); + return ParseCXXTryBlock(Attr.AttrList); } // If we reached this code, the statement must end in a semicolon. @@ -202,7 +211,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -Parser::OwningStmtResult Parser::ParseLabeledStatement() { +Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); @@ -215,10 +224,8 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { SourceLocation ColonLoc = ConsumeToken(); // Read label attributes, if present. - Action::AttrTy *AttrList = 0; if (Tok.is(tok::kw___attribute)) - // TODO: save these somewhere. - AttrList = ParseAttributes(); + Attr = addAttributeLists(Attr, ParseGNUAttributes()); OwningStmtResult SubStmt(ParseStatement()); @@ -236,8 +243,9 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -Parser::OwningStmtResult Parser::ParseCaseStatement() { +Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); + // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -354,7 +362,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -Parser::OwningStmtResult Parser::ParseDefaultStatement() { +Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { + //FIXME: Use attributes? assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -408,7 +417,9 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement() { /// [OMP] barrier-directive /// [OMP] flush-directive /// -Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { +Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr, + bool isStmtExpr) { + //FIXME: Use attributes? assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound @@ -449,6 +460,10 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + // If this is the start of a declaration, parse it as such. if (isDeclarationStatement()) { // __extension__ silences extension warnings in the subdeclaration. @@ -456,7 +471,8 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd); + DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd, + Attr); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. @@ -467,6 +483,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } + // FIXME: Use attributes? // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); @@ -500,22 +517,22 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. -bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, - bool OnlyAllowCondition, - SourceLocation *LParenLocPtr, - SourceLocation *RParenLocPtr) { +bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, + DeclPtrTy &DeclResult) { + bool ParseError = false; + SourceLocation LParenLoc = ConsumeParen(); - if (LParenLocPtr) *LParenLocPtr = LParenLoc; - - if (getLang().CPlusPlus) - CondExp = ParseCXXCondition(); - else - CondExp = ParseExpression(); + if (getLang().CPlusPlus) + ParseError = ParseCXXCondition(ExprResult, DeclResult); + else { + ExprResult = ParseExpression(); + DeclResult = DeclPtrTy(); + } // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. - if (CondExp.isInvalid() && Tok.isNot(tok::r_paren)) { + if (ExprResult.isInvalid() && !DeclResult.get() && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. @@ -524,8 +541,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, } // Otherwise the condition is valid or the rparen is present. - SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - if (RParenLocPtr) *RParenLocPtr = RPLoc; + MatchRHSPunctuation(tok::r_paren, LParenLoc); return false; } @@ -537,7 +553,8 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -Parser::OwningStmtResult Parser::ParseIfStatement() { +Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -565,7 +582,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { // Parse the condition. OwningExprResult CondExp(Actions); - if (ParseParenExprOrCondition(CondExp)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(CondExp, CondVar)) return StmtError(); FullExprArg FullCondExp(Actions.FullExpr(CondExp)); @@ -632,7 +650,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. - if (CondExp.isInvalid()) + if (CondExp.isInvalid() && !CondVar.get()) return StmtError(); // If the then or else stmt is invalid and the other is valid (and present), @@ -651,7 +669,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt), + return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, move(ThenStmt), ElseLoc, move(ElseStmt)); } @@ -659,7 +677,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseSwitchStatement() { +Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -690,12 +709,13 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { // Parse the condition. OwningExprResult Cond(Actions); - if (ParseParenExprOrCondition(Cond)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); - OwningStmtResult Switch(Actions); - if (!Cond.isInvalid()) - Switch = Actions.ActOnStartOfSwitchStmt(move(Cond)); + FullExprArg FullCond(Actions.FullExpr(Cond)); + + OwningStmtResult Switch = Actions.ActOnStartOfSwitchStmt(FullCond, CondVar); // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -724,7 +744,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { SwitchScope.Exit(); - if (Cond.isInvalid()) + if (Cond.isInvalid() && !CondVar.get()) return StmtError(); return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body)); @@ -734,7 +754,8 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseWhileStatement() { +Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. @@ -769,7 +790,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { // Parse the condition. OwningExprResult Cond(Actions); - if (ParseParenExprOrCondition(Cond)) + DeclPtrTy CondVar; + if (ParseParenExprOrCondition(Cond, CondVar)) return StmtError(); FullExprArg FullCond(Actions.FullExpr(Cond)); @@ -795,17 +817,18 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { InnerScope.Exit(); WhileScope.Exit(); - if (Cond.isInvalid() || Body.isInvalid()) + if ((Cond.isInvalid() && !CondVar.get()) || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, FullCond, move(Body)); + return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, move(Body)); } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -Parser::OwningStmtResult Parser::ParseDoStatement() { +Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -854,10 +877,9 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { } // Parse the parenthesized condition. - OwningExprResult Cond(Actions); - SourceLocation LPLoc, RPLoc; - ParseParenExprOrCondition(Cond, true, &LPLoc, &RPLoc); - + SourceLocation LPLoc = ConsumeParen(); + OwningExprResult Cond = ParseExpression(); + SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) @@ -880,7 +902,8 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { /// [C++] expression-statement /// [C++] simple-declaration /// -Parser::OwningStmtResult Parser::ParseForStatement() { +Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -922,7 +945,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() { bool ForEach = false; OwningStmtResult FirstPart(Actions); OwningExprResult SecondPart(Actions), ThirdPart(Actions); - + DeclPtrTy SecondVar; + if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(CurScope); ConsumeToken(); @@ -937,13 +961,19 @@ Parser::OwningStmtResult Parser::ParseForStatement() { if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); + AttributeList *AttrList = 0; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + AttrList = ParseCXX0XAttributes().AttrList; + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, + AttrList); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' SecondPart = ParseExpression(); @@ -974,13 +1004,17 @@ Parser::OwningStmtResult Parser::ParseForStatement() { if (Tok.is(tok::semi)) { // for (...;; // no second part. } else { - SecondPart =getLang().CPlusPlus ? ParseCXXCondition() : ParseExpression(); + if (getLang().CPlusPlus) + ParseCXXCondition(SecondPart, SecondVar); + else + SecondPart = ParseExpression(); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { - if (!SecondPart.isInvalid()) Diag(Tok, diag::err_expected_semi_for); + if (!SecondPart.isInvalid() || SecondVar.get()) + Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } @@ -1019,8 +1053,9 @@ Parser::OwningStmtResult Parser::ParseForStatement() { if (!ForEach) return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), - move(SecondPart), move(ThirdPart), - RParenLoc, move(Body)); + Actions.FullExpr(SecondPart), SecondVar, + Actions.FullExpr(ThirdPart), RParenLoc, + move(Body)); return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), @@ -1035,7 +1070,8 @@ Parser::OwningStmtResult Parser::ParseForStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseGotoStatement() { +Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -1068,7 +1104,8 @@ Parser::OwningStmtResult Parser::ParseGotoStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseContinueStatement() { +Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { + // FIXME: Use attributes? SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, CurScope); } @@ -1079,7 +1116,8 @@ Parser::OwningStmtResult Parser::ParseContinueStatement() { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseBreakStatement() { +Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { + // FIXME: Use attributes? SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, CurScope); } @@ -1087,7 +1125,8 @@ Parser::OwningStmtResult Parser::ParseBreakStatement() { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -Parser::OwningStmtResult Parser::ParseReturnStatement() { +Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { + // FIXME: Use attributes? assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -1163,7 +1202,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { } DeclSpec DS; SourceLocation Loc = Tok.getLocation(); - ParseTypeQualifierListOpt(DS); + ParseTypeQualifierListOpt(DS, true, false); // GNU asms accept, but warn, about type-qualifiers other than volatile. if (DS.getTypeQualifiers() & DeclSpec::TQ_const) @@ -1371,7 +1410,8 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { /// try-block: /// 'try' compound-statement handler-seq /// -Parser::OwningStmtResult Parser::ParseCXXTryBlock() { +Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { + // FIXME: Add attributes? assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -1393,11 +1433,17 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlock() { Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); - OwningStmtResult TryBlock(ParseCompoundStatement()); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult TryBlock(ParseCompoundStatement(0)); if (TryBlock.isInvalid()) return move(TryBlock); StmtVector Handlers(Actions); + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + CXX0XAttributeList Attr = ParseCXX0XAttributes(); + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + } if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { @@ -1457,7 +1503,8 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); - OwningStmtResult Block(ParseCompoundStatement()); + // FIXME: Possible draft standard bug: attribute-specifier should be allowed? + OwningStmtResult Block(ParseCompoundStatement(0)); if (Block.isInvalid()) return move(Block); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 16b1c80..0dbf37c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -16,7 +16,6 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "llvm/Support/Compiler.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -34,7 +33,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, /// \brief RAII class that manages the template parameter depth. namespace { - class VISIBILITY_HIDDEN TemplateParameterDepthCounter { + class TemplateParameterDepthCounter { unsigned &Depth; unsigned AddedLevels; @@ -192,6 +191,10 @@ Parser::ParseSingleDeclarationAfterTemplate( // Parse the declaration specifiers. ParsingDeclSpec DS(*this); + + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + DS.AddAttributes(ParseCXX0XAttributes().AttrList); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { @@ -333,6 +336,40 @@ Parser::ParseTemplateParameterList(unsigned Depth, return true; } +/// \brief Determine whether the parser is at the start of a template +/// type parameter. +bool Parser::isStartOfTemplateTypeParameter() { + if (Tok.is(tok::kw_class)) + return true; + + if (Tok.isNot(tok::kw_typename)) + return false; + + // C++ [temp.param]p2: + // There is no semantic difference between class and typename in a + // template-parameter. typename followed by an unqualified-id + // names a template type parameter. typename followed by a + // qualified-id denotes the type in a non-type + // parameter-declaration. + Token Next = NextToken(); + + // If we have an identifier, skip over it. + if (Next.getKind() == tok::identifier) + Next = GetLookAheadToken(2); + + switch (Next.getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + default: + return false; + } +} + /// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). /// /// template-parameter: [C++ temp.param] @@ -348,12 +385,8 @@ Parser::ParseTemplateParameterList(unsigned Depth, /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression Parser::DeclPtrTy Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (Tok.is(tok::kw_class) || - (Tok.is(tok::kw_typename) && - // FIXME: Next token has not been annotated! - NextToken().isNot(tok::annot_typename))) { + if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); - } if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -851,7 +884,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (isEndOfTemplateArgument(Tok)) { TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, - /*ObjectType=*/0); + /*ObjectType=*/0, + /*EnteringContext=*/false); if (Template.get()) return ParsedTemplateArgument(SS, Template, Name.StartLocation); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 7ac2977..dabd065 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -55,12 +55,11 @@ bool Parser::isCXXDeclarationStatement() { // using-declaration // using-directive case tok::kw_using: - return true; - case tok::kw_static_assert: // static_assert-declaration + case tok::kw_static_assert: return true; - default: // simple-declaration + default: return isCXXSimpleDeclaration(); } } @@ -351,6 +350,89 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { return TPR == TPResult::True(); } +/// isCXX0XAttributeSpecifier - returns true if this is a C++0x +/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is +/// performed that will simply return true if a [[ is seen. Currently C++ has no +/// syntactical ambiguities from this check, but it may inhibit error recovery. +/// If CheckClosing is true, a check is made for closing ]] brackets. +/// +/// If given, After is set to the token after the attribute-specifier so that +/// appropriate parsing decisions can be made; it is left untouched if false is +/// returned. +/// +/// FIXME: If an error is in the closing ]] brackets, the program assumes +/// the absence of an attribute-specifier, which can cause very yucky errors +/// to occur. +/// +/// [C++0x] attribute-specifier: +/// '[' '[' attribute-list ']' ']' +/// +/// [C++0x] attribute-list: +/// attribute[opt] +/// attribute-list ',' attribute[opt] +/// +/// [C++0x] attribute: +/// attribute-token attribute-argument-clause[opt] +/// +/// [C++0x] attribute-token: +/// identifier +/// attribute-scoped-token +/// +/// [C++0x] attribute-scoped-token: +/// attribute-namespace '::' identifier +/// +/// [C++0x] attribute-namespace: +/// identifier +/// +/// [C++0x] attribute-argument-clause: +/// '(' balanced-token-seq ')' +/// +/// [C++0x] balanced-token-seq: +/// balanced-token +/// balanced-token-seq balanced-token +/// +/// [C++0x] balanced-token: +/// '(' balanced-token-seq ')' +/// '[' balanced-token-seq ']' +/// '{' balanced-token-seq '}' +/// any token but '(', ')', '[', ']', '{', or '}' +bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, + tok::TokenKind *After) { + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) + return false; + + // No tentative parsing if we don't need to look for ]] + if (!CheckClosing && !getLang().ObjC1) + return true; + + struct TentativeReverter { + TentativeParsingAction PA; + + TentativeReverter (Parser& P) + : PA(P) + {} + ~TentativeReverter () { + PA.Revert(); + } + } R(*this); + + // Opening brackets were checked for above. + ConsumeBracket(); + ConsumeBracket(); + + // SkipUntil will handle balanced tokens, which are guaranteed in attributes. + SkipUntil(tok::r_square, false); + + if (Tok.isNot(tok::r_square)) + return false; + ConsumeBracket(); + + if (After) + *After = Tok.getKind(); + + return true; +} + /// declarator: /// direct-declarator /// ptr-operator declarator diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a915274..e321564 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -355,7 +355,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return true; } - Result = ParseExternalDeclaration(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + Result = ParseExternalDeclaration(Attr); return false; } @@ -396,7 +399,7 @@ void Parser::ParseTranslationUnit() { /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration -Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { +Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) { DeclPtrTy SingleDecl; switch (Tok.getKind()) { case tok::semi: @@ -418,9 +421,13 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseExternalDeclaration(); + return ParseExternalDeclaration(Attr); } case tok::kw_asm: { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + OwningExprResult Result(ParseSimpleAsm()); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, @@ -449,7 +456,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { case tok::code_completion: Actions.CodeCompleteOrdinaryName(CurScope); ConsumeToken(); - return ParseExternalDeclaration(); + return ParseExternalDeclaration(Attr); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: @@ -459,7 +466,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // A function definition cannot start with a these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(Declarator::FileContext, DeclEnd); + return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); } case tok::kw_extern: if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { @@ -477,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { default: // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(); + return ParseDeclarationOrFunctionDefinition(Attr.AttrList); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -525,9 +532,13 @@ bool Parser::isStartOfFunctionDefinition() { /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { +Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, + AccessSpecifier AS) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); + if (Attr) + DS.AddAttributes(Attr); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -719,7 +730,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // If attributes are present, parse them. if (Tok.is(tok::kw___attribute)) // FIXME: attach attributes too. - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index b4bf419..342b0e6 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -353,7 +353,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { RewriteBuffer &RB = R.getEditBuffer(FID); const SourceManager &SM = PP.getSourceManager(); - Lexer L(FID, SM, PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer L(FID, FromFile, SM, PP.getLangOptions()); const char *BufferStart = L.getBufferStart(); // Inform the preprocessor that we want to retain comments as tokens, so we @@ -444,7 +445,8 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { const SourceManager &SM = PP.getSourceManager(); std::vector TokenStream; - Lexer L(FID, SM, PP.getLangOptions()); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer L(FID, FromFile, SM, PP.getLangOptions()); // Lex all the tokens in raw mode, to avoid entering #includes or expanding // macros. diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp index 0effbb1..789d53f 100644 --- a/lib/Rewrite/TokenRewriter.cpp +++ b/lib/Rewrite/TokenRewriter.cpp @@ -23,7 +23,8 @@ TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, ScratchBuf.reset(new ScratchBuffer(SM)); // Create a lexer to lex all the tokens of the main file in raw mode. - Lexer RawLex(FID, SM, LangOpts); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer RawLex(FID, FromFile, SM, LangOpts); // Return all comments and whitespace as tokens. RawLex.SetKeepWhitespaceMode(true); diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index a9d8301..91b16d3 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -14,10 +14,10 @@ #include "clang/AST/DeclCXX.h" #include "clang/Parse/Scope.h" #include "clang/Lex/Preprocessor.h" +#include "clang-c/Index.h" #include "Sema.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -210,306 +210,111 @@ CodeCompletionString *CodeCompletionString::Clone() const { return Result; } -namespace { - // Escape a string for XML-like formatting. - struct EscapedString { - EscapedString(llvm::StringRef Str) : Str(Str) { } - - llvm::StringRef Str; - }; - - llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) { - llvm::StringRef Str = EStr.Str; - while (!Str.empty()) { - // Find the next escaped character. - llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'"); - - // Print everything before that escaped character. - OS << Str.substr(0, Pos); +static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { + OS.write((const char *)&Value, sizeof(unsigned)); +} - // If we didn't find any escaped characters, we're done. - if (Pos == llvm::StringRef::npos) - break; - - // Print the appropriate escape sequence. - switch (Str[Pos]) { - case '<': OS << "<"; break; - case '>': OS << ">"; break; - case '&': OS << "&"; break; - case '"': OS << """; break; - case '\'': OS << "'"; break; - } - - // Remove everything up to and including that escaped character. - Str = Str.substr(Pos + 1); - } - - return OS; - } - - /// \brief Remove XML-like escaping from a string. - std::string UnescapeString(llvm::StringRef Str) { - using llvm::StringRef; - - std::string Result; - llvm::raw_string_ostream OS(Result); - - while (!Str.empty()) { - StringRef::size_type Amp = Str.find('&'); - OS << Str.substr(0, Amp); - - if (Amp == StringRef::npos) - break; - - StringRef::size_type Semi = Str.substr(Amp).find(';'); - if (Semi == StringRef::npos) { - // Malformed input; do the best we can. - OS << '&'; - Str = Str.substr(Amp + 1); - continue; - } - - char Unescaped = llvm::StringSwitch(Str.substr(Amp + 1, Semi - 1)) - .Case("lt", '<') - .Case("gt", '>') - .Case("amp", '&') - .Case("quot", '"') - .Case("apos", '\'') - .Default('\0'); - - if (Unescaped) - OS << Unescaped; - else - OS << Str.substr(Amp, Semi + 1); - Str = Str.substr(Amp + Semi + 1); - } - - return OS.str(); - } +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; } void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { + // Write the number of chunks. + WriteUnsigned(OS, size()); + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { + WriteUnsigned(OS, C->Kind); + switch (C->Kind) { case CK_TypedText: - OS << "" << EscapedString(C->Text) << ""; - break; case CK_Text: - OS << "" << EscapedString(C->Text) << ""; - break; - case CK_Optional: - OS << ""; - C->Optional->Serialize(OS); - OS << ""; - break; case CK_Placeholder: - OS << "" << EscapedString(C->Text) << ""; - break; case CK_Informative: - OS << "" << EscapedString(C->Text) << ""; + case CK_CurrentParameter: { + const char *Text = C->Text; + unsigned StrLen = strlen(Text); + WriteUnsigned(OS, StrLen); + OS.write(Text, StrLen); break; - case CK_CurrentParameter: - OS << "" << EscapedString(C->Text) << ""; + } + + case CK_Optional: + C->Optional->Serialize(OS); break; + case CK_LeftParen: - OS << ""; - break; case CK_RightParen: - OS << ""; - break; case CK_LeftBracket: - OS << ""; - break; case CK_RightBracket: - OS << ""; - break; case CK_LeftBrace: - OS << ""; - break; case CK_RightBrace: - OS << ""; - break; case CK_LeftAngle: - OS << ""; - break; case CK_RightAngle: - OS << ""; - break; case CK_Comma: - OS << ""; break; - } + } } } -/// \brief Parse the next XML-ish tag of the form . -/// -/// \param Str the string in which we're looking for the next tag. -/// -/// \param TagPos if successful, will be set to the start of the tag we found. -/// -/// \param Standalone will indicate whether this is a "standalone" tag that -/// has no associated data, e.g., . -/// -/// \param Terminator will indicate whether this is a terminating tag (that is -/// or starts with '/'). -/// -/// \returns the tag itself, without the angle brackets. -static llvm::StringRef ParseNextTag(llvm::StringRef Str, - llvm::StringRef::size_type &StartTag, - llvm::StringRef::size_type &AfterTag, - bool &Standalone, bool &Terminator) { - using llvm::StringRef; - - Standalone = false; - Terminator = false; - AfterTag = StringRef::npos; - - // Find the starting '<'. - StartTag = Str.find('<'); - if (StartTag == StringRef::npos) - return llvm::StringRef(); - - // Find the corresponding '>'. - llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>'); - if (EndTag == StringRef::npos) - return llvm::StringRef(); - AfterTag = StartTag + EndTag + 1; - - // Determine whether this is a terminating tag. - if (Str[StartTag + 1] == '/') { - Terminator = true; - Str = Str.substr(1); - --EndTag; - } - - // Determine whether this is a standalone tag. - if (!Terminator && Str[StartTag + EndTag - 1] == '/') { - Standalone = true; - if (EndTag > 1) - --EndTag; - } - - return Str.substr(StartTag + 1, EndTag - 1); -} +CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, + const char *StrEnd) { + if (Str == StrEnd || *Str == 0) + return 0; -CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { - using llvm::StringRef; - CodeCompletionString *Result = new CodeCompletionString; - - do { - // Parse the next tag. - StringRef::size_type StartTag, AfterTag; - bool Standalone, Terminator; - StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, - Terminator); - - if (StartTag == StringRef::npos) + unsigned NumBlocks; + if (ReadUnsigned(Str, StrEnd, NumBlocks)) + return Result; + + for (unsigned I = 0; I != NumBlocks; ++I) { + if (Str + 1 >= StrEnd) break; - - // Figure out what kind of chunk we have. - const unsigned UnknownKind = 10000; - unsigned Kind = llvm::StringSwitch(Tag) - .Case("typed-text", CK_TypedText) - .Case("text", CK_Text) - .Case("optional", CK_Optional) - .Case("placeholder", CK_Placeholder) - .Case("informative", CK_Informative) - .Case("current-parameter", CK_CurrentParameter) - .Case("lparen", CK_LeftParen) - .Case("rparen", CK_RightParen) - .Case("lbracket", CK_LeftBracket) - .Case("rbracket", CK_RightBracket) - .Case("lbrace", CK_LeftBrace) - .Case("rbrace", CK_RightBrace) - .Case("langle", CK_LeftAngle) - .Case("rangle", CK_RightAngle) - .Case("comma", CK_Comma) - .Default(UnknownKind); - - // If we've hit a terminator tag, we're done. - if (Terminator) + + // Parse the next kind. + unsigned KindValue; + if (ReadUnsigned(Str, StrEnd, KindValue)) + return Result; + + switch (ChunkKind Kind = (ChunkKind)KindValue) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: { + unsigned StrLen; + if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd)) + return Result; + + Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen))); + Str += StrLen; break; - - // Consume the tag. - Str = Str.substr(AfterTag); - - // Handle standalone tags now, since they don't need to be matched to - // anything. - if (Standalone) { - // Ignore anything we don't know about. - if (Kind == UnknownKind) - continue; - - switch ((ChunkKind)Kind) { - case CK_TypedText: - case CK_Text: - case CK_Optional: - case CK_Placeholder: - case CK_Informative: - case CK_CurrentParameter: - // There is no point in creating empty chunks of these kinds. - break; - - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - Result->AddChunk(Chunk((ChunkKind)Kind)); - break; - } - - continue; } - - if (Kind == CK_Optional) { - // Deserialize the optional code-completion string. - std::auto_ptr Optional(Deserialize(Str)); + + case CK_Optional: { + std::auto_ptr Optional(Deserialize(Str, StrEnd)); Result->AddOptionalChunk(Optional); + break; } - - StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, - Terminator); - if (StartTag == StringRef::npos || !Terminator || Standalone) - break; // Parsing failed; just give up. - - if (EndTag.empty() || Tag == EndTag) { - // Found the matching end tag. Add this chunk based on the text - // between the tags, then consume that input. - StringRef Text = Str.substr(0, StartTag); - switch ((ChunkKind)Kind) { - case CK_TypedText: - case CK_Text: - case CK_Placeholder: - case CK_Informative: - case CK_CurrentParameter: - case CK_LeftParen: - case CK_RightParen: - case CK_LeftBracket: - case CK_RightBracket: - case CK_LeftBrace: - case CK_RightBrace: - case CK_LeftAngle: - case CK_RightAngle: - case CK_Comma: - Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text))); - break; - - case CK_Optional: - // We've already added the optional chunk. - break; - } + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + Result->AddChunk(Chunk(Kind)); + break; } - - // Remove this tag. - Str = Str.substr(AfterTag); - } while (!Str.empty()); + }; return Result; } @@ -633,62 +438,110 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { - OS << "COMPLETION:" << Results[I].Rank << ":"; + CXCursorKind Kind = CXCursor_NotImplemented; + switch (Results[I].Kind) { - case Result::RK_Declaration: - if (RecordDecl *Record = dyn_cast(Results[I].Declaration)) { - if (Record->isStruct()) - OS << "Struct:"; - else if (Record->isUnion()) - OS << "Union:"; - else - OS << "Class:"; - } else if (ObjCMethodDecl *Method - = dyn_cast(Results[I].Declaration)) { - if (Method->isInstanceMethod()) - OS << "ObjCInstanceMethod:"; - else - OS << "ObjCClassMethod:"; - } else { - OS << Results[I].Declaration->getDeclKindName() << ":"; - } - if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { - CCS->Serialize(OS); - delete CCS; - } else { - OS << "" - << Results[I].Declaration->getNameAsString() - << ""; - } + case Result::RK_Declaration: + switch (Results[I].Declaration->getKind()) { + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: { + RecordDecl *Record = cast(Results[I].Declaration); + if (Record->isStruct()) + Kind = CXCursor_StructDecl; + else if (Record->isUnion()) + Kind = CXCursor_UnionDecl; + else + Kind = CXCursor_ClassDecl; + break; + } + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast(Results[I].Declaration); + if (Method->isInstanceMethod()) + Kind = CXCursor_ObjCInstanceMethodDecl; + else + Kind = CXCursor_ObjCClassMethodDecl; + break; + } - OS << '\n'; + case Decl::Typedef: + Kind = CXCursor_TypedefDecl; break; - case Result::RK_Keyword: - OS << "Keyword:" << Results[I].Keyword << "\n"; + case Decl::Enum: + Kind = CXCursor_EnumDecl; break; - case Result::RK_Macro: { - OS << "Macro:"; - if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { - CCS->Serialize(OS); - delete CCS; - } else { - OS << "" << Results[I].Macro->getName() << ""; - } - OS << '\n'; + case Decl::Field: + Kind = CXCursor_FieldDecl; + break; + + case Decl::EnumConstant: + Kind = CXCursor_EnumConstantDecl; + break; + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + Kind = CXCursor_FunctionDecl; + break; + + case Decl::Var: + Kind = CXCursor_VarDecl; + break; + + case Decl::ParmVar: + Kind = CXCursor_ParmDecl; + break; + + case Decl::ObjCInterface: + Kind = CXCursor_ObjCInterfaceDecl; + break; + + case Decl::ObjCCategory: + Kind = CXCursor_ObjCCategoryDecl; + break; + + case Decl::ObjCProtocol: + Kind = CXCursor_ObjCProtocolDecl; break; - } - case Result::RK_Pattern: { - OS << "Pattern:"; - Results[I].Pattern->Serialize(OS); - OS << '\n'; + case Decl::ObjCProperty: + Kind = CXCursor_ObjCPropertyDecl; + break; + + case Decl::ObjCIvar: + Kind = CXCursor_ObjCIvarDecl; + break; + + case Decl::ObjCImplementation: + Kind = CXCursor_ObjCClassDefn; + break; + + case Decl::ObjCCategoryImpl: + Kind = CXCursor_ObjCCategoryDefn; + break; + + default: break; } + break; + + case Result::RK_Keyword: + case Result::RK_Macro: + case Result::RK_Pattern: + Kind = CXCursor_NotImplemented; + break; } + + WriteUnsigned(OS, Kind); + CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); + assert(CCS && "No code-completion string?"); + CCS->Serialize(OS); + delete CCS; } // Once we've printed the code-completion results, suppress remaining @@ -703,13 +556,12 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, OverloadCandidate *Candidates, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { - if (CodeCompletionString *CCS - = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { - OS << "OVERLOAD:"; - CCS->Serialize(OS); - OS << '\n'; - delete CCS; - } + WriteUnsigned(OS, CXCursor_NotImplemented); + CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); + assert(CCS && "No code-completion string?"); + CCS->Serialize(OS); + delete CCS; } // Once we've printed the code-completion results, suppress remaining diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 10cc818..e2134a2 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -208,6 +208,15 @@ public: return getResultKind() == Found; } + /// Determines if the results are overloaded. + bool isOverloadedResult() const { + return getResultKind() == FoundOverloaded; + } + + bool isUnresolvableResult() const { + return getResultKind() == FoundUnresolvedValue; + } + LookupResultKind getResultKind() const { sanity(); return ResultKind; @@ -280,6 +289,12 @@ public: /// ambiguous and overloaded lookups. NamedDecl *getAsSingleDecl(ASTContext &Context) const; + template + DeclClass *getAsSingle() const { + if (getResultKind() != Found) return 0; + return dyn_cast(getFoundDecl()); + } + /// \brief Fetch the unique decl found by this lookup. Asserts /// that one was found. /// @@ -368,14 +383,14 @@ public: class Filter { LookupResult &Results; unsigned I; - bool ErasedAny; + bool Changed; #ifndef NDEBUG bool CalledDone; #endif friend class LookupResult; Filter(LookupResult &Results) - : Results(Results), I(0), ErasedAny(false) + : Results(Results), I(0), Changed(false) #ifndef NDEBUG , CalledDone(false) #endif @@ -402,7 +417,12 @@ public: void erase() { Results.Decls[--I] = Results.Decls.back(); Results.Decls.pop_back(); - ErasedAny = true; + Changed = true; + } + + void replace(NamedDecl *D) { + Results.Decls[I-1] = D; + Changed = true; } void done() { @@ -411,7 +431,7 @@ public: CalledDone = true; #endif - if (ErasedAny) + if (Changed) Results.resolveKindAfterFilter(); } }; @@ -438,15 +458,25 @@ private: void sanity() const { assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); - assert(ResultKind == NotFound || ResultKind == Found || - ResultKind == FoundUnresolvedValue || - (ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects) - || Decls.size() > 1); + assert(ResultKind != FoundOverloaded || Decls.size() > 1 || + (Decls.size() == 1 && + isa(Decls[0]->getUnderlyingDecl()))); + assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); + assert(ResultKind != Ambiguous || Decls.size() > 1 || + (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); assert((Paths != NULL) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); } + bool sanityCheckUnresolved() const { + for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end(); + I != E; ++I) + if (isa(*I)) + return true; + return false; + } + static void deletePaths(CXXBasePaths *); // Results. diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 7b223a8..7c7df4b 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -90,8 +90,5 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Decl::PrintStats(); Stmt::PrintStats(); Consumer->PrintStats(); - - Decl::CollectingStats(false); - Stmt::CollectingStats(false); } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fe2d744..f0812bf 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -299,17 +299,15 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { // Built-in ObjC types may already be set by PCHReader (hence isNull checks). if (Context.getObjCSelType().isNull()) { - // Synthesize "typedef struct objc_selector *SEL;" - RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector"); - PushOnScopeChains(SelTag, TUScope); - - QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); + // Create the built-in typedef for 'SEL'. + QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT); TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("SEL"), SelInfo); PushOnScopeChains(SelTypedef, TUScope); Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); + Context.ObjCSelRedefinitionType = Context.getObjCSelType(); } // Synthesize "@class Protocol; @@ -354,7 +352,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), - GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), + GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), NonInstantiationEntries(0), CurrentInstantiationScope(0) @@ -365,6 +363,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Tell diagnostics how to render things from the AST library. PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); + + ExprEvalContexts.push_back( + ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } /// Retrieves the width and signedness of the given integer type, @@ -594,7 +595,7 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { /// Implements -Wconversion. static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { // Don't diagnose in unevaluated contexts. - if (S.ExprEvalContext == Sema::Unevaluated) + if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) return; // Don't diagnose for value-dependent expressions. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ad4c90b..b594ece 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -330,18 +330,49 @@ public: /// have been declared. bool GlobalNewDeleteDeclared; - /// The current expression evaluation context. - ExpressionEvaluationContext ExprEvalContext; - - typedef std::vector > + /// \brief The set of declarations that have been referenced within + /// a potentially evaluated expression. + typedef std::vector > PotentiallyReferencedDecls; - /// A stack of declarations, each element of which is a set of declarations - /// that will be marked as referenced if the corresponding potentially - /// potentially evaluated expression is potentially evaluated. Each element - /// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression - /// evaluation context. - std::list PotentiallyReferencedDeclStack; + /// \brief Data structure used to record current or nested + /// expression evaluation contexts. + struct ExpressionEvaluationContextRecord { + /// \brief The expression evaluation context. + ExpressionEvaluationContext Context; + + /// \brief The number of temporaries that were active when we + /// entered this expression evaluation context. + unsigned NumTemporaries; + + /// \brief The set of declarations referenced within a + /// potentially potentially-evaluated context. + /// + /// When leaving a potentially potentially-evaluated context, each + /// of these elements will be as referenced if the corresponding + /// potentially potentially evaluated expression is potentially + /// evaluated. + PotentiallyReferencedDecls *PotentiallyReferenced; + + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, + unsigned NumTemporaries) + : Context(Context), NumTemporaries(NumTemporaries), + PotentiallyReferenced(0) { } + + void addReferencedDecl(SourceLocation Loc, Decl *Decl) { + if (!PotentiallyReferenced) + PotentiallyReferenced = new PotentiallyReferencedDecls; + PotentiallyReferenced->push_back(std::make_pair(Loc, Decl)); + } + + void Destroy() { + delete PotentiallyReferenced; + PotentiallyReferenced = 0; + } + }; + + /// A stack of expression evaluation contexts. + llvm::SmallVector ExprEvalContexts; /// \brief Whether the code handled by Sema should be considered a /// complete translation unit or not. @@ -428,13 +459,20 @@ public: virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); - OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); } + OwningExprResult Owned(Expr* E) { + assert(!E || E->isRetained()); + return OwningExprResult(*this, E); + } OwningExprResult Owned(ExprResult R) { if (R.isInvalid()) return ExprError(); + assert(!R.get() || ((Expr*) R.get())->isRetained()); return OwningExprResult(*this, R.get()); } - OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); } + OwningStmtResult Owned(Stmt* S) { + assert(!S || S->isRetained()); + return OwningStmtResult(*this, S); + } virtual void ActOnEndOfTranslationUnit(); @@ -485,7 +523,7 @@ public: /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); DeclarationName GetNameForDeclarator(Declarator &D); - DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name); + DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); @@ -533,7 +571,8 @@ public: virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName = false); + bool isClassName = false, + TypeTy *ObjectType = 0); virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, @@ -893,17 +932,13 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, @@ -939,9 +974,7 @@ public: OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, @@ -958,26 +991,23 @@ public: bool Complain); Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); - void AddOverloadedCallCandidates(NamedDecl *Callee, + void AddOverloadedCallCandidates(llvm::SmallVectorImpl& Callees, DeclarationName &UnqualifiedName, - bool &ArgumentDependentLookup, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + bool ArgumentDependentLookup, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); - FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, + FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, + llvm::SmallVectorImpl &Fns, DeclarationName UnqualifiedName, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, SourceLocation RParenLoc, - bool &ArgumentDependentLookup); + bool ArgumentDependentLookup); OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, @@ -1260,6 +1290,7 @@ public: virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc); + virtual void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal, SourceLocation DotDotDotLoc, ExprArg RHSVal, SourceLocation ColonLoc); @@ -1273,13 +1304,16 @@ public: SourceLocation ColonLoc, StmtArg SubStmt); virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, StmtArg ThenVal, + FullExprArg CondVal, DeclPtrTy CondVar, + StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond); + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + DeclPtrTy CondVar); virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, StmtArg Body); + FullExprArg Cond, + DeclPtrTy CondVar, StmtArg Body); virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, SourceLocation WhileLoc, SourceLocation CondLParen, ExprArg Cond, @@ -1287,8 +1321,10 @@ public: virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - ExprArg Third, SourceLocation RParenLoc, + StmtArg First, FullExprArg Second, + DeclPtrTy SecondVar, + FullExprArg Third, + SourceLocation RParenLoc, StmtArg Body); virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, SourceLocation LParenLoc, @@ -1379,12 +1415,10 @@ public: const PartialDiagnostic &PD, bool Equality = false); - virtual ExpressionEvaluationContext + virtual void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); - virtual void - PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext); + virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); @@ -1396,10 +1430,19 @@ public: UnqualifiedId &Name, bool HasTrailingLParen, bool IsAddressOfOperand); + + OwningExprResult LookupInObjCMethod(LookupResult &R, + Scope *S, + IdentifierInfo *II); + + OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + bool CheckForImplicitMember, + const TemplateArgumentListInfo *TemplateArgs); OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, - SourceLocation Loc, bool TypeDependent, - bool ValueDependent, + SourceLocation Loc, const CXXScopeSpec *SS = 0); VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, llvm::SmallVectorImpl &Path); @@ -1408,15 +1451,27 @@ public: FieldDecl *Field, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); - OwningExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, - DeclarationName Name, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand = false); - OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand); + OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs); + bool UseArgumentDependentLookup(const CXXScopeSpec &SS, + const LookupResult &R, + bool HasTrailingLParen); + + OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc); + OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs); + + OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool ADL); + OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + SourceLocation Loc, + NamedDecl *D); virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); @@ -1424,9 +1479,10 @@ public: virtual OwningExprResult ActOnCharacterConstant(const Token &); virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, ExprArg Val); - virtual OwningExprResult ActOnParenListExpr(SourceLocation L, + virtual OwningExprResult ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val); + MultiExprArg Val, + TypeTy *TypeOfCast=0); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). @@ -1468,36 +1524,40 @@ public: ExprArg Idx, SourceLocation RLoc); - OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + OwningExprResult BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - DeclarationName MemberName, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS = 0, - NamedDecl *FirstQualifierInScope = 0) { - // FIXME: Temporary helper while we migrate existing calls to - // BuildMemberReferenceExpr to support explicitly-specified template - // arguments. - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, - MemberName, false, SourceLocation(), 0, 0, - SourceLocation(), ImplDecl, SS, - FirstQualifierInScope); - } + bool IsArrow, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs); - OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs); + + OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclPtrTy ObjCImpDecl); + + bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R); + + OwningExprResult ActOnDependentMemberExpr(ExprArg Base, + bool IsArrow, SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - DeclarationName MemberName, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS, - NamedDecl *FirstQualifierInScope = 0); + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs); virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -1515,14 +1575,14 @@ public: SourceLocation RParenLoc); void DeconstructCallFunction(Expr *FnExpr, - NamedDecl *&Function, + llvm::SmallVectorImpl& Fns, DeclarationName &Name, NestedNameSpecifier *&Qualifier, SourceRange &QualifierRange, bool &ArgumentDependentLookup, - bool &HasExplicitTemplateArguments, - const TemplateArgumentLoc *&ExplicitTemplateArgs, - unsigned &NumExplicitTemplateArgs); + bool &Overloaded, + bool &HasExplicitTemplateArgs, + TemplateArgumentListInfo &ExplicitTemplateArgs); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma @@ -1536,6 +1596,9 @@ public: virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + virtual bool TypeIsVectorType(TypeTy *Ty) { + return GetTypeFromParser(Ty)->isVectorType(); + } OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, @@ -1868,15 +1931,10 @@ public: bool UseGlobal, bool ArrayForm, ExprArg Operand); - /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a - /// C++ if/switch/while/for statement. - /// e.g: "if (int x = f()) {...}" - virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, - SourceLocation StartLoc, - Declarator &D, - SourceLocation EqualLoc, - ExprArg AssignExprVal); - + virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, + Declarator &D); + OwningExprResult CheckConditionVariable(VarDecl *ConditionVar); + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, @@ -2028,7 +2086,7 @@ public: Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, - ExprTy *Init, + ExprTy *Init, bool IsDefinition, bool Deleted = false); virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD, @@ -2093,14 +2151,12 @@ public: void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, FunctionDecl::StorageClass& SC); - void CheckDestructor(CXXDestructorDecl *Destructor); + bool CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - bool isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, - SourceLocation NameLoc, QualType &ThisType, - QualType &MemberType); + bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType); //===--------------------------------------------------------------------===// // C++ Derived Classes @@ -2147,6 +2203,11 @@ public: bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); + /// CheckOverridingFunctionAttributes - Checks whether attributes are + /// incompatible or prevent overriding. + bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + //===--------------------------------------------------------------------===// // C++ Access Control // @@ -2190,6 +2251,9 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // + void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS, + QualType ObjectType, bool EnteringContext); + virtual TemplateNameKind isTemplateName(Scope *S, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -2235,8 +2299,19 @@ public: SourceLocation LAngleLoc, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc); + + /// \brief The context in which we are checking a template parameter + /// list. + enum TemplateParamListContext { + TPC_ClassTemplate, + TPC_FunctionTemplate, + TPC_ClassTemplateMember, + TPC_FriendFunctionTemplate + }; + bool CheckTemplateParameterList(TemplateParameterList *NewParams, - TemplateParameterList *OldParams); + TemplateParameterList *OldParams, + TemplateParamListContext TPC); TemplateParameterList * MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, const CXXScopeSpec &SS, @@ -2251,15 +2326,12 @@ public: TemplateParameterList *TemplateParams, AccessSpecifier AS); - void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - llvm::SmallVectorImpl &TempArgs); + void translateTemplateArguments(const ASTTemplateArgsPtr &In, + TemplateArgumentListInfo &Out); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo &TemplateArgs); virtual TypeResult ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, @@ -2272,26 +2344,20 @@ public: DeclSpec::TST TagSpec, SourceLocation TagLoc); - OwningExprResult BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc); - - OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc); + OwningExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo &TemplateArgs); + OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo &TemplateArgs); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, - TypeTy *ObjectType); + TypeTy *ObjectType, + bool EnteringContext); bool CheckClassTemplatePartialSpecializationArgs( TemplateParameterList *TemplateParams, @@ -2327,11 +2393,7 @@ public: bool &SuppressNew); bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, + const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); @@ -2365,6 +2427,13 @@ public: SourceLocation TemplateLoc, Declarator &D); + TemplateArgumentLoc + SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + TemplateArgumentListBuilder &Converted); + bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, TemplateDecl *Template, @@ -2374,10 +2443,7 @@ public: bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc, + const TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted); @@ -2603,8 +2669,7 @@ public: TemplateDeductionResult SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo &ExplicitTemplateArgs, llvm::SmallVectorImpl &Deduced, llvm::SmallVectorImpl &ParamTypes, QualType *FunctionType, @@ -2618,18 +2683,14 @@ public: TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); @@ -3312,9 +3373,20 @@ public: VariadicFunction, VariadicBlock, VariadicMethod, - VariadicConstructor + VariadicConstructor, + VariadicDoesNotApply }; + /// GatherArgumentsForCall - Collector argument expressions for various + /// form of call prototypes. + bool GatherArgumentsForCall(SourceLocation CallLoc, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + unsigned FirstProtoArg, + Expr **Args, unsigned NumArgs, + llvm::SmallVector &AllArgs, + VariadicCallType CallType = VariadicDoesNotApply); + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will warn if the resulting type is not a POD type. bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 6dbb442..b386adb 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -206,17 +206,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), CurContext); - // Handle each declaration in an overload set separately. - if (OverloadedFunctionDecl *Ovl - = dyn_cast(R.Declaration)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) - MaybeAddResult(Result(*F, R.Rank, R.Qualifier), CurContext); - - return; - } - Decl *CanonDecl = R.Declaration->getCanonicalDecl(); unsigned IDNS = CanonDecl->getIdentifierNamespace(); @@ -704,7 +693,7 @@ static void AddFunctionParameterChunks(ASTContext &Context, Context.PrintingPolicy); // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + CCStr->AddPlaceholderChunk(PlaceholderStr); } if (const FunctionProtoType *Proto @@ -778,7 +767,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Add the placeholder string. - CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); + CCStr->AddPlaceholderChunk(PlaceholderStr); } } @@ -797,9 +786,9 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, Qualifier->print(OS, Context.PrintingPolicy); } if (QualifierIsInformative) - Result->AddInformativeChunk(PrintedNNS.c_str()); + Result->AddInformativeChunk(PrintedNNS); else - Result->AddTextChunk(PrintedNNS.c_str()); + Result->AddTextChunk(PrintedNNS); } /// \brief If possible, create a new code completion string for the given @@ -812,17 +801,26 @@ CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { typedef CodeCompletionString::Chunk Chunk; - if (Kind == RK_Keyword) - return 0; + if (Kind == RK_Pattern) + return Pattern->Clone(); + + CodeCompletionString *Result = new CodeCompletionString; + + if (Kind == RK_Keyword) { + Result->AddTypedTextChunk(Keyword); + return Result; + } if (Kind == RK_Macro) { MacroInfo *MI = S.PP.getMacroInfo(Macro); - if (!MI || !MI->isFunctionLike()) - return 0; + assert(MI && "Not a macro?"); + + Result->AddTypedTextChunk(Macro->getName()); + + if (!MI->isFunctionLike()) + return Result; // Format a function-like macro with placeholders for the arguments. - CodeCompletionString *Result = new CodeCompletionString; - Result->AddTypedTextChunk(Macro->getName().str().c_str()); Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); A != AEnd; ++A) { @@ -831,7 +829,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (!MI->isVariadic() || A != AEnd - 1) { // Non-variadic argument. - Result->AddPlaceholderChunk((*A)->getName().str().c_str()); + Result->AddPlaceholderChunk((*A)->getName()); continue; } @@ -843,7 +841,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { else { std::string Arg = (*A)->getName(); Arg += "..."; - Result->AddPlaceholderChunk(Arg.c_str()); + Result->AddPlaceholderChunk(Arg); } } Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); @@ -854,17 +852,15 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { NamedDecl *ND = Declaration; if (StartsNestedNameSpecifier) { - CodeCompletionString *Result = new CodeCompletionString; - Result->AddTypedTextChunk(ND->getNameAsString().c_str()); + Result->AddTypedTextChunk(ND->getNameAsString()); Result->AddTextChunk("::"); return Result; } if (FunctionDecl *Function = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(Function->getNameAsString().c_str()); + Result->AddTypedTextChunk(Function->getNameAsString()); Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); @@ -872,11 +868,10 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { } if (FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - Result->AddTypedTextChunk(Function->getNameAsString().c_str()); + Result->AddTypedTextChunk(Function->getNameAsString()); // Figure out which template parameters are deduced (or have default // arguments). @@ -926,10 +921,9 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { } if (TemplateDecl *Template = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(Template->getNameAsString().c_str()); + Result->AddTypedTextChunk(Template->getNameAsString()); Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, Template, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); @@ -937,7 +931,6 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { } if (ObjCMethodDecl *Method = dyn_cast(ND)) { - CodeCompletionString *Result = new CodeCompletionString; Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); @@ -993,15 +986,12 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { return Result; } - if (Qualifier) { - CodeCompletionString *Result = new CodeCompletionString; + if (Qualifier) AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTypedTextChunk(ND->getNameAsString().c_str()); - return Result; - } - - return 0; + + Result->AddTypedTextChunk(ND->getNameAsString()); + return Result; } CodeCompletionString * @@ -1019,7 +1009,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // highlighted ellipsis. const FunctionType *FT = getFunctionType(); Result->AddTextChunk( - FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); + FT->getResultType().getAsString(S.Context.PrintingPolicy)); Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); @@ -1027,10 +1017,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( } if (FDecl) - Result->AddTextChunk(FDecl->getNameAsString().c_str()); + Result->AddTextChunk(FDecl->getNameAsString()); else Result->AddTextChunk( - Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); + Proto->getResultType().getAsString(S.Context.PrintingPolicy)); Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); @@ -1052,9 +1042,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( if (I == CurrentArg) Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, - ArgString.c_str())); + ArgString)); else - Result->AddTextChunk(ArgString.c_str()); + Result->AddTextChunk(ArgString); } if (Proto && Proto->isVariadic()) { @@ -1467,19 +1457,18 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, Expr::hasAnyTypeDependentArguments(Args, NumArgs)) return; - NamedDecl *Function; + llvm::SmallVector Fns; DeclarationName UnqualifiedName; NestedNameSpecifier *Qualifier; SourceRange QualifierRange; bool ArgumentDependentLookup; + bool Overloaded; bool HasExplicitTemplateArgs; - const TemplateArgumentLoc *ExplicitTemplateArgs; - unsigned NumExplicitTemplateArgs; + TemplateArgumentListInfo ExplicitTemplateArgs; - DeconstructCallFunction(Fn, - Function, UnqualifiedName, Qualifier, QualifierRange, - ArgumentDependentLookup, HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs); + DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange, + ArgumentDependentLookup, Overloaded, + HasExplicitTemplateArgs, ExplicitTemplateArgs); // FIXME: What if we're calling something that isn't a function declaration? @@ -1488,9 +1477,9 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // Build an overload candidate set based on the functions we find. OverloadCandidateSet CandidateSet; - AddOverloadedCallCandidates(Function, UnqualifiedName, - ArgumentDependentLookup, HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs, + AddOverloadedCallCandidates(Fns, UnqualifiedName, + ArgumentDependentLookup, + (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), Args, NumArgs, CandidateSet, /*PartialOverloading=*/true); @@ -1968,8 +1957,10 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, if (!CDecl && FName->isStr("super")) { // "super" may be the name of a variable, in which case we are // probably calling an instance method. - OwningExprResult Super = ActOnDeclarationNameExpr(S, FNameLoc, FName, - false, 0, false); + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(FName, FNameLoc); + OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false); return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), SelIdents, NumSelIdents); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b5109f8..520d7de 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -66,31 +66,68 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS, - bool isClassName) { - // C++ [temp.res]p3: - // A qualified-id that refers to a type and in which the - // nested-name-specifier depends on a template-parameter (14.6.2) - // shall be prefixed by the keyword typename to indicate that the - // qualified-id denotes a type, forming an - // elaborated-type-specifier (7.1.5.3). - // - // We therefore do not perform any name lookup if the result would - // refer to a member of an unknown specialization. - if (SS && isUnknownSpecialization(*SS)) { - if (!isClassName) + bool isClassName, + TypeTy *ObjectTypePtr) { + // Determine where we will perform name lookup. + DeclContext *LookupCtx = 0; + if (ObjectTypePtr) { + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + if (ObjectType->isRecordType()) + LookupCtx = computeDeclContext(ObjectType); + } else if (SS && SS->isSet()) { + LookupCtx = computeDeclContext(*SS, false); + + if (!LookupCtx) { + if (isDependentScopeSpecifier(*SS)) { + // C++ [temp.res]p3: + // A qualified-id that refers to a type and in which the + // nested-name-specifier depends on a template-parameter (14.6.2) + // shall be prefixed by the keyword typename to indicate that the + // qualified-id denotes a type, forming an + // elaborated-type-specifier (7.1.5.3). + // + // We therefore do not perform any name lookup if the result would + // refer to a member of an unknown specialization. + if (!isClassName) + return 0; + + // We know from the grammar that this name refers to a type, so build a + // TypenameType node to describe the type. + // FIXME: Record somewhere that this TypenameType node has no "typename" + // keyword associated with it. + return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), + II, SS->getRange()).getAsOpaquePtr(); + } + + return 0; + } + + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) return 0; - - // We know from the grammar that this name refers to a type, so build a - // TypenameType node to describe the type. - // FIXME: Record somewhere that this TypenameType node has no "typename" - // keyword associated with it. - return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), - II, SS->getRange()).getAsOpaquePtr(); } - + LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName); - LookupParsedName(Result, S, SS, false); - + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + LookupQualifiedName(Result, LookupCtx); + + if (ObjectTypePtr && Result.empty()) { + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T of + // the object expression is of a class type C, the type-name is also + // looked up in the scope of class C. At least one of the lookups shall + // find a name that refers to (possibly cv-qualified) T. + LookupName(Result, S); + } + } else { + // Perform unqualified name lookup. + LookupName(Result, S); + } + NamedDecl *IIDecl = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: @@ -364,37 +401,6 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { - if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { - // Look inside the overload set to determine if any of the declarations - // are in scope. (Possibly) build a new overload set containing only - // those declarations that are in scope. - OverloadedFunctionDecl *NewOvl = 0; - bool FoundInScope = false; - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - NamedDecl *FD = F->get(); - if (!isDeclInScope(FD, Ctx, S)) { - if (!NewOvl && F != Ovl->function_begin()) { - NewOvl = OverloadedFunctionDecl::Create(Context, - F->get()->getDeclContext(), - F->get()->getDeclName()); - D = NewOvl; - for (OverloadedFunctionDecl::function_iterator - First = Ovl->function_begin(); - First != F; ++First) - NewOvl->addOverload(*First); - } - } else { - FoundInScope = true; - if (NewOvl) - NewOvl->addOverload(*F); - } - } - - return FoundInScope; - } - return IdResolver.isDeclInScope(D, Ctx, Context, S); } @@ -644,7 +650,9 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { case 3: if (!TypeID->isStr("SEL")) break; - Context.setObjCSelType(Context.getTypeDeclType(New)); + Context.ObjCSelRedefinitionType = New->getUnderlyingType(); + // Install the built-in type for 'SEL', ignoring the current definition. + New->setTypeForDecl(Context.getObjCSelType().getTypePtr()); return; case 8: if (!TypeID->isStr("Protocol")) @@ -766,9 +774,6 @@ struct GNUCompatibleParamWarning { /// /// Returns true if there was an error, false otherwise. bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { - assert(!isa(OldD) && - "Cannot merge with an overloaded function declaration"); - // Verify the old decl was also a function. FunctionDecl *Old = 0; if (FunctionTemplateDecl *OldFunctionTemplate @@ -1718,22 +1723,26 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) { } /// \brief Retrieves the canonicalized name from a parsed unqualified-id. -DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { +DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: return DeclarationName(Name.Identifier); case UnqualifiedId::IK_OperatorFunctionId: return Context.DeclarationNames.getCXXOperatorName( - Name.OperatorFunctionId.Operator); - + Name.OperatorFunctionId.Operator); + + case UnqualifiedId::IK_LiteralOperatorId: + return Context.DeclarationNames.getCXXLiteralOperatorName( + Name.Identifier); + case UnqualifiedId::IK_ConversionFunctionId: { QualType Ty = GetTypeFromParser(Name.ConversionFunctionId); if (Ty.isNull()) return DeclarationName(); return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Ty)); + Context.getCanonicalType(Ty)); } case UnqualifiedId::IK_ConstructorName: { @@ -1742,7 +1751,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { return DeclarationName(); return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Ty)); + Context.getCanonicalType(Ty)); } case UnqualifiedId::IK_DestructorName: { @@ -2194,8 +2203,6 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, if (!PrevDecl) return 0; - // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which - // case we need to check each of the overloaded functions. if (!PrevDecl->hasLinkage()) return false; @@ -2364,8 +2371,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); - NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), - SE->getByteLength()))); + NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getString())); } // Don't consider existing declarations that are in a different @@ -2548,10 +2554,22 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *UserData) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); - + FindOverriddenMethodData *Data = reinterpret_cast(UserData); - for (Path.Decls = BaseRecord->lookup(Data->Method->getDeclName()); + + DeclarationName Name = Data->Method->getDeclName(); + + // FIXME: Do we care about other names here too? + if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // We really want to find the base class constructor here. + QualType T = Data->S->Context.getTypeDeclType(BaseRecord); + CanQualType CT = Data->S->Context.getCanonicalType(T); + + Name = Data->S->Context.DeclarationNames.getCXXDestructorName(CT); + } + + for (Path.Decls = BaseRecord->lookup(Name); Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { if (CXXMethodDecl *MD = dyn_cast(*Path.Decls.first)) { @@ -2576,7 +2594,8 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast(*I)) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && - !CheckOverridingFunctionExceptionSpec(MD, OldMD)) + !CheckOverridingFunctionExceptionSpec(MD, OldMD) && + !CheckOverridingFunctionAttributes(MD, OldMD)) MD->addOverriddenMethod(OldMD); } } @@ -2846,7 +2865,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setAccess(AS_public); } - if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) AddOverriddenMethods(cast(DC), NewMD); @@ -2869,8 +2887,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); - NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), - SE->getByteLength()))); + NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getString())); } // Copy the parameter declarations from the declarator D to the function @@ -2935,10 +2952,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector TemplateArgs; - SourceLocation LAngleLoc, RAngleLoc; + TemplateArgumentListInfo TemplateArgs; if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); @@ -2947,8 +2965,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TemplateArgsPtr.release(); HasExplicitTemplateArgs = true; - LAngleLoc = TemplateId->LAngleLoc; - RAngleLoc = TemplateId->RAngleLoc; if (FunctionTemplate) { // FIXME: Diagnose function template with explicit template @@ -2970,9 +2986,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs, - LAngleLoc, TemplateArgs.data(), - TemplateArgs.size(), RAngleLoc, + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa(NewFD) && @@ -2988,6 +3003,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + // If we have a function template, check the template parameter + // list. This will check and merge default template arguments. + if (FunctionTemplate) { + FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDeclaration(); + CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), + PrevTemplate? PrevTemplate->getTemplateParameters() : 0, + D.getDeclSpec().isFriendSpecified()? TPC_FriendFunctionTemplate + : TPC_FunctionTemplate); + } + if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c96ab46..b2124fe 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -177,9 +177,10 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, // Special case where the argument is a template id. if (Attr.getParameterName()) { - sizeExpr = S.ActOnDeclarationNameExpr(scope, Attr.getLoc(), - Attr.getParameterName(), - false, 0, false).takeAs(); + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(Attr.getParameterName(), Attr.getLoc()); + sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs(); } else { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -410,12 +411,9 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - const char *Alias = Str->getStrData(); - unsigned AliasLen = Str->getByteLength(); - // FIXME: check if target symbol exists in current file - d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen))); + d->addAttr(::new (S.Context) AliasAttr(Str->getString())); } static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, @@ -464,7 +462,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, if (!isFunctionOrMethod(d) && !isa(d)) { ValueDecl *VD = dyn_cast(d); if (VD == 0 || !VD->getType()->isBlockPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return false; } @@ -484,6 +484,15 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, d->addAttr(::new (S.Context) AnalyzerNoReturnAttr()); } +static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (!isFunctionOrMethod(d) && !isa(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << 8; /*function, method, or parameter*/ + return; + } + // FIXME: Actually store the attribute on the declaration +} + static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { @@ -994,12 +1003,10 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - std::string SectionStr(SE->getStrData(), SE->getByteLength()); - // If the target wants to validate the section specifier, make it happen. - std::string Error = S.Context.Target.isValidSectionSpecifier(SectionStr); + std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString()); if (Error.empty()) { - D->addAttr(::new (S.Context) SectionAttr(SectionStr)); + D->addAttr(::new (S.Context) SectionAttr(SE->getString())); return; } @@ -1506,8 +1513,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(), - SE->getByteLength()))); + d->addAttr(::new (S.Context) AnnotateAttr(SE->getString())); } static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1516,6 +1522,10 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } + + //FIXME: The C++0x version of this attribute has more limited applicabilty + // than GNU's, and should error out when it is used to specify a + // weaker alignment, rather than being silently ignored. unsigned Align = 0; if (Attr.getNumArgs() == 0) { @@ -1794,6 +1804,108 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue())); } +static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d) + && (!isa(d) || !cast(d)->isVirtual())) { + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 7 /*virtual method or class*/; + return; + } + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "final"; + return; + } + + d->addAttr(::new (S.Context) FinalAttr()); +} + +//===----------------------------------------------------------------------===// +// C++0x member checking attributes +//===----------------------------------------------------------------------===// + +static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d)) { + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 9 /*class*/; + return; + } + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "base_check"; + return; + } + + d->addAttr(::new (S.Context) BaseCheckAttr()); +} + +static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d->getDeclContext())) { + // FIXME: It's not the type that's the problem + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 11 /*member*/; + return; + } + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "hiding"; + return; + } + + d->addAttr(::new (S.Context) HidingAttr()); +} + +static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa(d) || !cast(d)->isVirtual()) { + // FIXME: It's not the type that's the problem + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 10 /*virtual method*/; + return; + } + + // FIXME: Conform to C++0x redeclaration rules. + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "override"; + return; + } + + d->addAttr(::new (S.Context) OverrideAttr()); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -1841,7 +1953,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just -/// silently ignore it. +/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to +/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) { if (Attr.isDeclspecAttribute()) @@ -1854,31 +1967,37 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; - case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; - case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; + case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; + case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; case AttributeList::AT_always_inline: HandleAlwaysInlineAttr (D, Attr, S); break; case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; - case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; - case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break; - case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break; - case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break; - case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break; - case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break; + case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break; + case AttributeList::AT_carries_dependency: + HandleDependencyAttr (D, Attr, S); break; + case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; + case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; + case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; + case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; + case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break; + case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break; case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; - case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; - case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; - case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; - case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break; - case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; - case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; - case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; - case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; + case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; + case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break; + case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; + case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; + case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; + case AttributeList::AT_hiding: HandleHidingAttr (D, Attr, S); break; + case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; + case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; + case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; + case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; + case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; + case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break; // Checker-specific. case AttributeList::AT_ns_returns_retained: @@ -1888,18 +2007,18 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_reqd_wg_size: HandleReqdWorkGroupSize(D, Attr, S); break; - case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; - case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; - case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; - case AttributeList::AT_unavailable: HandleUnavailableAttr(D, Attr, S); break; - case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; - case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; - case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break; - case AttributeList::AT_visibility: HandleVisibilityAttr(D, Attr, S); break; + case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; + case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; + case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; + case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; + case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; + case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; + case AttributeList::AT_vector_size: HandleVectorSizeAttr (D, Attr, S); break; + case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break; case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; - case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; - case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break; + case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; case AttributeList::AT_transparent_union: HandleTransparentUnionAttr(D, Attr, S); break; @@ -1907,15 +2026,15 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, HandleObjCExceptionAttr(D, Attr, S); break; case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; - case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; - case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; - case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; - case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; - case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; - case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; - case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; - case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; - case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; + case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; + case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; + case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; + case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; + case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; + case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; + case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; + case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; + case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; case AttributeList::IgnoredAttribute: case AttributeList::AT_no_instrument_function: // Interacts with -pg. // Just ignore diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bda1a69..f161cb5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -24,8 +24,6 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Compiler.h" -#include // for std::equal #include #include @@ -41,7 +39,7 @@ namespace { /// contains any ill-formed subexpressions. For example, this will /// diagnose the use of local variables or parameters within the /// default argument expression. - class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor + class CheckDefaultArgumentVisitor : public StmtVisitor { Expr *DefaultArg; Sema *S; @@ -354,9 +352,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { if (CheckEquivalentExceptionSpec( Old->getType()->getAs(), Old->getLocation(), - New->getType()->getAs(), New->getLocation())) { + New->getType()->getAs(), New->getLocation())) Invalid = true; - } return Invalid; } @@ -489,6 +486,13 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, Class->setEmpty(false); if (CXXBaseDecl->isPolymorphic()) Class->setPolymorphic(true); + // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. + if (CXXBaseDecl->hasAttr()) { + Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); + Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl) + << BaseType.getAsString(); + return 0; + } // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. @@ -783,7 +787,8 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { Sema::DeclPtrTy Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - ExprTy *BW, ExprTy *InitExpr, bool Deleted) { + ExprTy *BW, ExprTy *InitExpr, bool IsDefinition, + bool Deleted) { const DeclSpec &DS = D.getDeclSpec(); DeclarationName Name = GetNameForDeclarator(D); Expr *BitWidth = static_cast(BW); @@ -865,7 +870,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, AS); assert(Member && "HandleField never returns null"); } else { - Member = HandleDeclarator(S, D, move(TemplateParameterLists), false) + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition) .getAs(); if (!Member) { if (BitWidth) DeleteExpr(BitWidth); @@ -1708,7 +1713,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { namespace { /// PureVirtualMethodCollector - traverses a class and its superclasses /// and determines if it has any pure virtual methods. - class VISIBILITY_HIDDEN PureVirtualMethodCollector { + class PureVirtualMethodCollector { ASTContext &Context; public: @@ -1855,7 +1860,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, } namespace { - class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser + class AbstractClassUsageDiagnoser : public DeclVisitor { Sema &SemaRef; CXXRecordDecl *AbstractClass; @@ -2164,6 +2169,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); ClassDecl->addDecl(Destructor); + + AddOverriddenMethods(ClassDecl, Destructor); } } @@ -2360,9 +2367,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { ClassDecl->addedConstructor(Context, Constructor); } -/// CheckDestructor - Checks a fully-formed destructor for -/// well-formedness, issuing any diagnostics required. -void Sema::CheckDestructor(CXXDestructorDecl *Destructor) { +/// CheckDestructor - Checks a fully-formed destructor for well-formedness, +/// issuing any diagnostics required. Returns true on error. +bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) { CXXRecordDecl *RD = Destructor->getParent(); if (Destructor->isVirtual()) { @@ -2377,9 +2384,13 @@ void Sema::CheckDestructor(CXXDestructorDecl *Destructor) { FunctionDecl *OperatorDelete = 0; DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); - if (!FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) - Destructor->setOperatorDelete(OperatorDelete); + if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) + return true; + + Destructor->setOperatorDelete(OperatorDelete); } + + return false; } static inline bool @@ -2594,16 +2605,8 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration(); - OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Conv = Conversions->function_begin(), - ConvEnd = Conversions->function_end(); - Conv != ConvEnd; ++Conv) { - if (*Conv == ExpectedPrevDecl) { - *Conv = Conversion; - return DeclPtrTy::make(Conversion); - } - } + if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion)) + return DeclPtrTy::make(Conversion); assert(Conversion->isInvalidDecl() && "Conversion should not get here."); } else if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) @@ -2723,6 +2726,14 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, return DeclPtrTy::make(Namespc); } +/// getNamespaceDecl - Returns the namespace a decl represents. If the decl +/// is a namespace alias, returns the namespace it points to. +static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { + if (NamespaceAliasDecl *AD = dyn_cast_or_null(D)) + return AD->getNamespace(); + return dyn_cast_or_null(D); +} + /// ActOnFinishNamespaceDef - This callback is called after a namespace is /// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { @@ -2754,9 +2765,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, return DeclPtrTy(); if (!R.empty()) { - NamedDecl *NS = R.getFoundDecl(); - // FIXME: Namespace aliases! - assert(isa(NS) && "expected namespace decl"); + NamedDecl *Named = R.getFoundDecl(); + assert((isa(Named) || isa(Named)) + && "expected namespace decl"); // C++ [namespace.udir]p1: // A using-directive specifies that the names in the nominated // namespace can be used in the scope in which the @@ -2769,18 +2780,15 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, // Find enclosing context containing both using-directive and // nominated namespace. + NamespaceDecl *NS = getNamespaceDecl(Named); DeclContext *CommonAncestor = cast(NS); while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) CommonAncestor = CommonAncestor->getParent(); - UDir = UsingDirectiveDecl::Create(Context, - CurContext, UsingLoc, - NamespcLoc, + UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc, SS.getRange(), (NestedNameSpecifier *)SS.getScopeRep(), - IdentLoc, - cast(NS), - CommonAncestor); + IdentLoc, Named, CommonAncestor); PushUsingDirective(S, UDir); } else { Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); @@ -2817,6 +2825,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_ConversionFunctionId: break; @@ -3007,14 +3016,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } -/// getNamespaceDecl - Returns the namespace a decl represents. If the decl -/// is a namespace alias, returns the namespace it points to. -static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { - if (NamespaceAliasDecl *AD = dyn_cast_or_null(D)) - return AD->getNamespace(); - return dyn_cast_or_null(D); -} - Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, @@ -3074,8 +3075,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) { - Diag(CurrentLocation, diag::note_ctor_synthesized_at) - << Context.getTagDeclType(ClassDecl); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); @@ -3127,6 +3128,17 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } } + + // FIXME: If CheckDestructor fails, we should emit a note about where the + // implicit destructor was needed. + if (CheckDestructor(Destructor)) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXDestructor << Context.getTagDeclType(ClassDecl); + + Destructor->setInvalidDecl(); + return; + } + Destructor->setUsed(); } @@ -3292,6 +3304,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); + MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, Constructor, Elidable, Exprs, NumExprs)); } @@ -3305,6 +3318,7 @@ Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor, unsigned NumExprs = Args.size(); Expr **Exprs = (Expr **)Args.release(); + MarkDeclarationReferenced(TyBeginLoc, Constructor); return Owned(new (Context) CXXTemporaryObjectExpr(Context, Constructor, Ty, TyBeginLoc, Exprs, NumExprs, RParenLoc)); @@ -3490,7 +3504,8 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, + SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, + /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); @@ -3612,10 +3627,13 @@ Sema::PerformInitializationByConstructor(QualType ClassType, Diag(Loc, diag::err_ovl_deleted_init) << Best->Function->isDeleted() << InitEntity << Range; - else + else { + const CXXRecordDecl *RD = + cast(ClassType->getAs()->getDecl()); Diag(Loc, diag::err_ovl_deleted_init) << Best->Function->isDeleted() - << InitEntity << Range; + << RD->getDeclName() << Range; + } PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); return 0; } @@ -3646,58 +3664,22 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, = Constructor->getType()->getAs(); assert(Proto && "Constructor without a prototype?"); unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned NumArgsToCheck = NumArgs; // If too few arguments are available, we'll fill in the rest with defaults. - if (NumArgs < NumArgsInProto) { - NumArgsToCheck = NumArgsInProto; + if (NumArgs < NumArgsInProto) ConvertedArgs.reserve(NumArgsInProto); - } else { + else ConvertedArgs.reserve(NumArgs); - if (NumArgs > NumArgsInProto) - NumArgsToCheck = NumArgsInProto; - } - - // Convert arguments - for (unsigned i = 0; i != NumArgsToCheck; i++) { - QualType ProtoArgType = Proto->getArgType(i); - - Expr *Arg; - if (i < NumArgs) { - Arg = Args[i]; - - // Pass the argument. - if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) - return true; - - Args[i] = 0; - } else { - ParmVarDecl *Param = Constructor->getParamDecl(i); - - OwningExprResult DefArg = BuildCXXDefaultArgExpr(Loc, Constructor, Param); - if (DefArg.isInvalid()) - return true; - - Arg = DefArg.takeAs(); - } - - ConvertedArgs.push_back(Arg); - } - - // If this is a variadic call, handle args passed through "...". - if (Proto->isVariadic()) { - // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = NumArgsInProto; i != NumArgs; i++) { - Expr *Arg = Args[i]; - if (DefaultVariadicArgumentPromotion(Arg, VariadicConstructor)) - return true; - - ConvertedArgs.push_back(Arg); - Args[i] = 0; - } - } - - return false; + + VariadicCallType CallType = + Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; + llvm::SmallVector AllArgs; + bool Invalid = GatherArgumentsForCall(Loc, Constructor, + Proto, 0, Args, NumArgs, AllArgs, + CallType); + for (unsigned i =0, size = AllArgs.size(); i < size; i++) + ConvertedArgs.push_back(AllArgs[i]); + return Invalid; } /// CompareReferenceRelationship - Compare the two types T1 and T2 to @@ -3888,18 +3870,17 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = dyn_cast(T2->getAs()->getDecl()); OverloadCandidateSet CandidateSet; - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func - = Conversions->function_begin(); - Func != Conversions->function_end(); ++Func) { + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { FunctionTemplateDecl *ConvTemplate - = dyn_cast(*Func); + = dyn_cast(*I); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else - Conv = cast(*Func); + Conv = cast(*I); // If the conversion function doesn't return a reference type, // it can't be considered for this conversion. @@ -4896,6 +4877,19 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return false; } +bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, + const CXXMethodDecl *Old) +{ + if (Old->hasAttr()) { + Diag(New->getLocation(), diag::err_final_function_overridden) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; + } + + return false; +} + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a @@ -4942,3 +4936,39 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { assert(S->getEntity() == D->getDeclContext() && "Context imbalance!"); ExitDeclaratorContext(S); } + +/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a +/// C++ if/switch/while/for statement. +/// e.g: "if (int x = f()) {...}" +Action::DeclResult +Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { + // C++ 6.4p2: + // The declarator shall not specify a function or an array. + // The type-specifier-seq shall not contain typedef and shall not declare a + // new class or enumeration. + assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class of condition decl."); + + DeclaratorInfo *DInfo = 0; + TagDecl *OwnedTag = 0; + QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); + + if (Ty->isFunctionType()) { // The declarator shall not specify a function... + // We exit without creating a CXXConditionDeclExpr because a FunctionDecl + // would be created and CXXConditionDeclExpr wants a VarDecl. + Diag(D.getIdentifierLoc(), diag::err_invalid_use_of_function_type) + << D.getSourceRange(); + return DeclResult(); + } else if (OwnedTag && OwnedTag->isDefinition()) { + // The type-specifier-seq shall not declare a new class or enumeration. + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); + } + + DeclPtrTy Dcl = ActOnDeclarator(S, D); + if (!Dcl) + return DeclResult(); + + VarDecl *VD = cast(Dcl.getAs()); + VD->setDeclaredInCondition(true); + return Dcl; +} diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 4f08ffe..f653cf6 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -152,9 +152,10 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ++sentinel; } Expr *sentinelExpr = Args[sentinel]; - if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() || - !sentinelExpr->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull))) { + if (sentinelExpr && (!isa(sentinelExpr) && + (!sentinelExpr->getType()->isPointerType() || + !sentinelExpr->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)))) { Diag(Loc, diag::warn_missing_sentinel) << isMethod; Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; } @@ -415,7 +416,6 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, /// BuildDeclRefExpr - Build a DeclRefExpr. Sema::OwningExprResult Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, - bool TypeDependent, bool ValueDependent, const CXXScopeSpec *SS) { if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { Diag(Loc, @@ -443,8 +443,7 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, return Owned(DeclRefExpr::Create(Context, SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, SS? SS->getRange() : SourceRange(), - D, Loc, - Ty, TypeDependent, ValueDependent)); + D, Loc, Ty)); } /// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or @@ -616,204 +615,210 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return Owned(Result); } -Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, - UnqualifiedId &Name, - bool HasTrailingLParen, - bool IsAddressOfOperand) { - if (Name.getKind() == UnqualifiedId::IK_TemplateId) { - ASTTemplateArgsPtr TemplateArgsPtr(*this, - Name.TemplateId->getTemplateArgs(), - Name.TemplateId->NumArgs); - return ActOnTemplateIdExpr(SS, - TemplateTy::make(Name.TemplateId->Template), - Name.TemplateId->TemplateNameLoc, - Name.TemplateId->LAngleLoc, - TemplateArgsPtr, - Name.TemplateId->RAngleLoc); +/// Decomposes the given name into a DeclarationName, its location, and +/// possibly a list of template arguments. +/// +/// If this produces template arguments, it is permitted to call +/// DecomposeTemplateName. +/// +/// This actually loses a lot of source location information for +/// non-standard name kinds; we should consider preserving that in +/// some way. +static void DecomposeUnqualifiedId(Sema &SemaRef, + const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationName &Name, + SourceLocation &NameLoc, + const TemplateArgumentListInfo *&TemplateArgs) { + if (Id.getKind() == UnqualifiedId::IK_TemplateId) { + Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); + Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); + + ASTTemplateArgsPtr TemplateArgsPtr(SemaRef, + Id.TemplateId->getTemplateArgs(), + Id.TemplateId->NumArgs); + SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer); + TemplateArgsPtr.release(); + + TemplateName TName = + Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal(); + + Name = SemaRef.Context.getNameForTemplate(TName); + NameLoc = Id.TemplateId->TemplateNameLoc; + TemplateArgs = &Buffer; + } else { + Name = SemaRef.GetNameFromUnqualifiedId(Id); + NameLoc = Id.StartLocation; + TemplateArgs = 0; } - - // FIXME: We lose a bunch of source information by doing this. Later, - // we'll want to merge ActOnDeclarationNameExpr's logic into - // ActOnIdExpression. - return ActOnDeclarationNameExpr(S, - Name.StartLocation, - GetNameFromUnqualifiedId(Name), - HasTrailingLParen, - &SS, - IsAddressOfOperand); } -/// ActOnDeclarationNameExpr - The parser has read some kind of name -/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine -/// performs lookup on that name and returns an expression that refers -/// to that name. This routine isn't directly called from the parser, -/// because the parser doesn't know about DeclarationName. Rather, -/// this routine is called by ActOnIdExpression, which contains a -/// parsed UnqualifiedId. +/// Decompose the given template name into a list of lookup results. /// -/// HasTrailingLParen indicates whether this identifier is used in a -/// function call context. LookupCtx is only used for a C++ -/// qualified-id (foo::bar) to indicate the class or namespace that -/// the identifier must be a member of. -/// -/// isAddressOfOperand means that this expression is the direct operand -/// of an address-of operator. This matters because this is the only -/// situation where a qualified name referencing a non-static member may -/// appear outside a member function of this class. -Sema::OwningExprResult -Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, - DeclarationName Name, bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand) { - // Could be enum-constant, value decl, instance variable, etc. - if (SS && SS->isInvalid()) - return ExprError(); +/// The unqualified ID must name a non-dependent template, which can +/// be more easily tested by checking whether DecomposeUnqualifiedId +/// found template arguments. +static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) { + assert(Id.getKind() == UnqualifiedId::IK_TemplateId); + TemplateName TName = + Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal(); + + if (TemplateDecl *TD = TName.getAsTemplateDecl()) + R.addDecl(TD); + else if (OverloadedFunctionDecl *OD + = TName.getAsOverloadedFunctionDecl()) + for (OverloadIterator I(OD), E; I != E; ++I) + R.addDecl(*I); + + R.resolveKind(); +} - // C++ [temp.dep.expr]p3: - // An id-expression is type-dependent if it contains: - // -- a nested-name-specifier that contains a class-name that - // names a dependent type. - // FIXME: Member of the current instantiation. - if (SS && isDependentScopeSpecifier(*SS)) { - return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy, - Loc, SS->getRange(), - static_cast(SS->getScopeRep()), - isAddressOfOperand)); +static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual BaseRT = BaseT->getAs(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); + if (!BaseRecord->isDefinition() || + !IsFullyFormedScope(SemaRef, BaseRecord)) + return false; } - LookupResult Lookup(*this, Name, Loc, LookupOrdinaryName); - LookupParsedName(Lookup, S, SS, true); + return true; +} + +/// Determines whether we can lookup this id-expression now or whether +/// we have to wait until template instantiation is complete. +static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { + DeclContext *DC = SemaRef.computeDeclContext(SS, false); + + // If the qualifier scope isn't computable, it's definitely dependent. + if (!DC) return true; - if (Lookup.isAmbiguous()) + // If the qualifier scope doesn't name a record, we can always look into it. + if (!isa(DC)) return false; + + // We can't look into record types unless they're fully-formed. + if (!IsFullyFormedScope(SemaRef, cast(DC))) return true; + + // We can always look into fully-formed record types, but if we're + // in a dependent but not fully-formed context, we can't decide + // whether the qualifier names a base class. We shouldn't be trying + // to decide that yet anyway, but we are, so we need to delay that + // decision. + CXXRecordDecl *CurRecord; + if (CXXMethodDecl *CurMethod = dyn_cast(SemaRef.CurContext)) + CurRecord = cast(CurMethod->getParent()); + else + CurRecord = dyn_cast(SemaRef.CurContext); + + return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord); +} + +Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Id, + bool HasTrailingLParen, + bool isAddressOfOperand) { + assert(!(isAddressOfOperand && HasTrailingLParen) && + "cannot be direct & operand and have a trailing lparen"); + + if (SS.isInvalid()) return ExprError(); - NamedDecl *D = Lookup.getAsSingleDecl(Context); + TemplateArgumentListInfo TemplateArgsBuffer; + + // Decompose the UnqualifiedId into the following data. + DeclarationName Name; + SourceLocation NameLoc; + const TemplateArgumentListInfo *TemplateArgs; + DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, + Name, NameLoc, TemplateArgs); - // If this reference is in an Objective-C method, then ivar lookup happens as - // well. IdentifierInfo *II = Name.getAsIdentifierInfo(); - if (II && getCurMethodDecl()) { - // There are two cases to handle here. 1) scoped lookup could have failed, - // in which case we should look for an ivar. 2) scoped lookup could have - // found a decl, but that decl is outside the current instance method (i.e. - // a global variable). In these two cases, we do a lookup for an ivar with - // this name, if the lookup sucedes, we replace it our current decl. - if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) { - ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); - ObjCInterfaceDecl *ClassDeclared; - if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { - // Check if referencing a field with __attribute__((deprecated)). - if (DiagnoseUseOfDecl(IV, Loc)) - return ExprError(); - // If we're referencing an invalid decl, just return this as a silent - // error node. The error diagnostic was already emitted on the decl. - if (IV->isInvalidDecl()) - return ExprError(); + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // -- a nested-name-specifier that contains a class-name that + // names a dependent type. + // Determine whether this is a member of an unknown specialization; + // we need to handle these differently. + if (SS.isSet() && IsDependentIdExpression(*this, SS)) { + bool CheckForImplicitMember = !isAddressOfOperand; - bool IsClsMethod = getCurMethodDecl()->isClassMethod(); - // If a class method attemps to use a free standing ivar, this is - // an error. - if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod()) - return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method) - << IV->getDeclName()); - // If a class method uses a global variable, even if an ivar with - // same name exists, use the global. - if (!IsClsMethod) { - if (IV->getAccessControl() == ObjCIvarDecl::Private && - ClassDeclared != IFace) - Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName(); - // FIXME: This should use a new expr for a direct reference, don't - // turn this into Self->ivar, just return a BareIVarExpr or something. - IdentifierInfo &II = Context.Idents.get("self"); - UnqualifiedId SelfName; - SelfName.setIdentifier(&II, SourceLocation()); - CXXScopeSpec SelfScopeSpec; - OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, - SelfName, false, false); - MarkDeclarationReferenced(Loc, IV); - return Owned(new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, - SelfExpr.takeAs(), true, true)); - } - } - } else if (getCurMethodDecl()->isInstanceMethod()) { - // We should warn if a local variable hides an ivar. - ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); - ObjCInterfaceDecl *ClassDeclared; - if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { - if (IV->getAccessControl() != ObjCIvarDecl::Private || - IFace == ClassDeclared) - Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName(); - } - } - // Needed to implement property "super.method" notation. - if (D == 0 && II->isStr("super")) { - QualType T; + return ActOnDependentIdExpression(SS, Name, NameLoc, + CheckForImplicitMember, + TemplateArgs); + } - if (getCurMethodDecl()->isInstanceMethod()) - T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( - getCurMethodDecl()->getClassInterface())); - else - T = Context.getObjCClassType(); - return Owned(new (Context) ObjCSuperExpr(Loc, T)); + // Perform the required lookup. + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); + if (TemplateArgs) { + // Just re-use the lookup done by isTemplateName. + DecomposeTemplateName(R, Id); + } else { + LookupParsedName(R, S, &SS, true); + + // If this reference is in an Objective-C method, then we need to do + // some special Objective-C lookup, too. + if (!SS.isSet() && II && getCurMethodDecl()) { + OwningExprResult E(LookupInObjCMethod(R, S, II)); + if (E.isInvalid()) + return ExprError(); + + Expr *Ex = E.takeAs(); + if (Ex) return Owned(Ex); } } + if (R.isAmbiguous()) + return ExprError(); + // Determine whether this name might be a candidate for // argument-dependent lookup. - bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && - HasTrailingLParen; + bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); - if (ADL && D == 0) { - // We've seen something of the form - // - // identifier( - // - // and we did not find any entity by the name - // "identifier". However, this identifier is still subject to - // argument-dependent lookup, so keep track of the name. - return Owned(new (Context) UnresolvedFunctionNameExpr(Name, - Context.OverloadTy, - Loc)); - } - - if (D == 0) { + if (R.empty() && !ADL) { // Otherwise, this could be an implicitly declared function reference (legal - // in C90, extension in C99). - if (HasTrailingLParen && II && - !getLangOptions().CPlusPlus) // Not in C++. - D = ImplicitlyDefineFunction(Loc, *II, S); - else { - // If this name wasn't predeclared and if this is not a function call, - // diagnose the problem. - if (SS && !SS->isEmpty()) - return ExprError(Diag(Loc, diag::err_no_member) - << Name << computeDeclContext(*SS, false) - << SS->getRange()); + // in C90, extension in C99, forbidden in C++). + if (HasTrailingLParen && II && !getLangOptions().CPlusPlus) { + NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S); + if (D) R.addDecl(D); + } + + // If this name wasn't predeclared and if this is not a function + // call, diagnose the problem. + if (R.empty()) { + if (!SS.isEmpty()) + return ExprError(Diag(NameLoc, diag::err_no_member) + << Name << computeDeclContext(SS, false) + << SS.getRange()); else if (Name.getNameKind() == DeclarationName::CXXOperatorName || + Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || Name.getNameKind() == DeclarationName::CXXConversionFunctionName) - return ExprError(Diag(Loc, diag::err_undeclared_use) - << Name.getAsString()); + return ExprError(Diag(NameLoc, diag::err_undeclared_use) + << Name); else - return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name); + return ExprError(Diag(NameLoc, diag::err_undeclared_var_use) << Name); } } - if (VarDecl *Var = dyn_cast(D)) { + // This is guaranteed from this point on. + assert(!R.empty() || ADL); + + if (VarDecl *Var = R.getAsSingle()) { // Warn about constructs like: // if (void *X = foo()) { ... } else { X }. // In the else block, the pointer is always false. - // FIXME: In a template instantiation, we don't have scope - // information to check this property. if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; while (CheckS && CheckS->getControlParent()) { if (CheckS->isWithinElse() && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { - ExprError(Diag(Loc, diag::warn_value_always_zero) + ExprError(Diag(NameLoc, diag::warn_value_always_zero) << Var->getDeclName() << (Var->getType()->isPointerType()? 2 : Var->getType()->isBooleanType()? 1 : 0)); @@ -824,26 +829,174 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, CheckS = CheckS->getParent(); } } - } else if (FunctionDecl *Func = dyn_cast(D)) { + } else if (FunctionDecl *Func = R.getAsSingle()) { if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) { // C99 DR 316 says that, if a function type comes from a // function definition (without a prototype), that type is only // used for checking compatibility. Therefore, when referencing // the function, we pretend that we don't have the full function // type. - if (DiagnoseUseOfDecl(Func, Loc)) + if (DiagnoseUseOfDecl(Func, NameLoc)) return ExprError(); QualType T = Func->getType(); QualType NoProtoType = T; if (const FunctionProtoType *Proto = T->getAs()) NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType()); - return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS); + return BuildDeclRefExpr(Func, NoProtoType, NameLoc, &SS); + } + } + + // &SomeClass::foo is an abstract member reference, regardless of + // the nature of foo, but &SomeClass::foo(...) is not. If this is + // *not* an abstract member reference, and any of the results is a + // class member (which necessarily means they're all class members), + // then we make an implicit member reference instead. + // + // This check considers all the same information as the "needs ADL" + // check, but there's no simple logical relationship other than the + // fact that they can never be simultaneously true. We could + // calculate them both in one pass if that proves important for + // performance. + if (!ADL) { + bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); + + if (!isAbstractMemberPointer && !R.empty() && + isa((*R.begin())->getDeclContext())) { + return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs); } } - return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand); + if (TemplateArgs) + return BuildTemplateIdExpr(SS, R, ADL, *TemplateArgs); + + return BuildDeclarationNameExpr(SS, R, ADL); +} + +/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified +/// declaration name, generally during template instantiation. +/// There's a large number of things which don't need to be done along +/// this path. +Sema::OwningExprResult +Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc) { + DeclContext *DC; + if (!(DC = computeDeclContext(SS, false)) || + DC->isDependentContext() || + RequireCompleteDeclContext(SS)) + return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0); + + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); + LookupQualifiedName(R, DC); + + if (R.isAmbiguous()) + return ExprError(); + + if (R.empty()) { + Diag(NameLoc, diag::err_no_member) << Name << DC << SS.getRange(); + return ExprError(); + } + + return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); } + +/// LookupInObjCMethod - The parser has read a name in, and Sema has +/// detected that we're currently inside an ObjC method. Perform some +/// additional lookup. +/// +/// Ideally, most of this would be done by lookup, but there's +/// actually quite a lot of extra work involved. +/// +/// Returns a null sentinel to indicate trivial success. +Sema::OwningExprResult +Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, + IdentifierInfo *II) { + SourceLocation Loc = Lookup.getNameLoc(); + + // There are two cases to handle here. 1) scoped lookup could have failed, + // in which case we should look for an ivar. 2) scoped lookup could have + // found a decl, but that decl is outside the current instance method (i.e. + // a global variable). In these two cases, we do a lookup for an ivar with + // this name, if the lookup sucedes, we replace it our current decl. + + // If we're in a class method, we don't normally want to look for + // ivars. But if we don't find anything else, and there's an + // ivar, that's an error. + bool IsClassMethod = getCurMethodDecl()->isClassMethod(); + + bool LookForIvars; + if (Lookup.empty()) + LookForIvars = true; + else if (IsClassMethod) + LookForIvars = false; + else + LookForIvars = (Lookup.isSingleResult() && + Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); + + if (LookForIvars) { + ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { + // Diagnose using an ivar in a class method. + if (IsClassMethod) + return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method) + << IV->getDeclName()); + + // If we're referencing an invalid decl, just return this as a silent + // error node. The error diagnostic was already emitted on the decl. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check if referencing a field with __attribute__((deprecated)). + if (DiagnoseUseOfDecl(IV, Loc)) + return ExprError(); + + // Diagnose the use of an ivar outside of the declaring class. + if (IV->getAccessControl() == ObjCIvarDecl::Private && + ClassDeclared != IFace) + Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName(); + + // FIXME: This should use a new expr for a direct reference, don't + // turn this into Self->ivar, just return a BareIVarExpr or something. + IdentifierInfo &II = Context.Idents.get("self"); + UnqualifiedId SelfName; + SelfName.setIdentifier(&II, SourceLocation()); + CXXScopeSpec SelfScopeSpec; + OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, + SelfName, false, false); + MarkDeclarationReferenced(Loc, IV); + return Owned(new (Context) + ObjCIvarRefExpr(IV, IV->getType(), Loc, + SelfExpr.takeAs(), true, true)); + } + } else if (getCurMethodDecl()->isInstanceMethod()) { + // We should warn if a local variable hides an ivar. + ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { + if (IV->getAccessControl() != ObjCIvarDecl::Private || + IFace == ClassDeclared) + Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName(); + } + } + + // Needed to implement property "super.method" notation. + if (Lookup.empty() && II->isStr("super")) { + QualType T; + + if (getCurMethodDecl()->isInstanceMethod()) + T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( + getCurMethodDecl()->getClassInterface())); + else + T = Context.getObjCClassType(); + return Owned(new (Context) ObjCSuperExpr(Loc, T)); + } + + // Sentinel value saying that we didn't do anything special. + return Owned((Expr*) 0); +} + /// \brief Cast member's object to its own class if necessary. bool Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { @@ -874,114 +1027,224 @@ Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec *SS, NamedDecl *Member, - SourceLocation Loc, QualType Ty) { - if (SS && SS->isSet()) - return MemberExpr::Create(C, Base, isArrow, - (NestedNameSpecifier *)SS->getScopeRep(), - SS->getRange(), Member, Loc, - // FIXME: Explicit template argument lists - false, SourceLocation(), 0, 0, SourceLocation(), - Ty); - - return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty); + const CXXScopeSpec &SS, NamedDecl *Member, + SourceLocation Loc, QualType Ty, + const TemplateArgumentListInfo *TemplateArgs = 0) { + NestedNameSpecifier *Qualifier = 0; + SourceRange QualifierRange; + if (SS.isSet()) { + Qualifier = (NestedNameSpecifier *) SS.getScopeRep(); + QualifierRange = SS.getRange(); + } + + return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, + Member, Loc, TemplateArgs, Ty); } -/// \brief Complete semantic analysis for a reference to the given declaration. -Sema::OwningExprResult -Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand) { - assert(D && "Cannot refer to a NULL declaration"); - DeclarationName Name = D->getDeclName(); +/// Return true if all the decls in the given result are instance +/// methods. +static bool IsOnlyInstanceMethods(const LookupResult &R) { + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + + CXXMethodDecl *Method; + if (isa(D)) + Method = cast(cast(D) + ->getTemplatedDecl()); + else if (isa(D)) + Method = cast(D); + else + return false; - // If this is an expression of the form &Class::member, don't build an - // implicit member ref, because we want a pointer to the member in general, - // not any specific instance's member. - if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) { - DeclContext *DC = computeDeclContext(*SS); - if (D && isa(DC)) { - QualType DType; - if (FieldDecl *FD = dyn_cast(D)) { - DType = FD->getType().getNonReferenceType(); - } else if (CXXMethodDecl *Method = dyn_cast(D)) { - DType = Method->getType(); - } else if (isa(D)) { - DType = Context.OverloadTy; - } - // Could be an inner type. That's diagnosed below, so ignore it here. - if (!DType.isNull()) { - // The pointer is type- and value-dependent if it points into something - // dependent. - bool Dependent = DC->isDependentContext(); - return BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS); - } - } + if (Method->isStatic()) + return false; } + return true; +} + +/// Builds an implicit member access expression from the given +/// unqualified lookup set, which is known to contain only class +/// members. +Sema::OwningExprResult +Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { + assert(!R.empty() && !R.isAmbiguous()); + + SourceLocation Loc = R.getNameLoc(); + // We may have found a field within an anonymous union or struct // (C++ [class.union]). // FIXME: This needs to happen post-isImplicitMemberReference? - if (FieldDecl *FD = dyn_cast(D)) + // FIXME: template-ids inside anonymous structs? + if (FieldDecl *FD = R.getAsSingle()) if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - // Cope with an implicit member access in a C++ non-static member function. - QualType ThisType, MemberType; - if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) { + QualType ThisType; + if (isImplicitMemberReference(R, ThisType)) { Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - MarkDeclarationReferenced(Loc, D); - if (PerformObjectMemberConversion(This, D)) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast(D)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && (!SS || !SS->isSet())) - ShouldCheckUse = false; - } - - if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) - return ExprError(); - return Owned(BuildMemberExpr(Context, This, true, SS, D, - Loc, MemberType)); + return BuildMemberReferenceExpr(ExprArg(*this, This), + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } - if (FieldDecl *FD = dyn_cast(D)) { + // Diagnose now if none of the available methods are static. + if (IsOnlyInstanceMethods(R)) + return ExprError(Diag(Loc, diag::err_member_call_without_object)); + + if (R.getAsSingle()) { if (CXXMethodDecl *MD = dyn_cast(CurContext)) { - if (MD->isStatic()) + if (MD->isStatic()) { // "invalid use of member 'x' in static member function" - return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) - << FD->getDeclName()); + Diag(Loc, diag::err_invalid_member_use_in_static_method) + << R.getLookupName(); + return ExprError(); + } } // Any other ways we could have found the field in a well-formed // program would have been turned into implicit member expressions // above. - return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) - << FD->getDeclName()); - } - - if (isa(D)) - return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name); - if (isa(D)) - return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name); - if (isa(D)) - return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name); - - // Make the DeclRefExpr or BlockDeclRefExpr for the decl. - if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) - return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc, - false, false, SS); - else if (TemplateDecl *Template = dyn_cast(D)) - return BuildDeclRefExpr(Template, Context.OverloadTy, Loc, - false, false, SS); - else if (UnresolvedUsingValueDecl *UD = dyn_cast(D)) - return BuildDeclRefExpr(UD, Context.DependentTy, Loc, - /*TypeDependent=*/true, - /*ValueDependent=*/true, SS); + Diag(Loc, diag::err_invalid_non_static_member_use) + << R.getLookupName(); + return ExprError(); + } + + // We're not in an implicit member-reference context, but the lookup + // results might not require an instance. Try to build a non-member + // decl reference. + if (TemplateArgs) + return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs); + + return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); +} + +bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, + const LookupResult &R, + bool HasTrailingLParen) { + // Only when used directly as the postfix-expression of a call. + if (!HasTrailingLParen) + return false; + + // Never if a scope specifier was provided. + if (SS.isSet()) + return false; + + // Only in C++ or ObjC++. + if (!getLangOptions().CPlusPlus) + return false; + + // Turn off ADL when we find certain kinds of declarations during + // normal lookup: + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = *I; + + // C++0x [basic.lookup.argdep]p3: + // -- a declaration of a class member + // Since using decls preserve this property, we check this on the + // original decl. + if (D->getDeclContext()->isRecord()) + return false; + + // C++0x [basic.lookup.argdep]p3: + // -- a block-scope function declaration that is not a + // using-declaration + // NOTE: we also trigger this for function templates (in fact, we + // don't check the decl type at all, since all other decl types + // turn off ADL anyway). + if (isa(D)) + D = cast(D)->getTargetDecl(); + else if (D->getDeclContext()->isFunctionOrMethod()) + return false; + + // C++0x [basic.lookup.argdep]p3: + // -- a declaration that is neither a function or a function + // template + // And also for builtin functions. + if (isa(D)) { + FunctionDecl *FDecl = cast(D); + + // But also builtin functions. + if (FDecl->getBuiltinID() && FDecl->isImplicit()) + return false; + } else if (!isa(D)) + return false; + } + + return true; +} + + +/// Diagnoses obvious problems with the use of the given declaration +/// as an expression. This is only actually called for lookups that +/// were not overloaded, and it doesn't promise that the declaration +/// will in fact be used. +static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { + if (isa(D)) { + S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName(); + return true; + } + + if (isa(D)) { + S.Diag(Loc, diag::err_unexpected_interface) << D->getDeclName(); + return true; + } + + if (isa(D)) { + S.Diag(Loc, diag::err_unexpected_namespace) << D->getDeclName(); + return true; + } + + return false; +} + +Sema::OwningExprResult +Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool NeedsADL) { + assert(R.getResultKind() != LookupResult::FoundUnresolvedValue); + + // If this isn't an overloaded result and we don't need ADL, just + // build an ordinary singleton decl ref. + if (!NeedsADL && !R.isOverloadedResult()) + return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl()); + + // We only need to check the declaration if there's exactly one + // result, because in the overloaded case the results can only be + // functions and function templates. + if (R.isSingleResult() && + CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) + return ExprError(); + + bool Dependent + = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0); + UnresolvedLookupExpr *ULE + = UnresolvedLookupExpr::Create(Context, Dependent, + (NestedNameSpecifier*) SS.getScopeRep(), + SS.getRange(), + R.getLookupName(), R.getNameLoc(), + NeedsADL, R.isOverloadedResult()); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + ULE->addDecl(*I); + + return Owned(ULE); +} + + +/// \brief Complete semantic analysis for a reference to the given declaration. +Sema::OwningExprResult +Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, + SourceLocation Loc, NamedDecl *D) { + assert(D && "Cannot refer to a NULL declaration"); + assert(!isa(D) && + "Cannot refer unambiguously to a function template"); + DeclarationName Name = D->getDeclName(); + + if (CheckDeclInExpr(*this, Loc, D)) + return ExprError(); ValueDecl *VD = cast(D); @@ -989,9 +1252,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // this check when we're going to perform argument-dependent lookup // on this function name, because this might not be the function // that overload resolution actually selects. - bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && - HasTrailingLParen; - if (!(ADL && isa(VD)) && DiagnoseUseOfDecl(VD, Loc)) + if (DiagnoseUseOfDecl(VD, Loc)) return ExprError(); // Only create DeclRefExpr's for valid Decl's. @@ -1023,57 +1284,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // If this reference is not in a block or if the referenced variable is // within the block, create a normal DeclRefExpr. - bool TypeDependent = false; - bool ValueDependent = false; - if (getLangOptions().CPlusPlus) { - // C++ [temp.dep.expr]p3: - // An id-expression is type-dependent if it contains: - // - an identifier that was declared with a dependent type, - if (VD->getType()->isDependentType()) - TypeDependent = true; - // - FIXME: a template-id that is dependent, - // - a conversion-function-id that specifies a dependent type, - else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && - Name.getCXXNameType()->isDependentType()) - TypeDependent = true; - // - a nested-name-specifier that contains a class-name that - // names a dependent type. - else if (SS && !SS->isEmpty()) { - for (DeclContext *DC = computeDeclContext(*SS); - DC; DC = DC->getParent()) { - // FIXME: could stop early at namespace scope. - if (DC->isRecord()) { - CXXRecordDecl *Record = cast(DC); - if (Context.getTypeDeclType(Record)->isDependentType()) { - TypeDependent = true; - break; - } - } - } - } - - // C++ [temp.dep.constexpr]p2: - // - // An identifier is value-dependent if it is: - // - a name declared with a dependent type, - if (TypeDependent) - ValueDependent = true; - // - the name of a non-type template parameter, - else if (isa(VD)) - ValueDependent = true; - // - a constant with integral or enumeration type and is - // initialized with an expression that is value-dependent - else if (const VarDecl *Dcl = dyn_cast(VD)) { - if (Context.getCanonicalType(Dcl->getType()).getCVRQualifiers() - == Qualifiers::Const && - Dcl->getInit()) { - ValueDependent = Dcl->getInit()->isValueDependent(); - } - } - } - - return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, - TypeDependent, ValueDependent, SS); + return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, &SS); } Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, @@ -1281,6 +1492,13 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, if (exprType->isDependentType()) return false; + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = exprType->getAs()) + exprType = Ref->getPointeeType(); + // C99 6.5.3.4p1: if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. @@ -1733,33 +1951,318 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, return GDecl; } -Action::OwningExprResult -Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, SourceLocation MemberLoc, - DeclarationName MemberName, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, - DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS, - NamedDecl *FirstQualifierInScope) { - if (SS && SS->isInvalid()) +Sema::OwningExprResult +Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs) { + Expr *BaseExpr = Base.takeAs(); + + // Even in dependent contexts, try to diagnose base expressions with + // obviously wrong types, e.g.: + // + // T* t; + // t.f; + // + // In Obj-C++, however, the above expression is valid, since it could be + // accessing the 'f' property if T is an Obj-C interface. The extra check + // allows this, while still reporting an error if T is a struct pointer. + if (!IsArrow) { + const PointerType *PT = BaseExpr->getType()->getAs(); + if (PT && (!getLangOptions().ObjC1 || + PT->getPointeeType()->isRecordType())) { + Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) + << BaseExpr->getType() << BaseExpr->getSourceRange(); + return ExprError(); + } + } + + assert(BaseExpr->getType()->isDependentType()); + + // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr + // must have pointer type, and the accessed type is the pointee. + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, + IsArrow, OpLoc, + static_cast(SS.getScopeRep()), + SS.getRange(), + FirstQualifierInScope, + Name, NameLoc, + TemplateArgs)); +} + +/// We know that the given qualified member reference points only to +/// declarations which do not belong to the static type of the base +/// expression. Diagnose the problem. +static void DiagnoseQualifiedMemberReference(Sema &SemaRef, + Expr *BaseExpr, + QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R) { + DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); + + // FIXME: this is an exceedingly lame diagnostic for some of the more + // complicated cases here. + SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) + << QualifierRange << DC << BaseType; +} + +// Check whether the declarations we found through a nested-name +// specifier in a member expression are actually members of the base +// type. The restriction here is: +// +// C++ [expr.ref]p2: +// ... In these cases, the id-expression shall name a +// member of the class or of one of its base classes. +// +// So it's perfectly legitimate for the nested-name specifier to name +// an unrelated class, and for us to find an overload set including +// decls from classes which are not superclasses, as long as the decl +// we actually pick through overload resolution is from a superclass. +bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, + QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R) { + QualType BaseTypeCanon + = Context.getCanonicalType(BaseType).getUnqualifiedType(); + + bool FoundValid = false; + + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + TypeDecl* TyD = cast((*I)->getUnderlyingDecl()->getDeclContext()); + CanQualType MemberTypeCanon + = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + + if (BaseTypeCanon == MemberTypeCanon || + IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) { + FoundValid = true; + break; + } + } + + if (!FoundValid) { + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, + Qualifier, QualifierRange, R); + return true; + } + + return false; +} + +Sema::OwningExprResult +Sema::BuildMemberReferenceExpr(ExprArg BaseArg, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs) { + Expr *Base = BaseArg.takeAs(); + + if (Base->getType()->isDependentType()) + return ActOnDependentMemberExpr(ExprArg(*this, Base), + IsArrow, OpLoc, + SS, FirstQualifierInScope, + Name, NameLoc, + TemplateArgs); + + LookupResult R(*this, Name, NameLoc, LookupMemberName); + OwningExprResult Result = + LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + /*ObjCImpDecl*/ DeclPtrTy()); + + if (Result.isInvalid()) { + Owned(Base); return ExprError(); + } - // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + if (Result.get()) + return move(Result); + + return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, + IsArrow, SS, R, TemplateArgs); +} +Sema::OwningExprResult +Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, + bool IsArrow, const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs(); + QualType BaseType = BaseExpr->getType(); + if (IsArrow) { + assert(BaseType->isPointerType()); + BaseType = BaseType->getAs()->getPointeeType(); + } + + NestedNameSpecifier *Qualifier = + static_cast(SS.getScopeRep()); + DeclarationName MemberName = R.getLookupName(); + SourceLocation MemberLoc = R.getNameLoc(); + + if (R.isAmbiguous()) + return ExprError(); + + if (R.empty()) { + // Rederive where we looked up. + DeclContext *DC = (SS.isSet() + ? computeDeclContext(SS, false) + : BaseType->getAs()->getDecl()); + + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC << BaseExpr->getSourceRange(); + return ExprError(); + } + + // We can't always diagnose the problem yet: it's permitted for + // lookup to find things from an invalid context as long as they + // don't get picked by overload resolution. + if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, + Qualifier, SS.getRange(), R)) + return ExprError(); + + // Construct an unresolved result if we in fact got an unresolved + // result. + if (R.isOverloadedResult() || R.isUnresolvableResult()) { + bool Dependent = R.isUnresolvableResult(); + Dependent = Dependent || + UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), + TemplateArgs); + + UnresolvedMemberExpr *MemExpr + = UnresolvedMemberExpr::Create(Context, Dependent, + R.isUnresolvableResult(), + BaseExpr, IsArrow, OpLoc, + Qualifier, SS.getRange(), + MemberName, MemberLoc, + TemplateArgs); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + MemExpr->addDecl(*I); + + return Owned(MemExpr); + } + + assert(R.isSingleResult()); + NamedDecl *MemberDecl = R.getFoundDecl(); + + // FIXME: diagnose the presence of template arguments now. + + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (MemberDecl->isInvalidDecl()) + return ExprError(); + + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && !SS.isSet()) + ShouldCheckUse = false; + } + + // Check the use of this member. + if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) { + Owned(BaseExpr); + return ExprError(); + } + + if (FieldDecl *FD = dyn_cast(MemberDecl)) { + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) + return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + BaseExpr, OpLoc); + + // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] + QualType MemberType = FD->getType(); + if (const ReferenceType *Ref = MemberType->getAs()) + MemberType = Ref->getPointeeType(); + else { + Qualifiers BaseQuals = BaseType.getQualifiers(); + BaseQuals.removeObjCGCAttr(); + if (FD->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = Context.getCanonicalType(MemberType).getQualifiers(); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = Context.getQualifiedType(MemberType, Combined); + } + + MarkDeclarationReferenced(MemberLoc, FD); + if (PerformObjectMemberConversion(BaseExpr, FD)) + return ExprError(); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + FD, MemberLoc, MemberType)); + } + + if (VarDecl *Var = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, Var); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Var, MemberLoc, + Var->getType().getNonReferenceType())); + } + + if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + MemberFn, MemberLoc, + MemberFn->getType())); + } + + if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Enum, MemberLoc, Enum->getType())); + } + + Owned(BaseExpr); + + if (isa(MemberDecl)) + return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) + << MemberName << int(IsArrow)); + + // We found a declaration kind that we didn't expect. This is a + // generic error message that tells the user that she can't refer + // to this member with '.' or '->'. + return ExprError(Diag(MemberLoc, + diag::err_typecheck_member_reference_unknown) + << MemberName << int(IsArrow)); +} + +/// Look up the given member of the given non-type-dependent +/// expression. This can return in one of two ways: +/// * If it returns a sentinel null-but-valid result, the caller will +/// assume that lookup was performed and the results written into +/// the provided structure. It will take over from there. +/// * Otherwise, the returned expression will be produced in place of +/// an ordinary member expression. +/// +/// The ObjCImpDecl bit is a gross hack that will need to be properly +/// fixed for ObjC++. +Sema::OwningExprResult +Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); // Perform default conversions. DefaultFunctionArrayConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); + assert(!BaseType->isDependentType()); + + DeclarationName MemberName = R.getLookupName(); + SourceLocation MemberLoc = R.getNameLoc(); // If the user is trying to apply -> or . to a function pointer - // type, it's probably because the forgot parentheses to call that + // type, it's probably because they forgot parentheses to call that // function. Suggest the addition of those parentheses, build the // call, and continue on. if (const PointerType *Ptr = BaseType->getAs()) { @@ -1767,8 +2270,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, = Ptr->getPointeeType()->getAs()) { QualType ResultTy = Fun->getResultType(); if (Fun->getNumArgs() == 0 && - ((OpKind == tok::period && ResultTy->isRecordType()) || - (OpKind == tok::arrow && ResultTy->isPointerType() && + ((!IsArrow && ResultTy->isRecordType()) || + (IsArrow && ResultTy->isPointerType() && ResultTy->getAs()->getPointeeType() ->isRecordType()))) { SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); @@ -1777,10 +2280,10 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, << CodeModificationHint::CreateInsertion(Loc, "()"); OwningExprResult NewBase - = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc, + = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, MultiExprArg(*this, 0, 0), 0, Loc); if (NewBase.isInvalid()) - return move(NewBase); + return ExprError(); BaseExpr = NewBase.takeAs(); DefaultFunctionArrayConversion(BaseExpr); @@ -1799,10 +2302,22 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } } + + // If this is an Objective-C pseudo-builtin and a definition is provided then + // use that. + if (Context.isObjCSelType(BaseType)) { + // We have an 'SEL' type. Rather than fall through, we check if this + // is a reference to 'sel_id'. + if (BaseType != Context.ObjCSelRedefinitionType) { + BaseType = Context.ObjCSelRedefinitionType; + ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); + } + } + assert(!BaseType.isNull() && "no type for member expression"); // Handle properties on ObjC 'Class' types. - if (OpKind == tok::period && BaseType->isObjCClassType()) { + if (!IsArrow && BaseType->isObjCClassType()) { // Also must look for a getter name which uses property syntax. IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); @@ -1856,76 +2371,21 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseType = Context.ObjCClassRedefinitionType; ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } - - // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr - // must have pointer type, and the accessed type is the pointee. - if (OpKind == tok::arrow) { - if (BaseType->isDependentType()) { - NestedNameSpecifier *Qualifier = 0; - if (SS) { - Qualifier = static_cast(SS->getScopeRep()); - if (!FirstQualifierInScope) - FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); - } - return Owned(CXXUnresolvedMemberExpr::Create(Context, BaseExpr, true, - OpLoc, Qualifier, - SS? SS->getRange() : SourceRange(), - FirstQualifierInScope, - MemberName, - MemberLoc, - HasExplicitTemplateArgs, - LAngleLoc, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - RAngleLoc)); - } - else if (const PointerType *PT = BaseType->getAs()) + if (IsArrow) { + if (const PointerType *PT = BaseType->getAs()) BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr->getSourceRange()); - } else if (BaseType->isDependentType()) { - // Require that the base type isn't a pointer type - // (so we'll report an error for) - // T* t; - // t.f; - // - // In Obj-C++, however, the above expression is valid, since it could be - // accessing the 'f' property if T is an Obj-C interface. The extra check - // allows this, while still reporting an error if T is a struct pointer. - const PointerType *PT = BaseType->getAs(); - - if (!PT || (getLangOptions().ObjC1 && - !PT->getPointeeType()->isRecordType())) { - NestedNameSpecifier *Qualifier = 0; - if (SS) { - Qualifier = static_cast(SS->getScopeRep()); - if (!FirstQualifierInScope) - FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); - } - - return Owned(CXXUnresolvedMemberExpr::Create(Context, - BaseExpr, false, - OpLoc, - Qualifier, - SS? SS->getRange() : SourceRange(), - FirstQualifierInScope, - MemberName, - MemberLoc, - HasExplicitTemplateArgs, - LAngleLoc, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - RAngleLoc)); - } + else { + Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr->getSourceRange(); + return ExprError(); } + } - // Handle field access to simple records. This also handles access to fields - // of the ObjC 'id' struct. + // Handle field access to simple records. This also handles access + // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs()) { RecordDecl *RDecl = RTy->getDecl(); if (RequireCompleteType(OpLoc, BaseType, @@ -1934,155 +2394,25 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); DeclContext *DC = RDecl; - if (SS && SS->isSet()) { + if (SS.isSet()) { // If the member name was a qualified-id, look into the // nested-name-specifier. - DC = computeDeclContext(*SS, false); + DC = computeDeclContext(SS, false); if (!isa(DC)) { Diag(MemberLoc, diag::err_qualified_member_nonclass) - << DC << SS->getRange(); + << DC << SS.getRange(); return ExprError(); } // FIXME: If DC is not computable, we should build a - // CXXUnresolvedMemberExpr. + // CXXDependentScopeMemberExpr. assert(DC && "Cannot handle non-computable dependent contexts in lookup"); } // The record definition is complete, now make sure the member is valid. - LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName); - LookupQualifiedName(Result, DC); - - if (Result.empty()) - return ExprError(Diag(MemberLoc, diag::err_no_member) - << MemberName << DC << BaseExpr->getSourceRange()); - if (Result.isAmbiguous()) - return ExprError(); - - NamedDecl *MemberDecl = Result.getAsSingleDecl(Context); - - if (SS && SS->isSet()) { - TypeDecl* TyD = cast(MemberDecl->getDeclContext()); - QualType BaseTypeCanon - = Context.getCanonicalType(BaseType).getUnqualifiedType(); - QualType MemberTypeCanon - = Context.getCanonicalType(Context.getTypeDeclType(TyD)); - - if (BaseTypeCanon != MemberTypeCanon && - !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) - return ExprError(Diag(SS->getBeginLoc(), - diag::err_not_direct_base_or_virtual) - << MemberTypeCanon << BaseTypeCanon); - } - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (MemberDecl->isInvalidDecl()) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && (!SS || !SS->isSet())) - ShouldCheckUse = false; - } - - // Check the use of this field - if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) - return ExprError(); - - if (FieldDecl *FD = dyn_cast(MemberDecl)) { - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, - BaseExpr, OpLoc); - - // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = FD->getType(); - if (const ReferenceType *Ref = MemberType->getAs()) - MemberType = Ref->getPointeeType(); - else { - Qualifiers BaseQuals = BaseType.getQualifiers(); - BaseQuals.removeObjCGCAttr(); - if (FD->isMutable()) BaseQuals.removeConst(); - - Qualifiers MemberQuals - = Context.getCanonicalType(MemberType).getQualifiers(); - - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); - } - - MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, FD)) - return ExprError(); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - FD, MemberLoc, MemberType)); - } - - if (VarDecl *Var = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Var, MemberLoc, - Var->getType().getNonReferenceType())); - } - if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - MemberFn, MemberLoc, - MemberFn->getType())); - } - if (FunctionTemplateDecl *FunTmpl - = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - - if (HasExplicitTemplateArgs) - return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), - FunTmpl, MemberLoc, true, - LAngleLoc, ExplicitTemplateArgs, - NumExplicitTemplateArgs, RAngleLoc, - Context.OverloadTy)); - - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - FunTmpl, MemberLoc, - Context.OverloadTy)); - } - if (OverloadedFunctionDecl *Ovl - = dyn_cast(MemberDecl)) { - if (HasExplicitTemplateArgs) - return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), - Ovl, MemberLoc, true, - LAngleLoc, ExplicitTemplateArgs, - NumExplicitTemplateArgs, RAngleLoc, - Context.OverloadTy)); - - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Ovl, MemberLoc, Context.OverloadTy)); - } - if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Enum, MemberLoc, Enum->getType())); - } - if (isa(MemberDecl)) - return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) - << MemberName << int(OpKind == tok::arrow)); - - // We found a declaration kind that we didn't expect. This is a - // generic error message that tells the user that she can't refer - // to this member with '.' or '->'. - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_unknown) - << MemberName << int(OpKind == tok::arrow)); + LookupQualifiedName(R, DC); + return Owned((Expr*) 0); } // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring @@ -2118,18 +2448,17 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // FIXME: We've lost the precise spelling of the type by going through // DeclarationName. Can we do better? return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, - OpKind == tok::arrow, - OpLoc, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), + IsArrow, OpLoc, + (NestedNameSpecifier *) SS.getScopeRep(), + SS.getRange(), MemberName.getCXXNameType(), MemberLoc)); } // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. - if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) || - (OpKind == tok::period && BaseType->isObjCInterfaceType())) { + if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCInterfaceType())) { const ObjCObjectPointerType *OPT = BaseType->getAs(); const ObjCInterfaceType *IFaceT = OPT ? OPT->getInterfaceType() : BaseType->getAs(); @@ -2184,7 +2513,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), MemberLoc, BaseExpr, - OpKind == tok::arrow)); + IsArrow)); } return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) << IDecl->getDeclName() << MemberName @@ -2192,8 +2521,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } } // Handle properties on 'id' and qualified "id". - if (OpKind == tok::period && (BaseType->isObjCIdType() || - BaseType->isObjCQualifiedIdType())) { + if (!IsArrow && (BaseType->isObjCIdType() || + BaseType->isObjCQualifiedIdType())) { const ObjCObjectPointerType *QIdTy = BaseType->getAs(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); @@ -2226,8 +2555,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. const ObjCObjectPointerType *OPT; - if (OpKind == tok::period && - (OPT = BaseType->getAsObjCInterfacePointerType())) { + if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); @@ -2312,7 +2640,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } // Handle the following exceptional case (*Obj).isa. - if (OpKind == tok::period && + if (!IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, @@ -2334,75 +2662,105 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } -Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base, +static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef, + SourceLocation NameLoc, + Sema::ExprArg MemExpr) { + Expr *E = (Expr *) MemExpr.get(); + SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc); + SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return SemaRef.ActOnCallExpr(/*Scope*/ 0, + move(MemExpr), + /*LPLoc*/ ExpectedLParenLoc, + Sema::MultiExprArg(SemaRef, 0, 0), + /*CommaLocs*/ 0, + /*RPLoc*/ ExpectedLParenLoc); +} + +/// The main callback when the parser finds something like +/// expression . [nested-name-specifier] identifier +/// expression -> [nested-name-specifier] identifier +/// where 'identifier' encompasses a fairly broad spectrum of +/// possibilities, including destructor and operator references. +/// +/// \param OpKind either tok::arrow or tok::period +/// \param HasTrailingLParen whether the next token is '(', which +/// is used to diagnose mis-uses of special members that can +/// only be called +/// \param ObjCImpDecl the current ObjC @implementation decl; +/// this is an ugly hack around the fact that ObjC @implementations +/// aren't properly put in the context chain +Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, - UnqualifiedId &Member, + UnqualifiedId &Id, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen) { - if (Member.getKind() == UnqualifiedId::IK_TemplateId) { - TemplateName Template - = TemplateName::getFromVoidPointer(Member.TemplateId->Template); - - // FIXME: We're going to end up looking up the template based on its name, - // twice! - DeclarationName Name; - if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) - Name = ActualTemplate->getDeclName(); - else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) - Name = Ovl->getDeclName(); - else { - DependentTemplateName *DTN = Template.getAsDependentTemplateName(); - if (DTN->isIdentifier()) - Name = DTN->getIdentifier(); - else - Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator()); + if (SS.isSet() && SS.isInvalid()) + return ExprError(); + + TemplateArgumentListInfo TemplateArgsBuffer; + + // Decompose the name into its component parts. + DeclarationName Name; + SourceLocation NameLoc; + const TemplateArgumentListInfo *TemplateArgs; + DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, + Name, NameLoc, TemplateArgs); + + bool IsArrow = (OpKind == tok::arrow); + + NamedDecl *FirstQualifierInScope + = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, + static_cast(SS.getScopeRep()))); + + // This is a postfix expression, so get rid of ParenListExprs. + BaseArg = MaybeConvertParenListExprToParenExpr(S, move(BaseArg)); + + Expr *Base = BaseArg.takeAs(); + OwningExprResult Result(*this); + if (Base->getType()->isDependentType()) { + Result = ActOnDependentMemberExpr(ExprArg(*this, Base), + IsArrow, OpLoc, + SS, FirstQualifierInScope, + Name, NameLoc, + TemplateArgs); + } else { + LookupResult R(*this, Name, NameLoc, LookupMemberName); + if (TemplateArgs) { + // Re-use the lookup done for the template name. + DecomposeTemplateName(R, Id); + } else { + Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + ObjCImpDecl); + + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) { + // The only way a reference to a destructor can be used is to + // immediately call it, which falls into this case. If the + // next token is not a '(', produce a diagnostic and build the + // call now. + if (!HasTrailingLParen && + Id.getKind() == UnqualifiedId::IK_DestructorName) + return DiagnoseDtorReference(*this, NameLoc, move(Result)); + + return move(Result); + } } - - // Translate the parser's template argument list in our AST format. - ASTTemplateArgsPtr TemplateArgsPtr(*this, - Member.TemplateId->getTemplateArgs(), - Member.TemplateId->NumArgs); - - llvm::SmallVector TemplateArgs; - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); - TemplateArgsPtr.release(); - - // Do we have the save the actual template name? We might need it... - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, - Member.TemplateId->TemplateNameLoc, - Name, true, Member.TemplateId->LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - Member.TemplateId->RAngleLoc, DeclPtrTy(), - &SS); + + Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, + IsArrow, SS, R, TemplateArgs); } - - // FIXME: We lose a lot of source information by mapping directly to the - // DeclarationName. - OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, - Member.getSourceRange().getBegin(), - GetNameFromUnqualifiedId(Member), - ObjCImpDecl, &SS); - - if (Result.isInvalid() || HasTrailingLParen || - Member.getKind() != UnqualifiedId::IK_DestructorName) - return move(Result); - - // The only way a reference to a destructor can be used is to - // immediately call them. Since the next token is not a '(', produce a - // diagnostic and build the call now. - Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc - = PP.getLocForEndOfToken(Member.getSourceRange().getEnd()); - Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - - return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, - MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); + + return move(Result); } Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -2468,17 +2826,14 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned NumArgsToCheck = NumArgs; bool Invalid = false; - + // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); - // Use default arguments for missing arguments - NumArgsToCheck = NumArgsInProto; Call->setNumArgs(Context, NumArgsInProto); } @@ -2493,25 +2848,55 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, Args[NumArgs-1]->getLocEnd()); // This deletes the extra arguments. Call->setNumArgs(Context, NumArgsInProto); - Invalid = true; + return true; } - NumArgsToCheck = NumArgsInProto; } + llvm::SmallVector AllArgs; + VariadicCallType CallType = + Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; + if (Fn->getType()->isBlockPointerType()) + CallType = VariadicBlock; // Block + else if (isa(Fn)) + CallType = VariadicMethod; + Invalid = GatherArgumentsForCall(Call->getSourceRange().getBegin(), FDecl, + Proto, 0, Args, NumArgs, AllArgs, CallType); + if (Invalid) + return true; + unsigned TotalNumArgs = AllArgs.size(); + for (unsigned i = 0; i < TotalNumArgs; ++i) + Call->setArg(i, AllArgs[i]); + + return false; +} +bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + unsigned FirstProtoArg, + Expr **Args, unsigned NumArgs, + llvm::SmallVector &AllArgs, + VariadicCallType CallType) { + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + bool Invalid = false; + if (NumArgs != NumArgsInProto) + // Use default arguments for missing arguments + NumArgsToCheck = NumArgsInProto; + unsigned ArgIx = 0; // Continue to check argument types (even if we have too few/many args). - for (unsigned i = 0; i != NumArgsToCheck; i++) { + for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) { QualType ProtoArgType = Proto->getArgType(i); - + Expr *Arg; - if (i < NumArgs) { - Arg = Args[i]; - + if (ArgIx < NumArgs) { + Arg = Args[ArgIx++]; + if (RequireCompleteType(Arg->getSourceRange().getBegin(), ProtoArgType, PDiag(diag::err_call_incomplete_argument) - << Arg->getSourceRange())) + << Arg->getSourceRange())) return true; - + // Pass the argument. if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) return true; @@ -2520,35 +2905,26 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, Arg = MaybeBindToTemporary(Arg).takeAs(); } else { ParmVarDecl *Param = FDecl->getParamDecl(i); - + OwningExprResult ArgExpr = - BuildCXXDefaultArgExpr(Call->getSourceRange().getBegin(), - FDecl, Param); + BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); if (ArgExpr.isInvalid()) return true; - + Arg = ArgExpr.takeAs(); } - - Call->setArg(i, Arg); + AllArgs.push_back(Arg); } - + // If this is a variadic call, handle args passed through "...". - if (Proto->isVariadic()) { - VariadicCallType CallType = VariadicFunction; - if (Fn->getType()->isBlockPointerType()) - CallType = VariadicBlock; // Block - else if (isa(Fn)) - CallType = VariadicMethod; - + if (CallType != VariadicDoesNotApply) { // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = NumArgsInProto; i < NumArgs; i++) { + for (unsigned i = ArgIx; i < NumArgs; i++) { Expr *Arg = Args[i]; Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType); - Call->setArg(i, Arg); + AllArgs.push_back(Arg); } } - return Invalid; } @@ -2557,22 +2933,22 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, /// whether argument-dependent lookup is available, whether it has explicit /// template arguments, etc. void Sema::DeconstructCallFunction(Expr *FnExpr, - NamedDecl *&Function, + llvm::SmallVectorImpl &Fns, DeclarationName &Name, NestedNameSpecifier *&Qualifier, SourceRange &QualifierRange, bool &ArgumentDependentLookup, + bool &Overloaded, bool &HasExplicitTemplateArguments, - const TemplateArgumentLoc *&ExplicitTemplateArgs, - unsigned &NumExplicitTemplateArgs) { + TemplateArgumentListInfo &ExplicitTemplateArgs) { // Set defaults for all of the output parameters. - Function = 0; Name = DeclarationName(); Qualifier = 0; QualifierRange = SourceRange(); - ArgumentDependentLookup = getLangOptions().CPlusPlus; + ArgumentDependentLookup = false; + Overloaded = false; HasExplicitTemplateArguments = false; - + // If we're directly calling a function, get the appropriate declaration. // Also, in C++, keep track of whether we should perform argument-dependent // lookup and whether there were any explicitly-specified template arguments. @@ -2580,59 +2956,31 @@ void Sema::DeconstructCallFunction(Expr *FnExpr, if (ImplicitCastExpr *IcExpr = dyn_cast(FnExpr)) FnExpr = IcExpr->getSubExpr(); else if (ParenExpr *PExpr = dyn_cast(FnExpr)) { - // Parentheses around a function disable ADL - // (C++0x [basic.lookup.argdep]p1). - ArgumentDependentLookup = false; FnExpr = PExpr->getSubExpr(); } else if (isa(FnExpr) && cast(FnExpr)->getOpcode() == UnaryOperator::AddrOf) { FnExpr = cast(FnExpr)->getSubExpr(); } else if (DeclRefExpr *DRExpr = dyn_cast(FnExpr)) { - Function = dyn_cast(DRExpr->getDecl()); - if ((Qualifier = DRExpr->getQualifier())) { - ArgumentDependentLookup = false; + Fns.push_back(cast(DRExpr->getDecl())); + ArgumentDependentLookup = false; + if ((Qualifier = DRExpr->getQualifier())) QualifierRange = DRExpr->getQualifierRange(); - } break; - } else if (UnresolvedFunctionNameExpr *DepName - = dyn_cast(FnExpr)) { - Name = DepName->getName(); - break; - } else if (TemplateIdRefExpr *TemplateIdRef - = dyn_cast(FnExpr)) { - Function = TemplateIdRef->getTemplateName().getAsTemplateDecl(); - if (!Function) - Function = TemplateIdRef->getTemplateName().getAsOverloadedFunctionDecl(); - HasExplicitTemplateArguments = true; - ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs(); - NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs(); - - // C++ [temp.arg.explicit]p6: - // [Note: For simple function names, argument dependent lookup (3.4.2) - // applies even when the function name is not visible within the - // scope of the call. This is because the call still has the syntactic - // form of a function call (3.4.1). But when a function template with - // explicit template arguments is used, the call does not have the - // correct syntactic form unless there is a function template with - // that name visible at the point of the call. If no such name is - // visible, the call is not syntactically well-formed and - // argument-dependent lookup does not apply. If some such name is - // visible, argument dependent lookup applies and additional function - // templates may be found in other namespaces. - // - // The summary of this paragraph is that, if we get to this point and the - // template-id was not a qualified name, then argument-dependent lookup - // is still possible. - if ((Qualifier = TemplateIdRef->getQualifier())) { - ArgumentDependentLookup = false; - QualifierRange = TemplateIdRef->getQualifierRange(); + } else if (UnresolvedLookupExpr *UnresLookup + = dyn_cast(FnExpr)) { + Name = UnresLookup->getName(); + Fns.append(UnresLookup->decls_begin(), UnresLookup->decls_end()); + ArgumentDependentLookup = UnresLookup->requiresADL(); + Overloaded = UnresLookup->isOverloaded(); + if ((Qualifier = UnresLookup->getQualifier())) + QualifierRange = UnresLookup->getQualifierRange(); + if (UnresLookup->hasExplicitTemplateArgs()) { + HasExplicitTemplateArguments = true; + UnresLookup->copyTemplateArgumentsInto(ExplicitTemplateArgs); } break; } else { - // Any kind of name that does not refer to a declaration (or - // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). - ArgumentDependentLookup = false; break; } } @@ -2653,9 +3001,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Expr *Fn = fn.takeAs(); Expr **Args = reinterpret_cast(args.release()); assert(Fn && "no function call expression"); - FunctionDecl *FDecl = NULL; - NamedDecl *NDecl = NULL; - DeclarationName UnqualifiedName; if (getLangOptions().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. @@ -2696,20 +3041,33 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc)); + Expr *NakedFn = Fn->IgnoreParens(); + + // Determine whether this is a call to an unresolved member function. + if (UnresolvedMemberExpr *MemE = dyn_cast(NakedFn)) { + // If lookup was unresolved but not dependent (i.e. didn't find + // an unresolved using declaration), it has to be an overloaded + // function set, which means it must contain either multiple + // declarations (all methods or method templates) or a single + // method template. + assert((MemE->getNumDecls() > 1) || + isa(*MemE->decls_begin())); + (void)MemE; + + return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc)); + } + // Determine whether this is a call to a member function. - if (MemberExpr *MemExpr = dyn_cast(Fn->IgnoreParens())) { + if (MemberExpr *MemExpr = dyn_cast(NakedFn)) { NamedDecl *MemDecl = MemExpr->getMemberDecl(); - if (isa(MemDecl) || - isa(MemDecl) || - (isa(MemDecl) && - isa( - cast(MemDecl)->getTemplatedDecl()))) + if (isa(MemDecl)) return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc)); } // Determine whether this is a call to a pointer-to-member function. - if (BinaryOperator *BO = dyn_cast(Fn->IgnoreParens())) { + if (BinaryOperator *BO = dyn_cast(NakedFn)) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { if (const FunctionProtoType *FPT = @@ -2742,48 +3100,65 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // If we're directly calling a function, get the appropriate declaration. // Also, in C++, keep track of whether we should perform argument-dependent // lookup and whether there were any explicitly-specified template arguments. - bool ADL = true; + llvm::SmallVector Fns; + DeclarationName UnqualifiedName; + bool Overloaded; + bool ADL; bool HasExplicitTemplateArgs = 0; - const TemplateArgumentLoc *ExplicitTemplateArgs = 0; - unsigned NumExplicitTemplateArgs = 0; + TemplateArgumentListInfo ExplicitTemplateArgs; NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; - DeconstructCallFunction(Fn, NDecl, UnqualifiedName, Qualifier, QualifierRange, - ADL,HasExplicitTemplateArgs, ExplicitTemplateArgs, - NumExplicitTemplateArgs); - - OverloadedFunctionDecl *Ovl = 0; - FunctionTemplateDecl *FunctionTemplate = 0; - if (NDecl) { - FDecl = dyn_cast(NDecl); - if ((FunctionTemplate = dyn_cast(NDecl))) - FDecl = FunctionTemplate->getTemplatedDecl(); - else - FDecl = dyn_cast(NDecl); - Ovl = dyn_cast(NDecl); - } - - if (Ovl || FunctionTemplate || - (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) { - // We don't perform ADL for implicit declarations of builtins. - if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit()) - ADL = false; - - // We don't perform ADL in C. - if (!getLangOptions().CPlusPlus) - ADL = false; - - if (Ovl || FunctionTemplate || ADL) { - FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, - HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - LParenLoc, Args, NumArgs, CommaLocs, - RParenLoc, ADL); - if (!FDecl) - return ExprError(); + DeconstructCallFunction(Fn, Fns, UnqualifiedName, Qualifier, QualifierRange, + ADL, Overloaded, HasExplicitTemplateArgs, + ExplicitTemplateArgs); + + NamedDecl *NDecl; // the specific declaration we're calling, if applicable + FunctionDecl *FDecl; // same, if it's known to be a function + + if (Overloaded || ADL) { +#ifndef NDEBUG + if (ADL) { + // To do ADL, we must have found an unqualified name. + assert(UnqualifiedName && "found no unqualified name for ADL"); + + // We don't perform ADL for implicit declarations of builtins. + // Verify that this was correctly set up. + if (Fns.size() == 1 && (FDecl = dyn_cast(Fns[0])) && + FDecl->getBuiltinID() && FDecl->isImplicit()) + assert(0 && "performing ADL for builtin"); + + // We don't perform ADL in C. + assert(getLangOptions().CPlusPlus && "ADL enabled in C"); + } + + if (Overloaded) { + // To be overloaded, we must either have multiple functions or + // at least one function template (which is effectively an + // infinite set of functions). + assert((Fns.size() > 1 || + (Fns.size() == 1 && + isa(Fns[0]->getUnderlyingDecl()))) + && "unrecognized overload situation"); + } +#endif + + FDecl = ResolveOverloadedCallFn(Fn, Fns, UnqualifiedName, + (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), + LParenLoc, Args, NumArgs, CommaLocs, + RParenLoc, ADL); + if (!FDecl) + return ExprError(); - Fn = FixOverloadedFunctionReference(Fn, FDecl); + Fn = FixOverloadedFunctionReference(Fn, FDecl); + + NDecl = FDecl; + } else { + assert(Fns.size() <= 1 && "overloaded without Overloaded flag"); + if (Fns.empty()) + NDecl = FDecl = 0; + else { + NDecl = Fns[0]; + FDecl = dyn_cast(NDecl); } } @@ -3198,13 +3573,18 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, } } -Action::OwningExprResult Sema::ActOnParenListExpr(SourceLocation L, +Action::OwningExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val) { + MultiExprArg Val, + TypeTy *TypeOfCast) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast(Val.release()); - assert((exprs != 0) && "ActOnParenListExpr() missing expr list"); - Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); + assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); + Expr *expr; + if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast)) + expr = new (Context) ParenExpr(L, R, exprs[0]); + else + expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); return Owned(expr); } @@ -3305,6 +3685,17 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); return RHSTy; } + // And the same for struct objc_selector* / SEL + if (Context.isObjCSelType(LHSTy) && + (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (Context.isObjCSelType(RHSTy) && + (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { @@ -4334,7 +4725,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, const PartialDiagnostic &PD, bool Equality) { // Don't warn if we're in an unevaluated context. - if (ExprEvalContext == Unevaluated) + if (ExprEvalContexts.back().Context == Unevaluated) return; QualType lt = lex->getType(), rt = rex->getType(); @@ -4771,19 +5162,41 @@ inline QualType Sema::CheckBitwiseOperands( inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] Expr *&lex, Expr *&rex, SourceLocation Loc) { - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); + if (!Context.getLangOptions().CPlusPlus) { + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); - if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) + return InvalidOperands(Loc, lex, rex); - if (Context.getLangOptions().CPlusPlus) { - // C++ [expr.log.and]p2 - // C++ [expr.log.or]p2 - return Context.BoolTy; + return Context.IntTy; } + + // C++ [expr.log.and]p1 + // C++ [expr.log.or]p1 + // The operands are both implicitly converted to type bool (clause 4). + StandardConversionSequence LHS; + if (!IsStandardConversion(lex, Context.BoolTy, + /*InOverloadResolution=*/false, LHS)) + return InvalidOperands(Loc, lex, rex); - return Context.IntTy; + if (PerformImplicitConversion(lex, Context.BoolTy, LHS, + "passing", /*IgnoreBaseAccess=*/false)) + return InvalidOperands(Loc, lex, rex); + + StandardConversionSequence RHS; + if (!IsStandardConversion(rex, Context.BoolTy, + /*InOverloadResolution=*/false, RHS)) + return InvalidOperands(Loc, lex, rex); + + if (PerformImplicitConversion(rex, Context.BoolTy, RHS, + "passing", /*IgnoreBaseAccess=*/false)) + return InvalidOperands(Loc, lex, rex); + + // C++ [expr.log.and]p2 + // C++ [expr.log.or]p2 + // The result is a bool. + return Context.BoolTy; } /// IsReadonlyProperty - Verify that otherwise a valid l-value expression @@ -5123,6 +5536,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { // FIXME: Can LHS ever be null here? if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull()) return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc); + } else if (isa(op)) { + return Context.OverloadTy; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -5132,8 +5547,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { << "register variable" << op->getSourceRange(); return QualType(); } - } else if (isa(dcl) || - isa(dcl)) { + } else if (isa(dcl)) { return Context.OverloadTy; } else if (FieldDecl *FD = dyn_cast(dcl)) { // Okay: we can take the address of a field. @@ -6199,34 +6613,41 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ return false; } -Sema::ExpressionEvaluationContext +void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { - // Introduce a new set of potentially referenced declarations to the stack. - if (NewContext == PotentiallyPotentiallyEvaluated) - PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls()); - - std::swap(ExprEvalContext, NewContext); - return NewContext; + ExprEvalContexts.push_back( + ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size())); } void -Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext) { - ExprEvalContext = NewContext; +Sema::PopExpressionEvaluationContext() { + // Pop the current expression evaluation context off the stack. + ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); + ExprEvalContexts.pop_back(); - if (OldContext == PotentiallyPotentiallyEvaluated) { + if (Rec.Context == PotentiallyPotentiallyEvaluated && + Rec.PotentiallyReferenced) { // Mark any remaining declarations in the current position of the stack // as "referenced". If they were not meant to be referenced, semantic // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - PotentiallyReferencedDecls RemainingDecls; - RemainingDecls.swap(PotentiallyReferencedDeclStack.back()); - PotentiallyReferencedDeclStack.pop_back(); - - for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(), - IEnd = RemainingDecls.end(); + for (PotentiallyReferencedDecls::iterator + I = Rec.PotentiallyReferenced->begin(), + IEnd = Rec.PotentiallyReferenced->end(); I != IEnd; ++I) MarkDeclarationReferenced(I->first, I->second); - } + } + + // When are coming out of an unevaluated context, clear out any + // temporaries that we may have created as part of the evaluation of + // the expression in that context: they aren't relevant because they + // will never be constructed. + if (Rec.Context == Unevaluated && + ExprTemporaries.size() > Rec.NumTemporaries) + ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, + ExprTemporaries.end()); + + // Destroy the popped expression evaluation record. + Rec.Destroy(); } /// \brief Note that the given declaration was referenced in the source code. @@ -6258,7 +6679,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (CurContext->isDependentContext()) return; - switch (ExprEvalContext) { + switch (ExprEvalContexts.back().Context) { case Unevaluated: // We are in an expression that is not potentially evaluated; do nothing. return; @@ -6272,7 +6693,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // We are in an expression that may be potentially evaluated; queue this // declaration reference until we know whether the expression is // potentially evaluated. - PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D)); + ExprEvalContexts.back().addReferencedDecl(Loc, D); return; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 462bf13..00fb65d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -63,10 +63,11 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, } } - // If this is an unevaluated operand, clear out the set of declaration - // references we have been computing. + // If this is an unevaluated operand, clear out the set of + // declaration references we have been computing and eliminate any + // temporaries introduced in its computation. if (isUnevaluatedOperand) - PotentiallyReferencedDeclStack.back().clear(); + ExprEvalContexts.back().Context = Unevaluated; } return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, @@ -326,7 +327,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo); if (D.isInvalidType()) return ExprError(); - + return BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, move(PlacementArgs), @@ -394,7 +395,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); - + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, @@ -402,7 +403,24 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); - + llvm::SmallVector AllPlaceArgs; + if (OperatorNew) { + // Add default arguments, if any. + const FunctionProtoType *Proto = + OperatorNew->getType()->getAs(); + VariadicCallType CallType = + Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; + bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew, + Proto, 1, PlaceArgs, NumPlaceArgs, + AllPlaceArgs, CallType); + if (Invalid) + return ExprError(); + + NumPlaceArgs = AllPlaceArgs.size(); + if (NumPlaceArgs > 0) + PlaceArgs = &AllPlaceArgs[0]; + } + bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- // C++ 5.3.4p15 @@ -602,7 +620,9 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // The first argument is size_t, and the first parameter must be size_t, // too. This is checked on declaration and can be assumed. (It can't be // asserted on, though, since invalid decls are left in there.) - for (unsigned i = 0; i < NumArgs; ++i) { + // Whatch out for variadic allocator function. + unsigned NumArgsInFnDecl = FnDecl->getNumParams(); + for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { // FIXME: Passing word to diagnostic. if (PerformCopyInitialization(Args[i], FnDecl->getParamDecl(i)->getType(), @@ -827,18 +847,15 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *Record = Type->getAs()) { llvm::SmallVector ObjectPtrConversions; CXXRecordDecl *RD = cast(Record->getDecl()); - OverloadedFunctionDecl *Conversions = - RD->getVisibleConversionFunctions(); + const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { // Skip over templated conversion functions; they aren't considered. - if (isa(*Func)) + if (isa(*I)) continue; - CXXConversionDecl *Conv = cast(*Func); + CXXConversionDecl *Conv = cast(*I); QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs()) @@ -927,54 +944,25 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, OperatorDelete, Ex, StartLoc)); } - -/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a -/// C++ if/switch/while/for statement. -/// e.g: "if (int x = f()) {...}" -Action::OwningExprResult -Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, - Declarator &D, - SourceLocation EqualLoc, - ExprArg AssignExprVal) { - assert(AssignExprVal.get() && "Null assignment expression"); - - // C++ 6.4p2: - // The declarator shall not specify a function or an array. - // The type-specifier-seq shall not contain typedef and shall not declare a - // new class or enumeration. - - assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - "Parser allowed 'typedef' as storage class of condition decl."); - - // FIXME: Store DeclaratorInfo in the expression. - DeclaratorInfo *DInfo = 0; - TagDecl *OwnedTag = 0; - QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); - - if (Ty->isFunctionType()) { // The declarator shall not specify a function... - // We exit without creating a CXXConditionDeclExpr because a FunctionDecl - // would be created and CXXConditionDeclExpr wants a VarDecl. - return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type) - << SourceRange(StartLoc, EqualLoc)); - } else if (Ty->isArrayType()) { // ...or an array. - Diag(StartLoc, diag::err_invalid_use_of_array_type) - << SourceRange(StartLoc, EqualLoc); - } else if (OwnedTag && OwnedTag->isDefinition()) { - // The type-specifier-seq shall not declare a new class or enumeration. - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); - } - - DeclPtrTy Dcl = ActOnDeclarator(S, D); - if (!Dcl) - return ExprError(); - AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false); - - // Mark this variable as one that is declared within a conditional. - // We know that the decl had to be a VarDecl because that is the only type of - // decl that can be assigned and the grammar requires an '='. - VarDecl *VD = cast(Dcl.getAs()); - VD->setDeclaredInCondition(true); - return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD)); +/// \brief Check the use of the given variable as a C++ condition in an if, +/// while, do-while, or switch statement. +Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar) { + QualType T = ConditionVar->getType(); + + // C++ [stmt.select]p2: + // The declarator shall not specify a function or an array. + if (T->isFunctionType()) + return ExprError(Diag(ConditionVar->getLocation(), + diag::err_invalid_use_of_function_type) + << ConditionVar->getSourceRange()); + else if (T->isArrayType()) + return ExprError(Diag(ConditionVar->getLocation(), + diag::err_invalid_use_of_array_type) + << ConditionVar->getSourceRange()); + + return Owned(DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, + ConditionVar->getLocation(), + ConditionVar->getType().getNonReferenceType())); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. @@ -1128,11 +1116,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, dyn_cast(FD)) { CastKind = CastExpr::CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. - if (!ICS.UserDefined.EllipsisConversion) + if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the // initial standard conversion sequence converts the source type to the // type required by the argument of the constructor - BeforeToType = Ctor->getParamDecl(0)->getType(); + BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); + } } else assert(0 && "Unknown conversion function kind!"); @@ -1152,21 +1141,25 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CastArg.isInvalid()) return true; - + + From = CastArg.takeAs(); + + // FIXME: This and the following if statement shouldn't be necessary, but + // there's some nasty stuff involving MaybeBindToTemporary going on here. if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && ICS.UserDefined.After.CopyConstructor) { - From = CastArg.takeAs(); return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); } - - if (ICS.UserDefined.After.Second == ICK_Pointer_Member && - ToType.getNonReferenceType()->isMemberFunctionPointerType()) - CastKind = CastExpr::CK_BaseToDerivedMemberPointer; - - From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), - CastKind, CastArg.takeAs(), - ToType->isLValueReferenceType()); - return false; + + if (ICS.UserDefined.After.CopyConstructor) { + From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), + CastKind, From, + ToType->isLValueReferenceType()); + return false; + } + + return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, + "converting", IgnoreBaseAccess); } case ImplicitConversionSequence::EllipsisConversion: @@ -1333,9 +1326,14 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, ToType, Kind); break; } - case ICK_Boolean_Conversion: - ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown); + case ICK_Boolean_Conversion: { + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (FromType->isMemberPointerType()) + Kind = CastExpr::CK_MemberPointerToBoolean; + + ImpCastExprToType(From, Context.BoolTy, Kind); break; + } case ICK_Derived_To_Base: if (CheckDerivedToBaseConversion(From->getType(), @@ -2131,10 +2129,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } } - } - if (BaseType->isPointerType()) - BaseType = BaseType->getPointeeType(); + if (BaseType->isPointerType()) + BaseType = BaseType->getPointeeType(); + } // We could end up with various non-record types here, such as extended // vector types or Objective-C interfaces. Just return early and let @@ -2175,10 +2173,10 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, else ResultType = Method->getResultType().getNonReferenceType(); - CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, 0, 0, - ResultType, - Exp->getLocEnd()); + MarkDeclarationReferenced(Exp->getLocStart(), Method); + CXXMemberCallExpr *CE = + new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, + Exp->getLocEnd()); return CE; } @@ -2238,9 +2236,6 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { /// /// FIXME: Should Objective-C also use this approach? /// -/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the -/// name of the declaration referenced. -/// /// \param D the declaration being referenced from the current scope. /// /// \param NameLoc the location of the name in the source. @@ -2249,16 +2244,11 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { /// access, will be set to the type of the "this" pointer to be used when /// building that implicit member access. /// -/// \param MemberType if the reference to this declaration is an implicit -/// member access, will be set to the type of the member being referenced -/// (for use at the type of the resulting member access expression). -/// /// \returns true if this is an implicit member reference (in which case /// \p ThisType and \p MemberType will be set), or false if it is not an /// implicit member reference. -bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, - SourceLocation NameLoc, QualType &ThisType, - QualType &MemberType) { +bool Sema::isImplicitMemberReference(const LookupResult &R, + QualType &ThisType) { // If this isn't a C++ method, then it isn't an implicit member reference. CXXMethodDecl *MD = dyn_cast(CurContext); if (!MD || MD->isStatic()) @@ -2271,30 +2261,21 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, // class member access expression (5.2.5) using (*this) (9.3.2) // as the postfix-expression to the left of the '.' operator. DeclContext *Ctx = 0; - if (FieldDecl *FD = dyn_cast(D)) { + if (R.isUnresolvableResult()) { + // FIXME: this is just picking one at random + Ctx = R.getRepresentativeDecl()->getDeclContext(); + } else if (FieldDecl *FD = R.getAsSingle()) { Ctx = FD->getDeclContext(); - MemberType = FD->getType(); - - if (const ReferenceType *RefType = MemberType->getAs()) - MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) - MemberType - = Context.getQualifiedType(MemberType, - Qualifiers::fromCVRMask(MD->getTypeQualifiers())); } else { - for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) { - CXXMethodDecl *Method = dyn_cast(*Ovl); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + CXXMethodDecl *Method = dyn_cast(*I); FunctionTemplateDecl *FunTmpl = 0; - if (!Method && (FunTmpl = dyn_cast(*Ovl))) + if (!Method && (FunTmpl = dyn_cast(*I))) Method = dyn_cast(FunTmpl->getTemplatedDecl()); // FIXME: Do we have to know if there are explicit template arguments? if (Method && !Method->isStatic()) { Ctx = Method->getParent(); - if (isa(D) && !FunTmpl) - MemberType = Method->getType(); - else - MemberType = Context.OverloadTy; break; } } @@ -2306,11 +2287,8 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, // Determine whether the declaration(s) we found are actually in a base // class. If not, this isn't an implicit member reference. ThisType = MD->getThisType(Context); - - // If the type of "this" is dependent, we can't tell if the member is in a - // base class or not, so treat this as a dependent implicit member reference. - if (ThisType->isDependentType()) - return true; + + // FIXME: this doesn't really work for overloaded lookups. QualType CtxType = Context.getTypeDeclType(cast(Ctx)); QualType ClassType diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0f973d6d..2eba704 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -136,8 +136,51 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, SourceLocation InitLoc, DeclarationName InitEntity, bool DirectInit) { if (DeclType->isDependentType() || - Init->isTypeDependent() || Init->isValueDependent()) + Init->isTypeDependent() || Init->isValueDependent()) { + // We have either a dependent type or a type- or value-dependent + // initializer, so we don't perform any additional checking at + // this point. + + // If the declaration is a non-dependent, incomplete array type + // that has an initializer, then its type will be completed once + // the initializer is instantiated. + if (!DeclType->isDependentType()) { + if (const IncompleteArrayType *ArrayT + = Context.getAsIncompleteArrayType(DeclType)) { + if (InitListExpr *ILE = dyn_cast(Init)) { + if (!ILE->isTypeDependent()) { + // Compute the constant array type from the length of the + // initializer list. + // FIXME: This will be wrong if there are designated + // initializations. Good thing they don't exist in C++! + llvm::APInt NumElements(Context.getTypeSize(Context.getSizeType()), + ILE->getNumInits()); + llvm::APInt Zero(Context.getTypeSize(Context.getSizeType()), 0); + if (NumElements == Zero) { + // Sizing an array implicitly to zero is not allowed by ISO C, + // but is supported by GNU. + Diag(ILE->getLocStart(), diag::ext_typecheck_zero_array_size); + } + + DeclType = Context.getConstantArrayType(ArrayT->getElementType(), + NumElements, + ArrayT->getSizeModifier(), + ArrayT->getIndexTypeCVRQualifiers()); + return false; + } + } + + // Make the array type-dependent by making it dependently-sized. + DeclType = Context.getDependentSizedArrayType(ArrayT->getElementType(), + /*NumElts=*/0, + ArrayT->getSizeModifier(), + ArrayT->getIndexTypeCVRQualifiers(), + SourceRange()); + } + } + return false; + } // C++ [dcl.init.ref]p1: // A variable declared to be a T& or T&&, that is "reference to type T" diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 1957d7f..8f09827 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -242,6 +242,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } +/// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); @@ -251,8 +252,12 @@ void LookupResult::resolveKind() { return; } + // If there's a single decl, we need to examine it to decide what + // kind of lookup this is. if (N == 1) { - if (isa(Decls[0])) + if (isa(Decls[0])) + ResultKind = FoundOverloaded; + else if (isa(Decls[0])) ResultKind = FoundUnresolvedValue; return; } @@ -264,7 +269,7 @@ void LookupResult::resolveKind() { bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; - bool HasUnresolved = false; + bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; @@ -290,7 +295,10 @@ void LookupResult::resolveKind() { Ambiguous = true; UniqueTagIndex = I; HasTag = true; - } else if (D->isFunctionOrFunctionTemplate()) { + } else if (isa(D)) { + HasFunction = true; + HasFunctionTemplate = true; + } else if (isa(D)) { HasFunction = true; } else { if (HasNonFunction) @@ -323,7 +331,7 @@ void LookupResult::resolveKind() { setAmbiguous(LookupResult::AmbiguousReference); else if (HasUnresolved) ResultKind = LookupResult::FoundUnresolvedValue; - else if (N > 1) + else if (N > 1 || HasFunctionTemplate) ResultKind = LookupResult::FoundOverloaded; else ResultKind = LookupResult::Found; @@ -1525,33 +1533,25 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, // in which the function or function template is defined and the // classes and namespaces associated with its (non-dependent) // parameter types and return type. - DeclRefExpr *DRE = 0; - TemplateIdRefExpr *TIRE = 0; Arg = Arg->IgnoreParens(); - if (UnaryOperator *unaryOp = dyn_cast(Arg)) { - if (unaryOp->getOpcode() == UnaryOperator::AddrOf) { - DRE = dyn_cast(unaryOp->getSubExpr()); - TIRE = dyn_cast(unaryOp->getSubExpr()); - } - } else { - DRE = dyn_cast(Arg); - TIRE = dyn_cast(Arg); - } + if (UnaryOperator *unaryOp = dyn_cast(Arg)) + if (unaryOp->getOpcode() == UnaryOperator::AddrOf) + Arg = unaryOp->getSubExpr(); + + // TODO: avoid the copies. This should be easy when the cases + // share a storage implementation. + llvm::SmallVector Functions; - OverloadedFunctionDecl *Ovl = 0; - if (DRE) - Ovl = dyn_cast(DRE->getDecl()); - else if (TIRE) - Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl(); - if (!Ovl) + if (UnresolvedLookupExpr *ULE = dyn_cast(Arg)) + Functions.append(ULE->decls_begin(), ULE->decls_end()); + else continue; - for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - FunctionDecl *FDecl = dyn_cast(*Func); + for (llvm::SmallVectorImpl::iterator I = Functions.begin(), + E = Functions.end(); I != E; ++I) { + FunctionDecl *FDecl = dyn_cast(*I); if (!FDecl) - FDecl = cast(*Func)->getTemplatedDecl(); + FDecl = cast(*I)->getTemplatedDecl(); // Add the namespace in which this function was defined. Note // that, if this is a member function, we do *not* consider the diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index daf5b7f..6ea6a14 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -23,7 +23,6 @@ #include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Compiler.h" #include #include @@ -1353,18 +1352,6 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType); } -/// \brief Given a function template or function, extract the function template -/// declaration (if any) and the underlying function declaration. -template -static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function, - FunctionTemplateDecl *&FunctionTemplate) { - FunctionTemplate = dyn_cast(Orig); - if (FunctionTemplate) - Function = cast(FunctionTemplate->getTemplatedDecl()); - else - Function = cast(Orig); -} - /// Determines whether there is a user-defined conversion sequence /// (C++ [over.ics.user]) that converts expression From to the type /// ToType. If such a conversion exists, User will contain the @@ -1431,8 +1418,8 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, - 1, CandidateSet, + AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); else // Allow one user-defined conversion when user specifies a @@ -1455,18 +1442,16 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( if (CXXRecordDecl *FromRecordDecl = dyn_cast(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Conversions = FromRecordDecl->getVisibleConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func - = Conversions->function_begin(); - Func != Conversions->function_end(); ++Func) { + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { CXXConversionDecl *Conv; FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - if (ConvTemplate) + if ((ConvTemplate = dyn_cast(*I))) Conv = dyn_cast(ConvTemplate->getTemplatedDecl()); else - Conv = dyn_cast(*Func); + Conv = dyn_cast(*I); if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) @@ -2254,6 +2239,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (!CandidateSet.isNewCandidate(Function)) return; + // Overload resolution is always an unevaluated context. + EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + if (CXXConstructorDecl *Constructor = dyn_cast(Function)){ // C++ [class.copy]p3: // A member function template is never instantiated to perform the copy @@ -2365,13 +2353,13 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, if (isa(FunTmpl->getTemplatedDecl()) && !cast(FunTmpl->getTemplatedDecl())->isStatic()) AddMethodTemplateCandidate(FunTmpl, - /*FIXME: explicit args */false, 0, 0, + /*FIXME: explicit args */ 0, Args[0], Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddTemplateOverloadCandidate(FunTmpl, - /*FIXME: explicit args */false, 0, 0, + /*FIXME: explicit args */ 0, Args, NumArgs, CandidateSet, SuppressUserConversions); } @@ -2394,7 +2382,7 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, if (FunctionTemplateDecl *TD = dyn_cast(Decl)) { assert(isa(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, false, 0, 0, + AddMethodTemplateCandidate(TD, /*ExplicitArgs*/ 0, Object, Args, NumArgs, CandidateSet, SuppressUserConversions, @@ -2430,6 +2418,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, if (!CandidateSet.isNewCandidate(Method)) return; + // Overload resolution is always an unevaluated context. + EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2509,9 +2500,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, @@ -2531,8 +2520,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result - = DeduceTemplateArguments(MethodTmpl, HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs, + = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { // FIXME: Record what happened with template argument deduction, so // that we can give the user a beautiful diagnostic. @@ -2554,9 +2542,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, /// an appropriate function template specialization. void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, @@ -2576,8 +2562,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs, + = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args, NumArgs, Specialization, Info)) { // FIXME: Record what happened with template argument deduction, so // that we can give the user a beautiful diagnostic. @@ -2608,6 +2593,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, if (!CandidateSet.isNewCandidate(Conversion)) return; + // Overload resolution is always an unevaluated context. + EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2732,6 +2720,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (!CandidateSet.isNewCandidate(Conversion)) return; + // Overload resolution is always an unevaluated context. + EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); Candidate.Function = 0; @@ -2897,6 +2888,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator, unsigned NumContextualBoolArguments) { + // Overload resolution is always an unevaluated context. + EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -3144,20 +3138,17 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func - = Conversions->function_begin(); - Func != Conversions->function_end(); ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { // Skip conversion function templates; they don't tell us anything // about which builtin types we can convert to. - if (ConvTemplate) + if (isa(*I)) continue; + CXXConversionDecl *Conv = cast(*I); if (AllowExplicitConversions || !Conv->isExplicit()) { AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, VisibleQuals); @@ -3211,13 +3202,12 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast(TyRec->getDecl()); - OverloadedFunctionDecl *Conversions = + const UnresolvedSet *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator Func - = Conversions->function_begin(); - Func != Conversions->function_end(); ++Func) { - if (CXXConversionDecl *Conv = dyn_cast(*Func)) { + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + if (CXXConversionDecl *Conv = dyn_cast(*I)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); if (const ReferenceType *ResTypeRef = CanTy->getAs()) CanTy = ResTypeRef->getPointeeType(); @@ -3959,9 +3949,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading) { FunctionSet Functions; @@ -4000,16 +3988,14 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, FuncEnd = Functions.end(); Func != FuncEnd; ++Func) { if (FunctionDecl *FD = dyn_cast(*Func)) { - if (HasExplicitTemplateArgs) + if (ExplicitTemplateArgs) continue; AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, false, false, PartialOverloading); } else AddTemplateOverloadCandidate(cast(*Func), - HasExplicitTemplateArgs, ExplicitTemplateArgs, - NumExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } @@ -4336,7 +4322,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; // Find the actual overloaded function declaration. - OverloadedFunctionDecl *Ovl = 0; // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the @@ -4352,50 +4337,37 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } bool HasExplicitTemplateArgs = false; - const TemplateArgumentLoc *ExplicitTemplateArgs = 0; - unsigned NumExplicitTemplateArgs = 0; + TemplateArgumentListInfo ExplicitTemplateArgs; + + llvm::SmallVector Fns; - // Try to dig out the overloaded function. - FunctionTemplateDecl *FunctionTemplate = 0; - if (DeclRefExpr *DR = dyn_cast(OvlExpr)) { - Ovl = dyn_cast(DR->getDecl()); - FunctionTemplate = dyn_cast(DR->getDecl()); - HasExplicitTemplateArgs = DR->hasExplicitTemplateArgumentList(); - ExplicitTemplateArgs = DR->getTemplateArgs(); - NumExplicitTemplateArgs = DR->getNumTemplateArgs(); - } else if (MemberExpr *ME = dyn_cast(OvlExpr)) { - Ovl = dyn_cast(ME->getMemberDecl()); - FunctionTemplate = dyn_cast(ME->getMemberDecl()); - HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList(); - ExplicitTemplateArgs = ME->getTemplateArgs(); - NumExplicitTemplateArgs = ME->getNumTemplateArgs(); - } else if (TemplateIdRefExpr *TIRE = dyn_cast(OvlExpr)) { - TemplateName Name = TIRE->getTemplateName(); - Ovl = Name.getAsOverloadedFunctionDecl(); - FunctionTemplate = - dyn_cast_or_null(Name.getAsTemplateDecl()); - - HasExplicitTemplateArgs = true; - ExplicitTemplateArgs = TIRE->getTemplateArgs(); - NumExplicitTemplateArgs = TIRE->getNumTemplateArgs(); + // Look into the overloaded expression. + if (UnresolvedLookupExpr *UL + = dyn_cast(OvlExpr)) { + Fns.append(UL->decls_begin(), UL->decls_end()); + if (UL->hasExplicitTemplateArgs()) { + HasExplicitTemplateArgs = true; + UL->copyTemplateArgumentsInto(ExplicitTemplateArgs); + } + } else if (UnresolvedMemberExpr *ME + = dyn_cast(OvlExpr)) { + Fns.append(ME->decls_begin(), ME->decls_end()); + if (ME->hasExplicitTemplateArgs()) { + HasExplicitTemplateArgs = true; + ME->copyTemplateArgumentsInto(ExplicitTemplateArgs); + } } - - // If there's no overloaded function declaration or function template, - // we're done. - if (!Ovl && !FunctionTemplate) - return 0; - OverloadIterator Fun; - if (Ovl) - Fun = Ovl; - else - Fun = FunctionTemplate; + // If we didn't actually find anything, we're done. + if (Fns.empty()) + return 0; // Look through all of the overloaded functions, searching for one // whose type matches exactly. llvm::SmallPtrSet Matches; bool FoundNonTemplateFunction = false; - for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) { + for (llvm::SmallVectorImpl::iterator I = Fns.begin(), + E = Fns.end(); I != E; ++I) { // C++ [over.over]p3: // Non-member functions and static member functions match // targets of type "pointer-to-function" or "reference-to-function." @@ -4404,7 +4376,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Note that according to DR 247, the containing class does not matter. if (FunctionTemplateDecl *FunctionTemplate - = dyn_cast(*Fun)) { + = dyn_cast(*I)) { if (CXXMethodDecl *Method = dyn_cast(FunctionTemplate->getTemplatedDecl())) { // Skip non-static function templates when converting to pointer, and @@ -4424,9 +4396,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, + = DeduceTemplateArguments(FunctionTemplate, + (HasExplicitTemplateArgs ? &ExplicitTemplateArgs : 0), FunctionType, Specialization, Info)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; @@ -4438,9 +4409,11 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, Matches.insert( cast(Specialization->getCanonicalDecl())); } + + continue; } - if (CXXMethodDecl *Method = dyn_cast(*Fun)) { + if (CXXMethodDecl *Method = dyn_cast(*I)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. if (Method->isStatic() == IsMember) @@ -4452,9 +4425,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } else if (IsMember) continue; - if (FunctionDecl *FunDecl = dyn_cast(*Fun)) { + if (FunctionDecl *FunDecl = dyn_cast(*I)) { if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { - Matches.insert(cast(Fun->getCanonicalDecl())); + Matches.insert(cast(FunDecl->getCanonicalDecl())); FoundNonTemplateFunction = true; } } @@ -4522,51 +4495,47 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, - AnyFunctionDecl Callee, - bool &ArgumentDependentLookup, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + NamedDecl *Callee, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { + if (isa(Callee)) + Callee = cast(Callee)->getTargetDecl(); + if (FunctionDecl *Func = dyn_cast(Callee)) { - assert(!HasExplicitTemplateArgs && "Explicit template arguments?"); + assert(!ExplicitTemplateArgs && "Explicit template arguments?"); S.AddOverloadCandidate(Func, Args, NumArgs, CandidateSet, false, false, PartialOverloading); - - if (Func->getDeclContext()->isRecord() || - Func->getDeclContext()->isFunctionOrMethod()) - ArgumentDependentLookup = false; return; - } - - FunctionTemplateDecl *FuncTemplate = cast(Callee); - S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet); - - if (FuncTemplate->getDeclContext()->isRecord()) - ArgumentDependentLookup = false; + } + + if (FunctionTemplateDecl *FuncTemplate + = dyn_cast(Callee)) { + S.AddTemplateOverloadCandidate(FuncTemplate, ExplicitTemplateArgs, + Args, NumArgs, CandidateSet); + return; + } + + assert(false && "unhandled case in overloaded call candidate"); + + // do nothing? } /// \brief Add the overload candidates named by callee and/or found by argument /// dependent lookup to the given overload set. -void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, +void Sema::AddOverloadedCallCandidates(llvm::SmallVectorImpl &Fns, DeclarationName &UnqualifiedName, - bool &ArgumentDependentLookup, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + bool ArgumentDependentLookup, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { - // Add the functions denoted by Callee to the set of candidate - // functions. While we're doing so, track whether argument-dependent - // lookup still applies, per: + +#ifndef NDEBUG + // Verify that ArgumentDependentLookup is consistent with the rules + // in C++0x [basic.lookup.argdep]p3: // - // C++0x [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent // lookup (defined as follows). If X contains @@ -4574,43 +4543,32 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, // -- a declaration of a class member, or // // -- a block-scope function declaration that is not a - // using-declaration (FIXME: check for using declaration), or + // using-declaration, or // // -- a declaration that is neither a function or a function // template // // then Y is empty. - if (!Callee) { - // Nothing to do. - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast(Callee)) { - for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) - AddOverloadedCallCandidate(*this, *Func, ArgumentDependentLookup, - HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet, - PartialOverloading); - } else if (isa(Callee) || isa(Callee)) - AddOverloadedCallCandidate(*this, - AnyFunctionDecl::getFromNamedDecl(Callee), - ArgumentDependentLookup, - HasExplicitTemplateArgs, - ExplicitTemplateArgs, NumExplicitTemplateArgs, - Args, NumArgs, CandidateSet, + + if (ArgumentDependentLookup) { + for (unsigned I = 0; I < Fns.size(); ++I) { + assert(!Fns[I]->getDeclContext()->isRecord()); + assert(isa(Fns[I]) || + !Fns[I]->getDeclContext()->isFunctionOrMethod()); + assert(Fns[I]->getUnderlyingDecl()->isFunctionOrFunctionTemplate()); + } + } +#endif + + for (llvm::SmallVectorImpl::iterator I = Fns.begin(), + E = Fns.end(); I != E; ++I) + AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs, + Args, NumArgs, CandidateSet, PartialOverloading); - // FIXME: assert isa || isa rather than - // checking dynamically. - - if (Callee) - UnqualifiedName = Callee->getDeclName(); - + if (ArgumentDependentLookup) AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs, - HasExplicitTemplateArgs, ExplicitTemplateArgs, - NumExplicitTemplateArgs, CandidateSet, PartialOverloading); } @@ -4622,23 +4580,21 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, /// the function declaration produced by overload /// resolution. Otherwise, emits diagnostics, deletes all of the /// arguments and Fn, and returns NULL. -FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, +FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, + llvm::SmallVectorImpl &Fns, DeclarationName UnqualifiedName, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, SourceLocation RParenLoc, - bool &ArgumentDependentLookup) { + bool ArgumentDependentLookup) { OverloadCandidateSet CandidateSet; // Add the functions denoted by Callee to the set of candidate // functions. - AddOverloadedCallCandidates(Callee, UnqualifiedName, ArgumentDependentLookup, - HasExplicitTemplateArgs, ExplicitTemplateArgs, - NumExplicitTemplateArgs, Args, NumArgs, + AddOverloadedCallCandidates(Fns, UnqualifiedName, ArgumentDependentLookup, + ExplicitTemplateArgs, Args, NumArgs, CandidateSet); OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { @@ -4675,6 +4631,11 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, return 0; } +static bool IsOverloaded(const Sema::FunctionSet &Functions) { + return Functions.size() > 1 || + (Functions.size() == 1 && isa(*Functions.begin())); +} + /// \brief Create a unary operation that may resolve to an overloaded /// operator. /// @@ -4716,15 +4677,14 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, } if (Input->isTypeDependent()) { - OverloadedFunctionDecl *Overloads - = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + UnresolvedLookupExpr *Fn + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + 0, SourceRange(), OpName, OpLoc, + /*ADL*/ true, IsOverloaded(Functions)); for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) - Overloads->addOverload(*Func); - - DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, - OpLoc, false, false); + Fn->addDecl(*Func); input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, @@ -4874,15 +4834,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OpLoc)); } - OverloadedFunctionDecl *Overloads - = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + UnresolvedLookupExpr *Fn + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + 0, SourceRange(), OpName, OpLoc, + /* ADL */ true, IsOverloaded(Functions)); + for (FunctionSet::iterator Func = Functions.begin(), FuncEnd = Functions.end(); Func != FuncEnd; ++Func) - Overloads->addOverload(*Func); - - DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, - OpLoc, false, false); + Fn->addDecl(*Func); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, @@ -5040,11 +5000,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { - OverloadedFunctionDecl *Overloads - = OverloadedFunctionDecl::Create(Context, CurContext, OpName); - - DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, - LLoc, false, false); + UnresolvedLookupExpr *Fn + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + 0, SourceRange(), OpName, LLoc, + /*ADL*/ true, /*Overloaded*/ false); + // Can't add any actual overloads yet Base.release(); Idx.release(); @@ -5169,51 +5129,63 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation RParenLoc) { // Dig out the member expression. This holds both the object // argument and the member function we're referring to. - MemberExpr *MemExpr = 0; - if (ParenExpr *ParenE = dyn_cast(MemExprE)) - MemExpr = dyn_cast(ParenE->getSubExpr()); - else - MemExpr = dyn_cast(MemExprE); - assert(MemExpr && "Building member call without member expression"); - + Expr *NakedMemExpr = MemExprE->IgnoreParens(); + // Extract the object argument. - Expr *ObjectArg = MemExpr->getBase(); + Expr *ObjectArg; + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; - if (isa(MemExpr->getMemberDecl()) || - isa(MemExpr->getMemberDecl())) { + if (isa(NakedMemExpr)) { + MemExpr = cast(NakedMemExpr); + ObjectArg = MemExpr->getBase(); + Method = cast(MemExpr->getMemberDecl()); + } else { + UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); + ObjectArg = UnresExpr->getBase(); + // Add overload candidates OverloadCandidateSet CandidateSet; - DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName(); - for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; - Func != FuncEnd; ++Func) { - if ((Method = dyn_cast(*Func))) { + for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(), + E = UnresExpr->decls_end(); I != E; ++I) { + + // TODO: note if we found something through a using declaration + NamedDecl *Func = (*I)->getUnderlyingDecl(); + + if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. - if (MemExpr->hasExplicitTemplateArgumentList()) + if (UnresExpr->hasExplicitTemplateArgs()) continue; AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); - } else - AddMethodTemplateCandidate(cast(*Func), - MemExpr->hasExplicitTemplateArgumentList(), - MemExpr->getTemplateArgs(), - MemExpr->getNumTemplateArgs(), + } else { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgs; + if (UnresExpr->hasExplicitTemplateArgs()) + UnresExpr->copyTemplateArgumentsInto(TemplateArgs); + + AddMethodTemplateCandidate(cast(Func), + (UnresExpr->hasExplicitTemplateArgs() + ? &TemplateArgs : 0), ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); + } } + DeclarationName DeclName = UnresExpr->getMemberName(); + OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) { + switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast(Best->Function); break; case OR_No_Viable_Function: - Diag(MemExpr->getSourceRange().getBegin(), + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); @@ -5221,16 +5193,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return true; case OR_Ambiguous: - Diag(MemExpr->getSourceRange().getBegin(), - diag::err_ovl_ambiguous_member_call) + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! return true; case OR_Deleted: - Diag(MemExpr->getSourceRange().getBegin(), - diag::err_ovl_deleted_member_call) + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); @@ -5238,9 +5208,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return true; } - FixOverloadedFunctionReference(MemExpr, Method); - } else { - Method = dyn_cast(MemExpr->getMemberDecl()); + MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + MemExpr = cast(MemExprE->IgnoreParens()); } assert(Method && "Member call to something that isn't a method?"); @@ -5329,21 +5298,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // accessible base class provided the function is not hidden // within T by another intervening declaration. // FIXME: Look in base classes for more conversion operators! - OverloadedFunctionDecl *Conversions + const UnresolvedSet *Conversions = cast(Record->getDecl())->getConversionFunctions(); - for (OverloadedFunctionDecl::function_iterator - Func = Conversions->function_begin(), - FuncEnd = Conversions->function_end(); - Func != FuncEnd; ++Func) { - CXXConversionDecl *Conv; - FunctionTemplateDecl *ConvTemplate; - GetFunctionAndTemplate(*Func, Conv, ConvTemplate); - + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { // Skip over templated conversion functions; they aren't // surrogates. - if (ConvTemplate) + if (isa(*I)) continue; + CXXConversionDecl *Conv = cast(*I); + // Strip the reference type (if any) and then the pointer type (if // any) to get down to what might be a function type. QualType ConvType = Conv->getConversionType().getNonReferenceType(); @@ -5604,80 +5569,111 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// refer (possibly indirectly) to Fn. Returns the new expr. Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast(E)) { - Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); - PE->setSubExpr(NewExpr); - PE->setType(NewExpr->getType()); - } else if (ImplicitCastExpr *ICE = dyn_cast(E)) { - Expr *NewExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + if (SubExpr == PE->getSubExpr()) + return PE->Retain(); + + return new (Context) ParenExpr(PE->getLParen(), PE->getRParen(), SubExpr); + } + + if (ImplicitCastExpr *ICE = dyn_cast(E)) { + Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); assert(Context.hasSameType(ICE->getSubExpr()->getType(), - NewExpr->getType()) && + SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); - ICE->setSubExpr(NewExpr); - } else if (UnaryOperator *UnOp = dyn_cast(E)) { + if (SubExpr == ICE->getSubExpr()) + return ICE->Retain(); + + return new (Context) ImplicitCastExpr(ICE->getType(), + ICE->getCastKind(), + SubExpr, + ICE->isLvalueCast()); + } + + if (UnaryOperator *UnOp = dyn_cast(E)) { assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); if (CXXMethodDecl *Method = dyn_cast(Fn)) { if (Method->isStatic()) { // Do nothing: static member functions aren't any different // from non-member functions. - } else if (DeclRefExpr *DRE = dyn_cast(UnOp->getSubExpr())) { - if (DRE->getQualifier()) { - // We have taken the address of a pointer to member - // function. Perform the computation here so that we get the - // appropriate pointer to member type. - DRE->setDecl(Fn); - DRE->setType(Fn->getType()); - QualType ClassType - = Context.getTypeDeclType(cast(Method->getDeclContext())); - E->setType(Context.getMemberPointerType(Fn->getType(), - ClassType.getTypePtr())); - return E; - } + } else { + // Fix the sub expression, which really has to be an + // UnresolvedLookupExpr holding an overloaded member function + // or template. + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + if (SubExpr == UnOp->getSubExpr()) + return UnOp->Retain(); + + assert(isa(SubExpr) + && "fixed to something other than a decl ref"); + assert(cast(SubExpr)->getQualifier() + && "fixed to a member ref with no nested name qualifier"); + + // We have taken the address of a pointer to member + // function. Perform the computation here so that we get the + // appropriate pointer to member type. + QualType ClassType + = Context.getTypeDeclType(cast(Method->getDeclContext())); + QualType MemPtrType + = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + + return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf, + MemPtrType, UnOp->getOperatorLoc()); } - // FIXME: TemplateIdRefExpr referring to a member function template - // specialization! } - Expr *NewExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); - UnOp->setSubExpr(NewExpr); - UnOp->setType(Context.getPointerType(NewExpr->getType())); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + if (SubExpr == UnOp->getSubExpr()) + return UnOp->Retain(); - return UnOp; - } else if (DeclRefExpr *DR = dyn_cast(E)) { - assert((isa(DR->getDecl()) || - isa(DR->getDecl()) || - isa(DR->getDecl())) && - "Expected function or function template"); - DR->setDecl(Fn); - E->setType(Fn->getType()); - } else if (MemberExpr *MemExpr = dyn_cast(E)) { - MemExpr->setMemberDecl(Fn); - E->setType(Fn->getType()); - } else if (TemplateIdRefExpr *TID = dyn_cast(E)) { - E = DeclRefExpr::Create(Context, - TID->getQualifier(), TID->getQualifierRange(), - Fn, TID->getTemplateNameLoc(), - true, - TID->getLAngleLoc(), - TID->getTemplateArgs(), - TID->getNumTemplateArgs(), - TID->getRAngleLoc(), - Fn->getType(), - /*FIXME?*/false, /*FIXME?*/false); - - // FIXME: Don't destroy TID here, since we need its template arguments - // to survive. - // TID->Destroy(Context); - } else if (isa(E)) { - return DeclRefExpr::Create(Context, - /*Qualifier=*/0, - /*QualifierRange=*/SourceRange(), - Fn, E->getLocStart(), - Fn->getType(), false, false); - } else { - assert(false && "Invalid reference to overloaded function"); + return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf, + Context.getPointerType(SubExpr->getType()), + UnOp->getOperatorLoc()); + } + + if (UnresolvedLookupExpr *ULE = dyn_cast(E)) { + if (ULE->hasExplicitTemplateArgs()) { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgs; + if (ULE->hasExplicitTemplateArgs()) + ULE->copyTemplateArgumentsInto(TemplateArgs); + + return DeclRefExpr::Create(Context, + ULE->getQualifier(), + ULE->getQualifierRange(), + Fn, + ULE->getNameLoc(), + Fn->getType(), + &TemplateArgs); + } + + return DeclRefExpr::Create(Context, + ULE->getQualifier(), + ULE->getQualifierRange(), + Fn, + ULE->getNameLoc(), + Fn->getType()); + } + + if (UnresolvedMemberExpr *MemExpr = dyn_cast(E)) { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgs; + if (MemExpr->hasExplicitTemplateArgs()) + MemExpr->copyTemplateArgumentsInto(TemplateArgs); + + return MemberExpr::Create(Context, MemExpr->getBase()->Retain(), + MemExpr->isArrow(), + MemExpr->getQualifier(), + MemExpr->getQualifierRange(), + Fn, + MemExpr->getMemberLoc(), + (MemExpr->hasExplicitTemplateArgs() + ? &TemplateArgs : 0), + Fn->getType()); } - return E; + assert(false && "Invalid reference to overloaded function"); + return E->Retain(); } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d0f214f..de67a5f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -15,9 +15,11 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -59,6 +61,15 @@ Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc)); } +void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { + DeclGroupRef DG = dg.getAsVal(); + + // If we have an invalid decl, just return. + if (DG.isNull() || !DG.isSingleDecl()) return; + // suppress any potential 'unused variable' warning. + DG.getSingleDecl()->setUsed(); +} + void Sema::DiagnoseUnusedExprResult(const Stmt *S) { const Expr *E = dyn_cast_or_null(S); if (!E) @@ -225,16 +236,24 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, } Action::OwningStmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, +Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal) { OwningExprResult CondResult(CondVal.release()); - Expr *condExpr = CondResult.takeAs(); - - assert(condExpr && "ActOnIfStmt(): missing expression"); - if (CheckBooleanCondition(condExpr, IfLoc)) { - CondResult = condExpr; + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); + } + Expr *ConditionExpr = CondResult.takeAs(); + if (!ConditionExpr) + return StmtError(); + + if (CheckBooleanCondition(ConditionExpr, IfLoc)) { + CondResult = ConditionExpr; return StmtError(); } @@ -254,41 +273,23 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DiagnoseUnusedExprResult(elseStmt); CondResult.release(); - return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt, - ElseLoc, elseStmt)); + return Owned(new (Context) IfStmt(IfLoc, ConditionVar, ConditionExpr, + thenStmt, ElseLoc, elseStmt)); } Action::OwningStmtResult -Sema::ActOnStartOfSwitchStmt(ExprArg cond) { - Expr *Cond = cond.takeAs(); - - if (getLangOptions().CPlusPlus) { - // C++ 6.4.2.p2: - // The condition shall be of integral type, enumeration type, or of a class - // type for which a single conversion function to integral or enumeration - // type exists (12.3). If the condition is of class type, the condition is - // converted by calling that conversion function, and the result of the - // conversion is used in place of the original condition for the remainder - // of this section. Integral promotions are performed. - if (!Cond->isTypeDependent()) { - QualType Ty = Cond->getType(); - - // FIXME: Handle class types. - - // If the type is wrong a diagnostic will be emitted later at - // ActOnFinishSwitchStmt. - if (Ty->isIntegralType() || Ty->isEnumeralType()) { - // Integral promotions are performed. - // FIXME: Integral promotions for C++ are not complete. - UsualUnaryConversions(Cond); - } - } - } else { - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - UsualUnaryConversions(Cond); +Sema::ActOnStartOfSwitchStmt(FullExprArg cond, DeclPtrTy CondVar) { + OwningExprResult CondResult(cond.release()); + + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); } - - SwitchStmt *SS = new (Context) SwitchStmt(Cond); + SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar, + CondResult.takeAs()); getSwitchStack().push_back(SS); return Owned(SS); } @@ -383,6 +384,103 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { return expr->getType(); } +/// \brief Check (and possibly convert) the condition in a switch +/// statement in C++. +static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, + Expr *&CondExpr) { + if (CondExpr->isTypeDependent()) + return false; + + QualType CondType = CondExpr->getType(); + + // C++ 6.4.2.p2: + // The condition shall be of integral type, enumeration type, or of a class + // type for which a single conversion function to integral or enumeration + // type exists (12.3). If the condition is of class type, the condition is + // converted by calling that conversion function, and the result of the + // conversion is used in place of the original condition for the remainder + // of this section. Integral promotions are performed. + + // Make sure that the condition expression has a complete type, + // otherwise we'll never find any conversions. + if (S.RequireCompleteType(SwitchLoc, CondType, + PDiag(diag::err_switch_incomplete_class_type) + << CondExpr->getSourceRange())) + return true; + + llvm::SmallVector ViableConversions; + llvm::SmallVector ExplicitConversions; + if (const RecordType *RecordTy = CondType->getAs()) { + const UnresolvedSet *Conversions + = cast(RecordTy->getDecl()) + ->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + if (CXXConversionDecl *Conversion = dyn_cast(*I)) + if (Conversion->getConversionType().getNonReferenceType() + ->isIntegralType()) { + if (Conversion->isExplicit()) + ExplicitConversions.push_back(Conversion); + else + ViableConversions.push_back(Conversion); + } + } + + switch (ViableConversions.size()) { + case 0: + if (ExplicitConversions.size() == 1) { + // The user probably meant to invoke the given explicit + // conversion; use it. + QualType ConvTy + = ExplicitConversions[0]->getConversionType() + .getNonReferenceType(); + std::string TypeStr; + ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy); + + S.Diag(SwitchLoc, diag::err_switch_explicit_conversion) + << CondType << ConvTy << CondExpr->getSourceRange() + << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(), + "static_cast<" + TypeStr + ">(") + << CodeModificationHint::CreateInsertion( + S.PP.getLocForEndOfToken(CondExpr->getLocEnd()), + ")"); + S.Diag(ExplicitConversions[0]->getLocation(), + diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + + // If we aren't in a SFINAE context, build a call to the + // explicit conversion function. + if (S.isSFINAEContext()) + return true; + + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]); + } + + // We'll complain below about a non-integral condition type. + break; + + case 1: + // Apply this conversion. + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]); + break; + + default: + S.Diag(SwitchLoc, diag::err_switch_multiple_conversions) + << CondType << CondExpr->getSourceRange(); + for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { + QualType ConvTy + = ViableConversions[I]->getConversionType().getNonReferenceType(); + S.Diag(ViableConversions[I]->getLocation(), + diag::note_switch_conversion) + << ConvTy->isEnumeralType() << ConvTy; + } + return true; + } + } + + return false; +} + Action::OwningStmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body) { @@ -394,8 +492,23 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, SS->setBody(BodyStmt, SwitchLoc); getSwitchStack().pop_back(); + if (SS->getCond() == 0) { + SS->Destroy(Context); + return StmtError(); + } + Expr *CondExpr = SS->getCond(); + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExpr); + + if (getLangOptions().CPlusPlus && + CheckCXXSwitchCondition(*this, SwitchLoc, CondExpr)) + return StmtError(); + + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + UsualUnaryConversions(CondExpr); QualType CondType = CondExpr->getType(); + SS->setCond(CondExpr); // C++ 6.4.2.p2: // Integral promotions are performed (on the switch condition). @@ -404,9 +517,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // type (before the promotion) doesn't make sense, even when it can // be represented by the promoted type. Therefore we need to find // the pre-promotion type of the switch condition. - QualType CondTypeBeforePromotion = - GetTypeBeforeIntegralPromotion(CondExpr); - if (!CondExpr->isTypeDependent()) { if (!CondType->isIntegerType()) { // C99 6.8.4.2p1 Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) @@ -614,21 +724,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, } Action::OwningStmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { - ExprArg CondArg(Cond.release()); - Expr *condExpr = CondArg.takeAs(); - assert(condExpr && "ActOnWhileStmt(): missing expression"); - - if (CheckBooleanCondition(condExpr, WhileLoc)) { - CondArg = condExpr; +Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, + DeclPtrTy CondVar, StmtArg Body) { + OwningExprResult CondResult(Cond.release()); + + VarDecl *ConditionVar = 0; + if (CondVar.get()) { + ConditionVar = CondVar.getAs(); + CondResult = CheckConditionVariable(ConditionVar); + if (CondResult.isInvalid()) + return StmtError(); + } + Expr *ConditionExpr = CondResult.takeAs(); + if (!ConditionExpr) + return StmtError(); + + if (CheckBooleanCondition(ConditionExpr, WhileLoc)) { + CondResult = ConditionExpr; return StmtError(); } Stmt *bodyStmt = Body.takeAs(); DiagnoseUnusedExprResult(bodyStmt); - CondArg.release(); - return Owned(new (Context) WhileStmt(condExpr, bodyStmt, WhileLoc)); + CondResult.release(); + return Owned(new (Context) WhileStmt(ConditionVar, ConditionExpr, bodyStmt, + WhileLoc)); } Action::OwningStmtResult @@ -653,12 +774,10 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, Action::OwningStmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg first, ExprArg second, ExprArg third, + StmtArg first, FullExprArg second, DeclPtrTy secondVar, + FullExprArg third, SourceLocation RParenLoc, StmtArg body) { Stmt *First = static_cast(first.get()); - Expr *Second = second.takeAs(); - Expr *Third = static_cast(third.get()); - Stmt *Body = static_cast(body.get()); if (!getLangOptions().CPlusPlus) { if (DeclStmt *DS = dyn_cast_or_null(First)) { @@ -676,20 +795,33 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } } + + OwningExprResult SecondResult(second.release()); + VarDecl *ConditionVar = 0; + if (secondVar.get()) { + ConditionVar = secondVar.getAs(); + SecondResult = CheckConditionVariable(ConditionVar); + if (SecondResult.isInvalid()) + return StmtError(); + } + + Expr *Second = SecondResult.takeAs(); if (Second && CheckBooleanCondition(Second, ForLoc)) { - second = Second; + SecondResult = Second; return StmtError(); } + Expr *Third = third.release().takeAs(); + Stmt *Body = static_cast(body.get()); + DiagnoseUnusedExprResult(First); DiagnoseUnusedExprResult(Third); DiagnoseUnusedExprResult(Body); first.release(); - third.release(); body.release(); - return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc, - LParenLoc, RParenLoc)); + return Owned(new (Context) ForStmt(First, Second, ConditionVar, Third, Body, + ForLoc, LParenLoc, RParenLoc)); } Action::OwningStmtResult diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 31cd300..f47577e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -20,7 +20,6 @@ #include "clang/Parse/Template.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" -#include "llvm/Support/Compiler.h" #include "llvm/ADT/StringExtras.h" using namespace clang; @@ -59,44 +58,20 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { return 0; } - OverloadedFunctionDecl *Ovl = dyn_cast(D); - if (!Ovl) - return 0; - - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - if (FunctionTemplateDecl *FuncTmpl = dyn_cast(*F)) { - // We've found a function template. Determine whether there are - // any other function templates we need to bundle together in an - // OverloadedFunctionDecl - for (++F; F != FEnd; ++F) { - if (isa(*F)) - break; - } - - if (F != FEnd) { - // Build an overloaded function decl containing only the - // function templates in Ovl. - OverloadedFunctionDecl *OvlTemplate - = OverloadedFunctionDecl::Create(Context, - Ovl->getDeclContext(), - Ovl->getDeclName()); - OvlTemplate->addOverload(FuncTmpl); - OvlTemplate->addOverload(*F); - for (++F; F != FEnd; ++F) { - if (isa(*F)) - OvlTemplate->addOverload(*F); - } - - return OvlTemplate; - } + return 0; +} - return FuncTmpl; - } +static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { + LookupResult::Filter filter = R.makeFilter(); + while (filter.hasNext()) { + NamedDecl *Orig = filter.next(); + NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl()); + if (!Repl) + filter.erase(); + else if (Repl != Orig) + filter.replace(Repl); } - - return 0; + filter.done(); } TemplateNameKind Sema::isTemplateName(Scope *S, @@ -117,18 +92,65 @@ TemplateNameKind Sema::isTemplateName(Scope *S, Name.OperatorFunctionId.Operator); break; + case UnqualifiedId::IK_LiteralOperatorId: + TName = Context.DeclarationNames.getCXXLiteralOperatorName(Name.Identifier); + break; + default: return TNK_Non_template; } - + + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + + LookupResult R(*this, TName, SourceLocation(), LookupOrdinaryName); + R.suppressDiagnostics(); + LookupTemplateName(R, S, SS, ObjectType, EnteringContext); + if (R.empty()) + return TNK_Non_template; + + NamedDecl *Template = R.getAsSingleDecl(Context); + + if (SS.isSet() && !SS.isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast(SS.getScopeRep()); + if (OverloadedFunctionDecl *Ovl + = dyn_cast(Template)) + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + Ovl)); + else + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + cast(Template))); + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast(Template)) { + TemplateResult = TemplateTy::make(TemplateName(Ovl)); + } else { + TemplateResult = TemplateTy::make( + TemplateName(cast(Template))); + } + + if (isa(Template) || + isa(Template)) + return TNK_Type_template; + + assert((isa(Template) || + isa(Template)) && + "Unhandled template kind in Sema::isTemplateName"); + return TNK_Function_template; +} + +void Sema::LookupTemplateName(LookupResult &Found, + Scope *S, const CXXScopeSpec &SS, + QualType ObjectType, + bool EnteringContext) { // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; - if (ObjectTypePtr) { + if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); - QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); assert((isDependent || !ObjectType->isIncompleteType()) && @@ -141,10 +163,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS)) - return TNK_Non_template; + return; } - LookupResult Found(*this, TName, SourceLocation(), LookupOrdinaryName); bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we @@ -153,7 +174,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // nested-name-specifier. LookupQualifiedName(Found, LookupCtx); - if (ObjectTypePtr && Found.empty()) { + if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the @@ -166,12 +187,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // // FIXME: When we're instantiating a template, do we actually have to // look in the scope of the template? Seems fishy... - LookupName(Found, S); + if (S) LookupName(Found, S); ObjectTypeSearchedInScope = true; } } else if (isDependent) { // We cannot look into a dependent object type or - return TNK_Non_template; + return; } else { // Perform unqualified name lookup in the current scope. LookupName(Found, S); @@ -181,27 +202,26 @@ TemplateNameKind Sema::isTemplateName(Scope *S, assert(!Found.isAmbiguous() && "Cannot handle template name-lookup ambiguities"); - NamedDecl *Template - = isAcceptableTemplateName(Context, Found.getAsSingleDecl(Context)); - if (!Template) - return TNK_Non_template; + FilterAcceptableTemplateNames(Context, Found); + if (Found.empty()) + return; - if (ObjectTypePtr && !ObjectTypeSearchedInScope) { + if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p1: // [...] If the lookup in the class of the object expression finds a // template, the name is also looked up in the context of the entire // postfix-expression and [...] // - LookupResult FoundOuter(*this, TName, SourceLocation(), LookupOrdinaryName); + LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), + LookupOrdinaryName); LookupName(FoundOuter, S); + FilterAcceptableTemplateNames(Context, FoundOuter); // FIXME: Handle ambiguities in this lookup better - NamedDecl *OuterTemplate - = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context)); - if (!OuterTemplate) { + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise - } else if (!isa(OuterTemplate)) { + } else if (!FoundOuter.getAsSingle()) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise @@ -209,49 +229,165 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. - if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) { - Diag(Name.getSourceRange().getBegin(), + if (!Found.isSingleResult() || + Found.getFoundDecl()->getCanonicalDecl() + != FoundOuter.getFoundDecl()->getCanonicalDecl()) { + Diag(Found.getNameLoc(), diag::err_nested_name_member_ref_lookup_ambiguous) - << TName - << Name.getSourceRange(); - Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type) - << QualType::getFromOpaquePtr(ObjectTypePtr); - Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope); + << Found.getLookupName(); + Diag(Found.getRepresentativeDecl()->getLocation(), + diag::note_ambig_member_ref_object_type) + << ObjectType; + Diag(FoundOuter.getFoundDecl()->getLocation(), + diag::note_ambig_member_ref_scope); // Recover by taking the template that we found in the object // expression's type. } } } +} - if (SS.isSet() && !SS.isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast(SS.getScopeRep()); - if (OverloadedFunctionDecl *Ovl - = dyn_cast(Template)) - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - Ovl)); - else - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - cast(Template))); - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast(Template)) { - TemplateResult = TemplateTy::make(TemplateName(Ovl)); - } else { - TemplateResult = TemplateTy::make( - TemplateName(cast(Template))); +/// Constructs a full type for the given nested-name-specifier. +static QualType GetTypeForQualifier(ASTContext &Context, + NestedNameSpecifier *Qualifier) { + // Three possibilities: + + // 1. A namespace (global or not). + assert(!Qualifier->getAsNamespace() && "can't construct type for namespace"); + + // 2. A type (templated or not). + Type *Ty = Qualifier->getAsType(); + if (Ty) return QualType(Ty, 0); + + // 3. A dependent identifier. + assert(Qualifier->getAsIdentifier()); + return Context.getTypenameType(Qualifier->getPrefix(), + Qualifier->getAsIdentifier()); +} + +static bool HasDependentTypeAsBase(ASTContext &Context, + CXXRecordDecl *Record, + CanQualType T) { + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = Context.getCanonicalType((*I).getType()); + if (BaseT == T) + return true; + + // We have to recurse here to cover some really bizarre cases. + // Obviously, we can only have the dependent type as an indirect + // base class through a dependent base class, and usually it's + // impossible to know which instantiation a dependent base class + // will have. But! If we're actually *inside* the dependent base + // class, then we know its instantiation and can therefore be + // reasonably expected to look into it. + + // template class A : Base { + // class Inner : A { + // void foo() { + // Base::foo(); // statically known to be an implicit member + // reference + // } + // }; + // }; + + CanQual RT = BaseT->getAs(); + + // Base might be a dependent member type, in which case we + // obviously can't look into it. + if (!RT) continue; + + CXXRecordDecl *BaseRecord = cast(RT->getDecl()); + if (BaseRecord->isDefinition() && + HasDependentTypeAsBase(Context, BaseRecord, T)) + return true; } - if (isa(Template) || - isa(Template)) - return TNK_Type_template; + return false; +} - assert((isa(Template) || - isa(Template)) && - "Unhandled template kind in Sema::isTemplateName"); - return TNK_Function_template; +/// Checks whether the given dependent nested-name specifier +/// introduces an implicit member reference. This is only true if the +/// nested-name specifier names a type identical to one of the current +/// instance method's context's (possibly indirect) base classes. +static bool IsImplicitDependentMemberReference(Sema &SemaRef, + NestedNameSpecifier *Qualifier, + QualType &ThisType) { + // If the context isn't a C++ method, then it isn't an implicit + // member reference. + CXXMethodDecl *MD = dyn_cast(SemaRef.CurContext); + if (!MD || MD->isStatic()) + return false; + + ASTContext &Context = SemaRef.Context; + + // We want to check whether the method's context is known to inherit + // from the type named by the nested name specifier. The trivial + // case here is: + // template class Base { ... }; + // template class Derived : Base { + // void foo() { + // Base::foo(); + // } + // }; + + QualType QT = GetTypeForQualifier(Context, Qualifier); + CanQualType T = Context.getCanonicalType(QT); + + // And now, just walk the non-dependent type hierarchy, trying to + // find the given type as a literal base class. + CXXRecordDecl *Record = cast(MD->getParent()); + if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T || + HasDependentTypeAsBase(Context, Record, T)) { + ThisType = MD->getThisType(Context); + return true; + } + + return false; +} + +/// ActOnDependentIdExpression - Handle a dependent declaration name +/// that was just parsed. +Sema::OwningExprResult +Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + bool CheckForImplicitMember, + const TemplateArgumentListInfo *TemplateArgs) { + NestedNameSpecifier *Qualifier + = static_cast(SS.getScopeRep()); + + QualType ThisType; + if (CheckForImplicitMember && + IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) { + Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + + // Since the 'this' expression is synthesized, we don't need to + // perform the double-lookup check. + NamedDecl *FirstQualifierInScope = 0; + + return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true, + /*Op*/ SourceLocation(), + Qualifier, SS.getRange(), + FirstQualifierInScope, + Name, NameLoc, + TemplateArgs)); + } + + return BuildDependentDeclRefExpr(SS, Name, NameLoc, TemplateArgs); +} + +Sema::OwningExprResult +Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs) { + return Owned(DependentScopeDeclRefExpr::Create(Context, + static_cast(SS.getScopeRep()), + SS.getRange(), + Name, NameLoc, + TemplateArgs)); } /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining @@ -317,12 +453,11 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. -void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - llvm::SmallVectorImpl &TemplateArgs) { - TemplateArgs.reserve(TemplateArgsIn.size()); - +void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, + TemplateArgumentListInfo &TemplateArgs) { for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) - TemplateArgs.push_back(translateTemplateArgument(*this, TemplateArgsIn[I])); + TemplateArgs.addArgument(translateTemplateArgument(*this, + TemplateArgsIn[I])); } /// ActOnTypeParameter - Called when a C++ template type parameter @@ -595,7 +730,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, DeclPtrTy *Params, unsigned NumParams, SourceLocation RAngleLoc) { if (ExportLoc.isValid()) - Diag(ExportLoc, diag::note_template_export_unsupported); + Diag(ExportLoc, diag::warn_template_export_unsupported); return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, (NamedDecl**)Params, NumParams, @@ -756,7 +891,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // merging in the template parameter list from the previous class // template declaration. if (CheckTemplateParameterList(TemplateParams, - PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0)) + PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0, + TPC_ClassTemplate)) Invalid = true; // FIXME: If we had a scope specifier, we better have a previous template @@ -837,6 +973,55 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, return DeclPtrTy::make(NewTemplate); } +/// \brief Diagnose the presence of a default template argument on a +/// template parameter, which is ill-formed in certain contexts. +/// +/// \returns true if the default template argument should be dropped. +static bool DiagnoseDefaultTemplateArgument(Sema &S, + Sema::TemplateParamListContext TPC, + SourceLocation ParamLoc, + SourceRange DefArgRange) { + switch (TPC) { + case Sema::TPC_ClassTemplate: + return false; + + case Sema::TPC_FunctionTemplate: + // C++ [temp.param]p9: + // A default template-argument shall not be specified in a + // function template declaration or a function template + // definition [...] + // (This sentence is not in C++0x, per DR226). + if (!S.getLangOptions().CPlusPlus0x) + S.Diag(ParamLoc, + diag::err_template_parameter_default_in_function_template) + << DefArgRange; + return false; + + case Sema::TPC_ClassTemplateMember: + // C++0x [temp.param]p9: + // A default template-argument shall not be specified in the + // template-parameter-lists of the definition of a member of a + // class template that appears outside of the member's class. + S.Diag(ParamLoc, diag::err_template_parameter_default_template_member) + << DefArgRange; + return true; + + case Sema::TPC_FriendFunctionTemplate: + // C++ [temp.param]p9: + // A default template-argument shall not be specified in a + // friend template declaration. + S.Diag(ParamLoc, diag::err_template_parameter_default_friend_template) + << DefArgRange; + return true; + + // FIXME: C++0x [temp.param]p9 allows default template-arguments + // for friend function templates if there is only a single + // declaration (and it is a definition). Strange! + } + + return false; +} + /// \brief Checks the validity of a template parameter list, possibly /// considering the template parameter list from a previous /// declaration. @@ -855,9 +1040,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, /// arguments will be merged from the old template parameter list to /// the new template parameter list. /// +/// \param TPC Describes the context in which we are checking the given +/// template parameter list. +/// /// \returns true if an error occurred, false otherwise. bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, - TemplateParameterList *OldParams) { + TemplateParameterList *OldParams, + TemplateParamListContext TPC) { bool Invalid = false; // C++ [temp.param]p10: @@ -897,9 +1086,17 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, Invalid = true; } - // Merge default arguments for template type parameters. if (TemplateTypeParmDecl *NewTypeParm = dyn_cast(*NewParam)) { + // Check the presence of a default argument here. + if (NewTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTypeParm->getLocation(), + NewTypeParm->getDefaultArgumentInfo()->getTypeLoc() + .getFullSourceRange())) + NewTypeParm->removeDefaultArgument(); + + // Merge default arguments for template type parameters. TemplateTypeParmDecl *OldTypeParm = OldParams? cast(*OldParam) : 0; @@ -929,6 +1126,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, MissingDefaultArg = true; } else if (NonTypeTemplateParmDecl *NewNonTypeParm = dyn_cast(*NewParam)) { + // Check the presence of a default argument here. + if (NewNonTypeParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewNonTypeParm->getLocation(), + NewNonTypeParm->getDefaultArgument()->getSourceRange())) { + NewNonTypeParm->getDefaultArgument()->Destroy(Context); + NewNonTypeParm->setDefaultArgument(0); + } + // Merge default arguments for non-type template parameters NonTypeTemplateParmDecl *OldNonTypeParm = OldParams? cast(*OldParam) : 0; @@ -955,9 +1161,16 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (SawDefaultArgument) MissingDefaultArg = true; } else { - // Merge default arguments for template template parameters + // Check the presence of a default argument here. TemplateTemplateParmDecl *NewTemplateParm = cast(*NewParam); + if (NewTemplateParm->hasDefaultArgument() && + DiagnoseDefaultTemplateArgument(*this, TPC, + NewTemplateParm->getLocation(), + NewTemplateParm->getDefaultArgument().getSourceRange())) + NewTemplateParm->setDefaultArgument(TemplateArgumentLoc()); + + // Merge default arguments for template template parameters TemplateTemplateParmDecl *OldTemplateParm = OldParams? cast(*OldParam) : 0; if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && @@ -1049,6 +1262,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // template-ids will match up with the template parameter lists. llvm::SmallVector TemplateIdsInSpecifier; + llvm::SmallVector + ExplicitSpecializationsInSpecifier; for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) { if (const TemplateSpecializationType *SpecType @@ -1062,10 +1277,10 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, = cast(Record->getDecl()); // If the nested name specifier refers to an explicit specialization, // we don't need a template<> header. - // FIXME: revisit this approach once we cope with specializations - // properly. - if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) + if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { + ExplicitSpecializationsInSpecifier.push_back(SpecDecl); continue; + } } TemplateIdsInSpecifier.push_back(SpecType); @@ -1128,6 +1343,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, ExpectedTemplateParams, true, TPL_TemplateMatch); } + + CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember); } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), diag::err_template_param_list_matches_nontemplate) @@ -1146,10 +1363,20 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // If there were too many template parameter lists, complain about that now. if (Idx != NumParamLists - 1) { while (Idx < NumParamLists - 1) { + bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0; Diag(ParamLists[Idx]->getTemplateLoc(), - diag::err_template_spec_extra_headers) + isExplicitSpecHeader? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) << SourceRange(ParamLists[Idx]->getTemplateLoc(), ParamLists[Idx]->getRAngleLoc()); + + if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) { + Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(), + diag::note_explicit_template_spec_does_not_need_header) + << ExplicitSpecializationsInSpecifier.back(); + ExplicitSpecializationsInSpecifier.pop_back(); + } + ++Idx; } } @@ -1161,24 +1388,19 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { + const TemplateArgumentListInfo &TemplateArgs) { TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { // The template name does not resolve to a template, so we just // build a dependent template-id type. - return Context.getTemplateSpecializationType(Name, TemplateArgs, - NumTemplateArgs); + return Context.getTemplateSpecializationType(Name, TemplateArgs); } // Check that the template argument list is well-formed for this // template. TemplateArgumentListBuilder Converted(Template->getTemplateParameters(), - NumTemplateArgs); - if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, - TemplateArgs, NumTemplateArgs, RAngleLoc, + TemplateArgs.size()); + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, Converted)) return QualType(); @@ -1190,8 +1412,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, - NumTemplateArgs)) { + TemplateArgs)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -1240,8 +1461,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, - NumTemplateArgs, CanonType); + return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); } Action::TypeResult @@ -1252,13 +1472,10 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, TemplateName Template = TemplateD.getAsVal(); // Translate the parser's template argument list in our AST format. - llvm::SmallVector TemplateArgs; + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc, - TemplateArgs.data(), - TemplateArgs.size(), - RAngleLoc); + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); TemplateArgsIn.release(); if (Result.isNull()) @@ -1310,64 +1527,72 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, return ElabType.getAsOpaquePtr(); } -Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { +Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo &TemplateArgs) { // FIXME: Can we do any checking at this point? I guess we could check the // template arguments that we have against the template name, if the template // name refers to a single template. That's not a terribly common case, // though. - - // Cope with an implicit member access in a C++ non-static member function. - NamedDecl *D = Template.getAsTemplateDecl(); - if (!D) - D = Template.getAsOverloadedFunctionDecl(); - - CXXScopeSpec SS; - SS.setRange(QualifierRange); - SS.setScopeRep(Qualifier); - QualType ThisType, MemberType; - if (D && isImplicitMemberReference(&SS, D, TemplateNameLoc, - ThisType, MemberType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - return Owned(MemberExpr::Create(Context, This, true, - Qualifier, QualifierRange, - D, TemplateNameLoc, true, - LAngleLoc, TemplateArgs, - NumTemplateArgs, RAngleLoc, - Context.OverloadTy)); + + // These should be filtered out by our callers. + assert(!R.empty() && "empty lookup results when building templateid"); + assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); + + NestedNameSpecifier *Qualifier = 0; + SourceRange QualifierRange; + if (SS.isSet()) { + Qualifier = static_cast(SS.getScopeRep()); + QualifierRange = SS.getRange(); } - return Owned(TemplateIdRefExpr::Create(Context, Context.OverloadTy, - Qualifier, QualifierRange, - Template, TemplateNameLoc, LAngleLoc, - TemplateArgs, - NumTemplateArgs, RAngleLoc)); + bool Dependent + = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), + &TemplateArgs); + UnresolvedLookupExpr *ULE + = UnresolvedLookupExpr::Create(Context, Dependent, + Qualifier, QualifierRange, + R.getLookupName(), R.getNameLoc(), + RequiresADL, TemplateArgs); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + ULE->addDecl(*I); + + return Owned(ULE); } -Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, - TemplateTy TemplateD, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation RAngleLoc) { - TemplateName Template = TemplateD.getAsVal(); +// We actually only call this from template instantiation. +Sema::OwningExprResult +Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo &TemplateArgs) { + DeclContext *DC; + if (!(DC = computeDeclContext(SS, false)) || + DC->isDependentContext() || + RequireCompleteDeclContext(SS)) + return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); + + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); + LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false); + + if (R.isAmbiguous()) + return ExprError(); + + if (R.empty()) { + Diag(NameLoc, diag::err_template_kw_refers_to_non_template) + << Name << SS.getRange(); + return ExprError(); + } - // Translate the parser's template argument list in our AST format. - llvm::SmallVector TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgs); - TemplateArgsIn.release(); + if (ClassTemplateDecl *Temp = R.getAsSingle()) { + Diag(NameLoc, diag::err_template_kw_refers_to_class_template) + << (NestedNameSpecifier*) SS.getScopeRep() << Name << SS.getRange(); + Diag(Temp->getLocation(), diag::note_referenced_class_template); + return ExprError(); + } - return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), - SS.getRange(), - Template, TemplateNameLoc, LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc); + return BuildTemplateIdExpr(SS, R, /* ADL */ false, TemplateArgs); } /// \brief Form a dependent template name. @@ -1381,10 +1606,11 @@ Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, - TypeTy *ObjectType) { + TypeTy *ObjectType, + bool EnteringContext) { if ((ObjectType && computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || - (SS.isSet() && computeDeclContext(SS, false))) { + (SS.isSet() && computeDeclContext(SS, EnteringContext))) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1403,7 +1629,7 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, - false, Template); + EnteringContext, Template); if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) @@ -1426,7 +1652,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, case UnqualifiedId::IK_OperatorFunctionId: return TemplateTy::make(Context.getDependentTemplateName(Qualifier, Name.OperatorFunctionId.Operator)); - + + case UnqualifiedId::IK_LiteralOperatorId: + assert(false && "We don't support these; Parse shouldn't have allowed propagation"); + default: break; } @@ -1609,6 +1838,65 @@ SubstDefaultTemplateArgument(Sema &SemaRef, AllTemplateArgs); } +/// \brief If the given template parameter has a default template +/// argument, substitute into that default template argument and +/// return the corresponding template argument. +TemplateArgumentLoc +Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + TemplateArgumentListBuilder &Converted) { + if (TemplateTypeParmDecl *TypeParm = dyn_cast(Param)) { + if (!TypeParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TypeParm, + Converted); + if (DI) + return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + + return TemplateArgumentLoc(); + } + + if (NonTypeTemplateParmDecl *NonTypeParm + = dyn_cast(Param)) { + if (!NonTypeParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + OwningExprResult Arg = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + NonTypeParm, + Converted); + if (Arg.isInvalid()) + return TemplateArgumentLoc(); + + Expr *ArgE = Arg.takeAs(); + return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE); + } + + TemplateTemplateParmDecl *TempTempParm + = cast(Param); + if (!TempTempParm->hasDefaultArgument()) + return TemplateArgumentLoc(); + + TemplateName TName = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TempTempParm, + Converted); + if (TName.isNull()) + return TemplateArgumentLoc(); + + return TemplateArgumentLoc(TemplateArgument(TName), + TempTempParm->getDefaultArgument().getTemplateQualifierRange(), + TempTempParm->getDefaultArgument().getTemplateNameLoc()); +} + /// \brief Check that the given template argument corresponds to the given /// template parameter. bool Sema::CheckTemplateArgument(NamedDecl *Param, @@ -1679,12 +1967,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, // parsed as a template template argument. However, since we now // know that we need a non-type template argument, convert this // template name into an expression. - Expr *E = new (Context) UnresolvedDeclRefExpr(DTN->getIdentifier(), - Context.DependentTy, - Arg.getTemplateNameLoc(), + Expr *E = DependentScopeDeclRefExpr::Create(Context, + DTN->getQualifier(), Arg.getTemplateQualifierRange(), - DTN->getQualifier(), - /*isAddressOfOperand=*/false); + DTN->getIdentifier(), + Arg.getTemplateNameLoc()); TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) @@ -1798,17 +2085,16 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc, + const TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); - unsigned NumArgs = NumTemplateArgs; + unsigned NumArgs = TemplateArgs.size(); bool Invalid = false; + SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc(); + bool HasParameterPack = NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); @@ -2048,7 +2334,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast(DRE->getDecl())) { - if (Func->getStorageClass() == FunctionDecl::Static) { + if (Func->getLinkage() != NamedDecl::ExternalLinkage) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); @@ -2063,7 +2349,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, } if (VarDecl *Var = dyn_cast(DRE->getDecl())) { - if (!Var->hasGlobalStorage()) { + if (Var->getLinkage() != NamedDecl::ExternalLinkage) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); @@ -3046,16 +3332,17 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } // Translate the parser's template argument list in our AST format. - llvm::SmallVector TemplateArgs; + TemplateArgumentListInfo TemplateArgs; + TemplateArgs.setLAngleLoc(LAngleLoc); + TemplateArgs.setRAngleLoc(RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); // Check that the template argument list is well-formed for this // template. TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), TemplateArgs.size()); - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, false, Converted)) + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, + TemplateArgs, false, Converted)) return true; assert((Converted.structuredSize() == @@ -3154,8 +3441,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParams, ClassTemplate, Converted, - TemplateArgs.data(), - TemplateArgs.size(), + TemplateArgs, PrevPartial); if (PrevPartial) { @@ -3267,10 +3553,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // name based on the "canonical" representation used to store the // template arguments in the specialization. QualType WrittenTy - = Context.getTemplateSpecializationType(Name, - TemplateArgs.data(), - TemplateArgs.size(), - CanonType); + = Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); if (TUK != TUK_Friend) Specialization->setTypeAsWritten(WrittenTy); TemplateArgsIn.release(); @@ -3533,11 +3816,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, /// \param PrevDecl the set of declarations that bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, + const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. @@ -3564,9 +3843,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, + = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FD->getType(), Specialization, Info)) { @@ -3589,7 +3866,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, PartialDiagnostic(diag::err_function_template_spec_no_match) << FD->getDeclName(), PartialDiagnostic(diag::err_function_template_spec_ambiguous) - << FD->getDeclName() << HasExplicitTemplateArgs, + << FD->getDeclName() << (ExplicitTemplateArgs != 0), PartialDiagnostic(diag::note_function_template_spec_matched)); if (!Specialization) return true; @@ -3901,16 +4178,15 @@ Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; // Translate the parser's template argument list in our AST format. - llvm::SmallVector TemplateArgs; + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); // Check that the template argument list is well-formed for this // template. TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), TemplateArgs.size()); - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, false, Converted)) + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, + TemplateArgs, false, Converted)) return true; assert((Converted.structuredSize() == @@ -3938,6 +4214,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplateSpecializationDecl *Specialization = 0; + bool ReusedDecl = false; if (PrevDecl) { bool SuppressNew = false; if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK, @@ -3959,6 +4236,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization = PrevDecl; Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; + ReusedDecl = true; } } @@ -3991,18 +4269,18 @@ Sema::ActOnExplicitInstantiation(Scope *S, // on the "canonical" representation used to store the template // arguments in the specialization. QualType WrittenTy - = Context.getTemplateSpecializationType(Name, - TemplateArgs.data(), - TemplateArgs.size(), + = Context.getTemplateSpecializationType(Name, TemplateArgs, Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); TemplateArgsIn.release(); - // Add the explicit instantiation into its lexical context. However, - // since explicit instantiations are never found by name lookup, we - // just put it into the declaration context directly. - Specialization->setLexicalDeclContext(CurContext); - CurContext->addDecl(Specialization); + if (!ReusedDecl) { + // Add the explicit instantiation into its lexical context. However, + // since explicit instantiations are never found by name lookup, we + // just put it into the declaration context directly. + Specialization->setLexicalDeclContext(CurContext); + CurContext->addDecl(Specialization); + } // C++ [temp.explicit]p3: // A definition of a class template or class member template @@ -4277,14 +4555,15 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector TemplateArgs; + TemplateArgumentListInfo TemplateArgs; if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); HasExplicitTemplateArgs = true; TemplateArgsPtr.release(); } @@ -4315,8 +4594,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs, - TemplateArgs.data(), TemplateArgs.size(), + = DeduceTemplateArguments(FunTmpl, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? (void)TDK; @@ -4365,12 +4644,12 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (SuppressNew) return DeclPtrTy(); } + + Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, false, /*DefinitionRequired=*/true); - - Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); // C++0x [temp.explicit]p2: // If the explicit instantiation is for a member function, a member class @@ -4537,7 +4816,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, namespace { // See Sema::RebuildTypeInCurrentInstantiation - class VISIBILITY_HIDDEN CurrentInstantiationRebuilder + class CurrentInstantiationRebuilder : public TreeTransform { SourceLocation Loc; DeclarationName Entity; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 10594c7..613ffde 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -17,7 +17,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/Parse/DeclSpec.h" -#include "llvm/Support/Compiler.h" #include namespace clang { @@ -1050,35 +1049,34 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); unsigned N = Partial->getNumTemplateArgsAsWritten(); - llvm::SmallVector InstArgs(N); + + // Note that we don't provide the langle and rangle locations. + TemplateArgumentListInfo InstArgs; + for (unsigned I = 0; I != N; ++I) { Decl *Param = const_cast( ClassTemplate->getTemplateParameters()->getParam(I)); - if (Subst(PartialTemplateArgs[I], InstArgs[I], + TemplateArgumentLoc InstArg; + if (Subst(PartialTemplateArgs[I], InstArg, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I].getArgument(); return TDK_SubstitutionFailure; } + InstArgs.addArgument(InstArg); } TemplateArgumentListBuilder ConvertedInstArgs( ClassTemplate->getTemplateParameters(), N); if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - /*LAngle*/ SourceLocation(), - InstArgs.data(), N, - /*RAngle*/ SourceLocation(), - false, ConvertedInstArgs)) { + InstArgs, false, ConvertedInstArgs)) { // FIXME: fail with more useful information? return TDK_SubstitutionFailure; } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { - // We don't really care if we overwrite the internal structures of - // the arg list builder, because we're going to throw it all away. - TemplateArgument &InstArg - = const_cast(ConvertedInstArgs.getFlatArguments()[I]); + TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I]; Decl *Param = const_cast( ClassTemplate->getTemplateParameters()->getParam(I)); @@ -1130,9 +1128,6 @@ static bool isSimpleTemplateIdType(QualType T) { /// \param ExplicitTemplateArguments the explicitly-specified template /// arguments. /// -/// \param NumExplicitTemplateArguments the number of explicitly-specified -/// template arguments in @p ExplicitTemplateArguments. This value may be zero. -/// /// \param Deduced the deduced template arguments, which will be populated /// with the converted and checked explicit template arguments. /// @@ -1151,8 +1146,7 @@ static bool isSimpleTemplateIdType(QualType T) { Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo &ExplicitTemplateArgs, llvm::SmallVectorImpl &Deduced, llvm::SmallVectorImpl &ParamTypes, QualType *FunctionType, @@ -1161,7 +1155,7 @@ Sema::SubstituteExplicitTemplateArguments( TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - if (NumExplicitTemplateArgs == 0) { + if (ExplicitTemplateArgs.size() == 0) { // No arguments to substitute; just copy over the parameter types and // fill in the function type. for (FunctionDecl::param_iterator P = Function->param_begin(), @@ -1185,7 +1179,7 @@ Sema::SubstituteExplicitTemplateArguments( // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. TemplateArgumentListBuilder Builder(TemplateParams, - NumExplicitTemplateArgs); + ExplicitTemplateArgs.size()); // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -1197,10 +1191,8 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, - SourceLocation(), SourceLocation(), - ExplicitTemplateArgs, - NumExplicitTemplateArgs, SourceLocation(), + ExplicitTemplateArgs, true, Builder) || Trap.hasErrorOccurred()) return TDK_InvalidExplicitArguments; @@ -1279,18 +1271,56 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Enter a new template instantiation context while we instantiate the + // actual function declaration. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - if (Deduced[I].isNull()) { + if (!Deduced[I].isNull()) { + Builder.Append(Deduced[I]); + continue; + } + + // Substitute into the default template argument, if available. + NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); + TemplateArgumentLoc DefArg + = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Param, + Builder); + + // If there was no default argument, deduction is incomplete. + if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( - const_cast(TemplateParams->getParam(I))); + const_cast(TemplateParams->getParam(I))); return TDK_Incomplete; } + + // Check whether we can actually use the default argument. + if (CheckTemplateArgument(Param, DefArg, + FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Builder)) { + Info.Param = makeTemplateParameter( + const_cast(TemplateParams->getParam(I))); + return TDK_SubstitutionFailure; + } - Builder.Append(Deduced[I]); + // If we get here, we successfully used the default template argument. } // Form the template argument list from the deduced template arguments. @@ -1298,18 +1328,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); Info.reset(DeducedArgumentList); - // Template argument deduction for function templates in a SFINAE context. - // Trap any errors that might occur. - SFINAETrap Trap(*this); - - // Enter a new template instantiation context while we instantiate the - // actual function declaration. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. Specialization = cast_or_null( @@ -1368,9 +1386,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -1398,11 +1414,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, = FunctionTemplate->getTemplateParameters(); llvm::SmallVector Deduced; llvm::SmallVector ParamTypes; - if (NumExplicitTemplateArgs) { + if (ExplicitTemplateArgs) { TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, + *ExplicitTemplateArgs, Deduced, ParamTypes, 0, @@ -1538,9 +1553,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - bool HasExplicitTemplateArgs, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -1552,11 +1565,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Substitute any explicit template arguments. llvm::SmallVector Deduced; llvm::SmallVector ParamTypes; - if (HasExplicitTemplateArgs) { + if (ExplicitTemplateArgs) { if (TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, + *ExplicitTemplateArgs, Deduced, ParamTypes, &FunctionType, Info)) return Result; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 58fe59e..623cde8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -12,13 +12,13 @@ #include "Sema.h" #include "TreeTransform.h" +#include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" #include "clang/Basic/LangOptions.h" -#include "llvm/Support/Compiler.h" using namespace clang; @@ -491,7 +491,7 @@ bool Sema::isSFINAEContext() const { // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { - class VISIBILITY_HIDDEN TemplateInstantiator + class TemplateInstantiator : public TreeTransform { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; @@ -743,7 +743,6 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, = SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), E->getLocation(), - /*FIXME:*/false, /*FIXME:*/false, &SS); if (RefExpr.isInvalid()) return SemaRef.ExprError(); @@ -755,8 +754,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, } return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), - E->getLocation(), - /*FIXME:*/false, /*FIXME:*/false); + E->getLocation()); } assert(Arg.getKind() == TemplateArgument::Integral); @@ -788,46 +786,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, if (!InstD) return SemaRef.ExprError(); - // Flatten using declarations into their shadow declarations. - if (isa(InstD)) { - UsingDecl *UD = cast(InstD); - - bool HasNonFunction = false; - - llvm::SmallVector Decls; - for (UsingDecl::shadow_iterator I = UD->shadow_begin(), - E = UD->shadow_end(); I != E; ++I) { - NamedDecl *TD = (*I)->getTargetDecl(); - if (!TD->isFunctionOrFunctionTemplate()) - HasNonFunction = true; - - Decls.push_back(TD); - } - - if (Decls.empty()) - return SemaRef.ExprError(); - - if (Decls.size() == 1) - InstD = Decls[0]; - else if (!HasNonFunction) { - OverloadedFunctionDecl *OFD - = OverloadedFunctionDecl::Create(SemaRef.Context, - UD->getDeclContext(), - UD->getDeclName()); - for (llvm::SmallVectorImpl::iterator I = Decls.begin(), - E = Decls.end(); I != E; ++I) - if (isa(*I)) - OFD->addOverload(cast(*I)); - else - OFD->addOverload(cast(*I)); - - InstD = OFD; - } else { - // FIXME - assert(false && "using declaration resolved to mixed set"); - return SemaRef.ExprError(); - } - } + assert(!isa(InstD) && "decl ref instantiated to UsingDecl"); CXXScopeSpec SS; NestedNameSpecifier *Qualifier = 0; @@ -841,10 +800,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, SS.setRange(E->getQualifierRange()); } - return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD, - /*FIXME:*/false, - &SS, - isAddressOfOperand); + return SemaRef.BuildDeclarationNameExpr(SS, E->getLocation(), InstD); } Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3f40ffc..a125857 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -18,12 +18,11 @@ #include "clang/AST/Expr.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/Support/Compiler.h" using namespace clang; namespace { - class VISIBILITY_HIDDEN TemplateDeclInstantiator + class TemplateDeclInstantiator : public DeclVisitor { Sema &SemaRef; DeclContext *Owner; @@ -205,6 +204,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // we don't want to redo all the checking, especially since the // initializer might have been wrapped by a CXXConstructExpr since we did // it the first time. + Var->setType(D->getType()); Var->setInit(SemaRef.Context, Init.takeAs()); } else if (ParenListExpr *PLE = dyn_cast((Expr *)Init.get())) { @@ -1153,11 +1153,12 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( = PartialSpec->getTemplateArgsAsWritten(); unsigned N = PartialSpec->getNumTemplateArgsAsWritten(); - llvm::SmallVector InstTemplateArgs(N); + TemplateArgumentListInfo InstTemplateArgs; // no angle locations for (unsigned I = 0; I != N; ++I) { - if (SemaRef.Subst(PartialSpecTemplateArgs[I], InstTemplateArgs[I], - TemplateArgs)) + TemplateArgumentLoc Loc; + if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs)) return true; + InstTemplateArgs.addArgument(Loc); } @@ -1167,10 +1168,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstTemplateArgs.size()); if (SemaRef.CheckTemplateArgumentList(ClassTemplate, PartialSpec->getLocation(), - /*FIXME:*/PartialSpec->getLocation(), - InstTemplateArgs.data(), - InstTemplateArgs.size(), - /*FIXME:*/PartialSpec->getLocation(), + InstTemplateArgs, false, Converted)) return true; @@ -1203,8 +1201,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // template arguments in the specialization. QualType WrittenTy = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - InstTemplateArgs.data(), - InstTemplateArgs.size(), + InstTemplateArgs, CanonType); if (PrevDecl) { @@ -1238,8 +1235,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstParams, ClassTemplate, Converted, - InstTemplateArgs.data(), - InstTemplateArgs.size(), + InstTemplateArgs, 0); InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); @@ -1887,22 +1883,6 @@ DeclContext *Sema::FindInstantiatedContext(DeclContext* DC, /// this mapping from within the instantiation of X. NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs) { - if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { - // Transform all of the elements of the overloaded function set. - OverloadedFunctionDecl *Result - = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName()); - - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - Result->addOverload( - AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F, - TemplateArgs))); - } - - return Result; - } - DeclContext *ParentDC = D->getDeclContext(); if (isa(D) || isa(D) || isa(D) || isa(D) || diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 00dc809..afce5e3 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -879,6 +879,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (D.getName().getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(D, *this); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ca680c2..28b2174 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_SEMA_TREETRANSFORM_H #include "Sema.h" +#include "Lookup.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" @@ -94,7 +95,8 @@ public: typedef Sema::ExprArg ExprArg; typedef Sema::MultiExprArg MultiExprArg; typedef Sema::MultiStmtArg MultiStmtArg; - + typedef Sema::DeclPtrTy DeclPtrTy; + /// \brief Initializes a new tree transformer. TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } @@ -503,10 +505,7 @@ public: /// different behavior. QualType RebuildTemplateSpecializationType(TemplateName Template, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *Args, - unsigned NumArgs, - SourceLocation RAngleLoc); + const TemplateArgumentListInfo &Args); /// \brief Build a new qualified name type. /// @@ -584,16 +583,6 @@ public: bool TemplateKW, TemplateDecl *Template); - /// \brief Build a new template name given a nested name specifier, a flag - /// indicating whether the "template" keyword was provided, and a set of - /// overloaded function templates. - /// - /// By default, builds the new template name directly. Subclasses may override - /// this routine to provide different behavior. - TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, - bool TemplateKW, - OverloadedFunctionDecl *Ovl); - /// \brief Build a new template name given a nested name specifier and the /// name that is referred to as a template. /// @@ -677,17 +666,19 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, - StmtArg Then, SourceLocation ElseLoc, - StmtArg Else) { - return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else)); + VarDecl *CondVar, StmtArg Then, + SourceLocation ElseLoc, StmtArg Else) { + return getSema().ActOnIfStmt(IfLoc, Cond, DeclPtrTy::make(CondVar), + move(Then), ElseLoc, move(Else)); } /// \brief Start building a new switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) { - return getSema().ActOnStartOfSwitchStmt(move(Cond)); + OwningStmtResult RebuildSwitchStmtStart(Sema::FullExprArg Cond, + VarDecl *CondVar) { + return getSema().ActOnStartOfSwitchStmt(Cond, DeclPtrTy::make(CondVar)); } /// \brief Attach the body to the switch statement. @@ -706,8 +697,10 @@ public: /// Subclasses may override this routine to provide different behavior. OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond, + VarDecl *CondVar, StmtArg Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body)); + return getSema().ActOnWhileStmt(WhileLoc, Cond, DeclPtrTy::make(CondVar), + move(Body)); } /// \brief Build a new do-while statement. @@ -729,10 +722,12 @@ public: /// Subclasses may override this routine to provide different behavior. OwningStmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg Init, ExprArg Cond, ExprArg Inc, + StmtArg Init, Sema::FullExprArg Cond, + VarDecl *CondVar, Sema::FullExprArg Inc, SourceLocation RParenLoc, StmtArg Body) { - return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond), - move(Inc), RParenLoc, move(Body)); + return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), Cond, + DeclPtrTy::make(CondVar), + Inc, RParenLoc, move(Body)); } /// \brief Build a new goto statement. @@ -818,6 +813,17 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool RequiresADL) { + return getSema().BuildDeclarationNameExpr(SS, R, RequiresADL); + } + + + /// \brief Build a new expression that references a declaration. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *ND, SourceLocation Loc, @@ -861,13 +867,10 @@ public: = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType)); - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), - OperatorLoc, - isArrow? tok::arrow : tok::period, - DestroyedTypeLoc, - Name, - Sema::DeclPtrTy::make((Decl *)0), - &SS); + return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow, + SS, /*FIXME: FirstQualifier*/ 0, + Name, DestroyedTypeLoc, + /*TemplateArgs*/ 0); } /// \brief Build a new unary operator expression. @@ -942,11 +945,7 @@ public: SourceRange QualifierRange, SourceLocation MemberLoc, NamedDecl *Member, - bool HasExplicitTemplateArgs, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *ExplicitTemplateArgs, - unsigned NumExplicitTemplateArgs, - SourceLocation RAngleLoc, + const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { // We have a reference to an unnamed field. @@ -965,18 +964,10 @@ public: SS.setScopeRep(Qualifier); } - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, - isArrow? tok::arrow : tok::period, - MemberLoc, - Member->getDeclName(), - HasExplicitTemplateArgs, - LAngleLoc, - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - RAngleLoc, - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS, - FirstQualifierInScope); + return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow, + SS, FirstQualifierInScope, + Member->getDeclName(), MemberLoc, + ExplicitTemplateArgs); } /// \brief Build a new binary operator expression. @@ -1051,10 +1042,13 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, - tok::period, AccessorLoc, + CXXScopeSpec SS; + return getSema().BuildMemberReferenceExpr(move(Base), + OpLoc, /*IsArrow*/ false, + SS, /*FirstQualifierInScope*/ 0, DeclarationName(&Accessor), - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + AccessorLoc, + /* TemplateArgs */ 0); } /// \brief Build a new initializer list expression. @@ -1122,7 +1116,8 @@ public: OwningExprResult RebuildParenListExpr(SourceLocation LParenLoc, MultiExprArg SubExprs, SourceLocation RParenLoc) { - return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs)); + return getSema().ActOnParenOrParenListExpr(LParenLoc, RParenLoc, + move(SubExprs)); } /// \brief Build a new address-of-label expression. @@ -1383,18 +1378,6 @@ public: 0, RParenLoc); } - /// \brief Build a new C++ conditional declaration expression. - /// - /// By default, performs semantic analysis to build the new expression. - /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXConditionDeclExpr(SourceLocation StartLoc, - SourceLocation EqLoc, - VarDecl *Var) { - return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr(StartLoc, - EqLoc, - Var)); - } - /// \brief Build a new C++ "new" expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1456,39 +1439,31 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildUnresolvedDeclRefExpr(NestedNameSpecifier *NNS, + OwningExprResult RebuildDependentScopeDeclRefExpr(NestedNameSpecifier *NNS, SourceRange QualifierRange, DeclarationName Name, SourceLocation Location, - bool IsAddressOfOperand) { + const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(NNS); - return getSema().ActOnDeclarationNameExpr(/*Scope=*/0, - Location, - Name, - /*Trailing lparen=*/false, - &SS, - IsAddressOfOperand); + + if (TemplateArgs) + return getSema().BuildQualifiedTemplateIdExpr(SS, Name, Location, + *TemplateArgs); + + return getSema().BuildQualifiedDeclarationNameExpr(SS, Name, Location); } /// \brief Build a new template-id expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildTemplateIdExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { - return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange, - Template, TemplateLoc, - LAngleLoc, - TemplateArgs, NumTemplateArgs, - RAngleLoc); + OwningExprResult RebuildTemplateIdExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo &TemplateArgs) { + return getSema().BuildTemplateIdExpr(SS, R, RequiresADL, TemplateArgs); } /// \brief Build a new object-construction expression. @@ -1546,76 +1521,43 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE, + OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation MemberLoc, - NamedDecl *FirstQualifierInScope) { - OwningExprResult Base = move(BaseE); - tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; - + const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, - move(Base), OperatorLoc, OpKind, - MemberLoc, - Name, - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS, - FirstQualifierInScope); + return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow, + SS, FirstQualifierInScope, + Name, MemberLoc, TemplateArgs); } - /// \brief Build a new member reference expression with explicit template - /// arguments. + /// \brief Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE, - bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - NamedDecl *FirstQualifierInScope, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - SourceLocation RAngleLoc) { + OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE, + SourceLocation OperatorLoc, + bool IsArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { OwningExprResult Base = move(BaseE); - tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - // FIXME: We're going to end up looking up the template based on its name, - // twice! Also, duplicates part of Sema::BuildMemberAccessExpr. - DeclarationName Name; - if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) - Name = ActualTemplate->getDeclName(); - else if (OverloadedFunctionDecl *Ovl - = Template.getAsOverloadedFunctionDecl()) - Name = Ovl->getDeclName(); - else { - DependentTemplateName *DTN = Template.getAsDependentTemplateName(); - if (DTN->isIdentifier()) - Name = DTN->getIdentifier(); - else - Name = SemaRef.Context.DeclarationNames.getCXXOperatorName( - DTN->getOperator()); - } - return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), - OperatorLoc, OpKind, - TemplateNameLoc, Name, true, - LAngleLoc, TemplateArgs, - NumTemplateArgs, RAngleLoc, - Sema::DeclPtrTy(), &SS); + return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow, + SS, R, TemplateArgs); } /// \brief Build a new Objective-C @encode expression. @@ -1664,7 +1606,7 @@ public: FunctionDecl *Builtin = cast(*Lookup.first); Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), - BuiltinLoc, false, false); + BuiltinLoc); SemaRef.UsualUnaryConversions(Callee); // Build the CallExpr @@ -1825,6 +1767,7 @@ TreeTransform::TransformDeclarationName(DeclarationName Name, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: return Name; @@ -1878,20 +1821,8 @@ TreeTransform::TransformTemplateName(TemplateName Name, TransTemplate); } - OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl(); - assert(Ovl && "Not a template name or an overload set?"); - OverloadedFunctionDecl *TransOvl - = cast_or_null(getDerived().TransformDecl(Ovl)); - if (!TransOvl) - return TemplateName(); - - if (!getDerived().AlwaysRebuild() && - NNS == QTN->getQualifier() && - TransOvl == Ovl) - return Name; - - return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), - TransOvl); + // These should be getting filtered out before they make it into the AST. + assert(false && "overloaded template name survived to here"); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { @@ -1927,18 +1858,9 @@ TreeTransform::TransformTemplateName(TemplateName Name, return TemplateName(TransTemplate); } - OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl(); - assert(Ovl && "Not a template name or an overload set?"); - OverloadedFunctionDecl *TransOvl - = cast_or_null(getDerived().TransformDecl(Ovl)); - if (!TransOvl) - return TemplateName(); - - if (!getDerived().AlwaysRebuild() && - TransOvl == Ovl) - return Name; - - return TemplateName(TransOvl); + // These should be getting filtered out before they reach the AST. + assert(false && "overloaded function decl survived to here"); + return TemplateName(); } template @@ -2879,21 +2801,23 @@ QualType TreeTransform::TransformTemplateSpecializationType( if (Template.isNull()) return QualType(); - llvm::SmallVector NewTemplateArgs(T->getNumArgs()); - for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) - if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), - NewTemplateArgs[i])) + TemplateArgumentListInfo NewTemplateArgs; + NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); + NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), Loc)) return QualType(); + NewTemplateArgs.addArgument(Loc); + } // FIXME: maybe don't rebuild if all the template arguments are the same. QualType Result = getDerived().RebuildTemplateSpecializationType(Template, TL.getTemplateNameLoc(), - TL.getLAngleLoc(), - NewTemplateArgs.data(), - NewTemplateArgs.size(), - TL.getRAngleLoc()); + NewTemplateArgs); if (!Result.isNull()) { TemplateSpecializationTypeLoc NewTL @@ -3103,10 +3027,21 @@ template Sema::OwningStmtResult TreeTransform::TransformIfStmt(IfStmt *S) { // Transform the condition - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); - + OwningExprResult Cond(SemaRef); + VarDecl *ConditionVar = 0; + if (S->getConditionVariable()) { + ConditionVar + = cast_or_null( + getDerived().TransformDefinition(S->getConditionVariable())); + if (!ConditionVar) + return SemaRef.StmtError(); + } else { + Cond = getDerived().TransformExpr(S->getCond()); + + if (Cond.isInvalid()) + return SemaRef.StmtError(); + } + Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); // Transform the "then" branch. @@ -3121,11 +3056,13 @@ TreeTransform::TransformIfStmt(IfStmt *S) { if (!getDerived().AlwaysRebuild() && FullCond->get() == S->getCond() && + ConditionVar == S->getConditionVariable() && Then.get() == S->getThen() && Else.get() == S->getElse()) return SemaRef.Owned(S->Retain()); - return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then), + return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar, + move(Then), S->getElseLoc(), move(Else)); } @@ -3133,12 +3070,26 @@ template Sema::OwningStmtResult TreeTransform::TransformSwitchStmt(SwitchStmt *S) { // Transform the condition. - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); + OwningExprResult Cond(SemaRef); + VarDecl *ConditionVar = 0; + if (S->getConditionVariable()) { + ConditionVar + = cast_or_null( + getDerived().TransformDefinition(S->getConditionVariable())); + if (!ConditionVar) + return SemaRef.StmtError(); + } else { + Cond = getDerived().TransformExpr(S->getCond()); + + if (Cond.isInvalid()) + return SemaRef.StmtError(); + } + Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); + // Rebuild the switch statement. - OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond)); + OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(FullCond, + ConditionVar); if (Switch.isInvalid()) return SemaRef.StmtError(); @@ -3156,9 +3107,20 @@ template Sema::OwningStmtResult TreeTransform::TransformWhileStmt(WhileStmt *S) { // Transform the condition - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); + OwningExprResult Cond(SemaRef); + VarDecl *ConditionVar = 0; + if (S->getConditionVariable()) { + ConditionVar + = cast_or_null( + getDerived().TransformDefinition(S->getConditionVariable())); + if (!ConditionVar) + return SemaRef.StmtError(); + } else { + Cond = getDerived().TransformExpr(S->getCond()); + + if (Cond.isInvalid()) + return SemaRef.StmtError(); + } Sema::FullExprArg FullCond(getSema().FullExpr(Cond)); @@ -3169,10 +3131,12 @@ TreeTransform::TransformWhileStmt(WhileStmt *S) { if (!getDerived().AlwaysRebuild() && FullCond->get() == S->getCond() && + ConditionVar == S->getConditionVariable() && Body.get() == S->getBody()) return SemaRef.Owned(S->Retain()); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, move(Body)); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, ConditionVar, + move(Body)); } template @@ -3207,9 +3171,20 @@ TreeTransform::TransformForStmt(ForStmt *S) { return SemaRef.StmtError(); // Transform the condition - OwningExprResult Cond = getDerived().TransformExpr(S->getCond()); - if (Cond.isInvalid()) - return SemaRef.StmtError(); + OwningExprResult Cond(SemaRef); + VarDecl *ConditionVar = 0; + if (S->getConditionVariable()) { + ConditionVar + = cast_or_null( + getDerived().TransformDefinition(S->getConditionVariable())); + if (!ConditionVar) + return SemaRef.StmtError(); + } else { + Cond = getDerived().TransformExpr(S->getCond()); + + if (Cond.isInvalid()) + return SemaRef.StmtError(); + } // Transform the increment OwningExprResult Inc = getDerived().TransformExpr(S->getInc()); @@ -3229,7 +3204,9 @@ TreeTransform::TransformForStmt(ForStmt *S) { return SemaRef.Owned(S->Retain()); return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), - move(Init), move(Cond), move(Inc), + move(Init), getSema().FullExpr(Cond), + ConditionVar, + getSema().FullExpr(Inc), S->getRParenLoc(), move(Body)); } @@ -3695,13 +3672,15 @@ TreeTransform::TransformMemberExpr(MemberExpr *E, !E->hasExplicitTemplateArgumentList()) return SemaRef.Owned(E->Retain()); - llvm::SmallVector TransArgs; + TemplateArgumentListInfo TransArgs; if (E->hasExplicitTemplateArgumentList()) { - TransArgs.resize(E->getNumTemplateArgs()); + TransArgs.setLAngleLoc(E->getLAngleLoc()); + TransArgs.setRAngleLoc(E->getRAngleLoc()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], - TransArgs[I])) + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) return SemaRef.ExprError(); + TransArgs.addArgument(Loc); } } @@ -3715,11 +3694,8 @@ TreeTransform::TransformMemberExpr(MemberExpr *E, E->getQualifierRange(), E->getMemberLoc(), Member, - E->hasExplicitTemplateArgumentList(), - E->getLAngleLoc(), - TransArgs.data(), - TransArgs.size(), - E->getRAngleLoc(), + (E->hasExplicitTemplateArgumentList() + ? &TransArgs : 0), 0); } @@ -4425,24 +4401,6 @@ TreeTransform::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, template Sema::OwningExprResult -TreeTransform::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E, - bool isAddressOfOperand) { - VarDecl *Var - = cast_or_null(getDerived().TransformDefinition(E->getVarDecl())); - if (!Var) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - Var == E->getVarDecl()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildCXXConditionDeclExpr(E->getStartLoc(), - /*FIXME:*/E->getStartLoc(), - Var); -} - -template -Sema::OwningExprResult TreeTransform::TransformCXXNewExpr(CXXNewExpr *E, bool isAddressOfOperand) { // Transform the type that we're allocating @@ -4558,11 +4516,66 @@ TreeTransform::TransformCXXPseudoDestructorExpr( template Sema::OwningExprResult -TreeTransform::TransformUnresolvedFunctionNameExpr( - UnresolvedFunctionNameExpr *E, +TreeTransform::TransformUnresolvedLookupExpr( + UnresolvedLookupExpr *Old, bool isAddressOfOperand) { - // There is no transformation we can apply to an unresolved function name. - return SemaRef.Owned(E->Retain()); + TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName()); + + LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), + Sema::LookupOrdinaryName); + + // Transform all the decls. + for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), + E = Old->decls_end(); I != E; ++I) { + NamedDecl *InstD = static_cast(getDerived().TransformDecl(*I)); + if (!InstD) + return SemaRef.ExprError(); + + // Expand using declarations. + if (isa(InstD)) { + UsingDecl *UD = cast(InstD); + for (UsingDecl::shadow_iterator I = UD->shadow_begin(), + E = UD->shadow_end(); I != E; ++I) + R.addDecl(*I); + continue; + } + + R.addDecl(InstD); + } + + // Resolve a kind, but don't do any further analysis. If it's + // ambiguous, the callee needs to deal with it. + R.resolveKind(); + + // Rebuild the nested-name qualifier, if present. + CXXScopeSpec SS; + NestedNameSpecifier *Qualifier = 0; + if (Old->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), + Old->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + + SS.setScopeRep(Qualifier); + SS.setRange(Old->getQualifierRange()); + } + + // If we have no template arguments, it's a normal declaration name. + if (!Old->hasExplicitTemplateArgs()) + return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL()); + + // If we have template arguments, rebuild them, then rebuild the + // templateid expression. + TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); + for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], Loc)) + return SemaRef.ExprError(); + TransArgs.addArgument(Loc); + } + + return getDerived().RebuildTemplateIdExpr(SS, R, Old->requiresADL(), + TransArgs); } template @@ -4592,8 +4605,8 @@ TreeTransform::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, template Sema::OwningExprResult -TreeTransform::TransformUnresolvedDeclRefExpr( - UnresolvedDeclRefExpr *E, +TreeTransform::TransformDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E, bool isAddressOfOperand) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), @@ -4606,56 +4619,30 @@ TreeTransform::TransformUnresolvedDeclRefExpr( if (!Name) return SemaRef.ExprError(); - if (!getDerived().AlwaysRebuild() && - NNS == E->getQualifier() && - Name == E->getDeclName()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildUnresolvedDeclRefExpr(NNS, - E->getQualifierRange(), - Name, - E->getLocation(), - isAddressOfOperand); -} - -template -Sema::OwningExprResult -TreeTransform::TransformTemplateIdRefExpr(TemplateIdRefExpr *E, - bool isAddressOfOperand) { - TemporaryBase Rebase(*this, E->getTemplateNameLoc(), DeclarationName()); - - TemplateName Template - = getDerived().TransformTemplateName(E->getTemplateName()); - if (Template.isNull()) - return SemaRef.ExprError(); + if (!E->hasExplicitTemplateArgs()) { + if (!getDerived().AlwaysRebuild() && + NNS == E->getQualifier() && + Name == E->getDeclName()) + return SemaRef.Owned(E->Retain()); - NestedNameSpecifier *Qualifier = 0; - if (E->getQualifier()) { - Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!Qualifier) - return SemaRef.ExprError(); + return getDerived().RebuildDependentScopeDeclRefExpr(NNS, + E->getQualifierRange(), + Name, E->getLocation(), + /*TemplateArgs*/ 0); } - - llvm::SmallVector TransArgs(E->getNumTemplateArgs()); + + TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], - TransArgs[I])) + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) return SemaRef.ExprError(); + TransArgs.addArgument(Loc); } - // FIXME: Would like to avoid rebuilding if nothing changed, but we can't - // compare template arguments (yet). - - // FIXME: It's possible that we'll find out now that the template name - // actually refers to a type, in which case the caller is actually dealing - // with a functional cast. Give a reasonable error message! - return getDerived().RebuildTemplateIdExpr(Qualifier, E->getQualifierRange(), - Template, E->getTemplateNameLoc(), - E->getLAngleLoc(), - TransArgs.data(), - TransArgs.size(), - E->getRAngleLoc()); + return getDerived().RebuildDependentScopeDeclRefExpr(NNS, + E->getQualifierRange(), + Name, E->getLocation(), + &TransArgs); } template @@ -4828,8 +4815,8 @@ TreeTransform::TransformCXXUnresolvedConstructExpr( template Sema::OwningExprResult -TreeTransform::TransformCXXUnresolvedMemberExpr( - CXXUnresolvedMemberExpr *E, +TreeTransform::TransformCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E, bool isAddressOfOperand) { // Transform the base of the expression. OwningExprResult Base = getDerived().TransformExpr(E->getBase()); @@ -4878,52 +4865,99 @@ TreeTransform::TransformCXXUnresolvedMemberExpr( FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), + return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), E->isArrow(), E->getOperatorLoc(), Qualifier, E->getQualifierRange(), + FirstQualifierInScope, Name, E->getMemberLoc(), - FirstQualifierInScope); + /*TemplateArgs*/ 0); } - // FIXME: This is an ugly hack, which forces the same template name to - // be looked up multiple times. Yuck! - TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName()); - TemplateName OrigTemplateName; - if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) - OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II); - else - OrigTemplateName - = SemaRef.Context.getDependentTemplateName(0, - Name.getCXXOverloadedOperator()); - - TemplateName Template - = getDerived().TransformTemplateName(OrigTemplateName, - QualType::getFromOpaquePtr(ObjectType)); - if (Template.isNull()) - return SemaRef.ExprError(); - - llvm::SmallVector TransArgs(E->getNumTemplateArgs()); + TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], - TransArgs[I])) + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) return SemaRef.ExprError(); + TransArgs.addArgument(Loc); } - return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), + return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), E->isArrow(), E->getOperatorLoc(), Qualifier, E->getQualifierRange(), - Template, - E->getMemberLoc(), FirstQualifierInScope, - E->getLAngleLoc(), - TransArgs.data(), - TransArgs.size(), - E->getRAngleLoc()); + Name, + E->getMemberLoc(), + &TransArgs); +} + +template +Sema::OwningExprResult +TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, + bool isAddressOfOperand) { + // Transform the base of the expression. + OwningExprResult Base = getDerived().TransformExpr(Old->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier = 0; + if (Old->getQualifier()) { + Qualifier + = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), + Old->getQualifierRange()); + if (Qualifier == 0) + return SemaRef.ExprError(); + } + + LookupResult R(SemaRef, Old->getMemberName(), Old->getMemberLoc(), + Sema::LookupOrdinaryName); + + // Transform all the decls. + for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), + E = Old->decls_end(); I != E; ++I) { + NamedDecl *InstD = static_cast(getDerived().TransformDecl(*I)); + if (!InstD) + return SemaRef.ExprError(); + + // Expand using declarations. + if (isa(InstD)) { + UsingDecl *UD = cast(InstD); + for (UsingDecl::shadow_iterator I = UD->shadow_begin(), + E = UD->shadow_end(); I != E; ++I) + R.addDecl(*I); + continue; + } + + R.addDecl(InstD); + } + + R.resolveKind(); + + TemplateArgumentListInfo TransArgs; + if (Old->hasExplicitTemplateArgs()) { + TransArgs.setLAngleLoc(Old->getLAngleLoc()); + TransArgs.setRAngleLoc(Old->getRAngleLoc()); + for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], + Loc)) + return SemaRef.ExprError(); + TransArgs.addArgument(Loc); + } + } + + return getDerived().RebuildUnresolvedMemberExpr(move(Base), + Old->getOperatorLoc(), + Old->isArrow(), + Qualifier, + Old->getQualifierRange(), + R, + (Old->hasExplicitTemplateArgs() + ? &TransArgs : 0)); } template @@ -5266,12 +5300,8 @@ template QualType TreeTransform::RebuildTemplateSpecializationType( TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - const TemplateArgumentLoc *Args, - unsigned NumArgs, - SourceLocation RAngleLoc) { - return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, LAngleLoc, - Args, NumArgs, RAngleLoc); + const TemplateArgumentListInfo &TemplateArgs) { + return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); } template @@ -5280,7 +5310,7 @@ TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, IdentifierInfo &II, QualType ObjectType, - NamedDecl *FirstQualifierInScope) { + NamedDecl *FirstQualifierInScope) { CXXScopeSpec SS; // FIXME: The source location information is all wrong. SS.setRange(Range); @@ -5330,14 +5360,6 @@ TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, template TemplateName TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, - bool TemplateKW, - OverloadedFunctionDecl *Ovl) { - return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl); -} - -template -TemplateName -TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, const IdentifierInfo &II, QualType ObjectType) { CXXScopeSpec SS; @@ -5349,7 +5371,8 @@ TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, /*FIXME:*/getDerived().getBaseLocation(), SS, Name, - ObjectType.getAsOpaquePtr()) + ObjectType.getAsOpaquePtr(), + /*EnteringContext=*/false) .template getAsVal(); } @@ -5369,7 +5392,8 @@ TreeTransform::RebuildTemplateName(NestedNameSpecifier *Qualifier, /*FIXME:*/getDerived().getBaseLocation(), SS, Name, - ObjectType.getAsOpaquePtr()) + ObjectType.getAsOpaquePtr(), + /*EnteringContext=*/false) .template getAsVal(); } @@ -5382,8 +5406,7 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, ExprArg Second) { Expr *FirstExpr = (Expr *)First.get(); Expr *SecondExpr = (Expr *)Second.get(); - DeclRefExpr *DRE - = cast(((Expr *)Callee.get())->IgnoreParenCasts()); + Expr *CalleeExpr = ((Expr *)Callee.get())->IgnoreParenCasts(); bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus); // Determine whether this should be a builtin operation. @@ -5391,7 +5414,7 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (!FirstExpr->getType()->isOverloadableType() && !SecondExpr->getType()->isOverloadableType()) return getSema().CreateBuiltinArraySubscriptExpr(move(First), - DRE->getLocStart(), + CalleeExpr->getLocStart(), move(Second), OpLoc); } else if (Op == OO_Arrow) { // -> is never a builtin operation. @@ -5426,10 +5449,18 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // used during overload resolution. Sema::FunctionSet Functions; - // FIXME: Do we have to check - // IsAcceptableNonMemberOperatorCandidate for each of these? - for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F) - Functions.insert(*F); + if (UnresolvedLookupExpr *ULE = dyn_cast(CalleeExpr)) { + assert(ULE->requiresADL()); + + // FIXME: Do we have to check + // IsAcceptableNonMemberOperatorCandidate for each of these? + for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), + E = ULE->decls_end(); I != E; ++I) + Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I)); + } else { + Functions.insert(AnyFunctionDecl::getFromNamedDecl( + cast(CalleeExpr)->getDecl())); + } // Add any functions found via argument-dependent lookup. Expr *Args[2] = { FirstExpr, SecondExpr }; @@ -5447,8 +5478,10 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, } if (Op == OO_Subscript) - return SemaRef.CreateOverloadedArraySubscriptExpr(DRE->getLocStart(), OpLoc, - move(First),move(Second)); + return SemaRef.CreateOverloadedArraySubscriptExpr(CalleeExpr->getLocStart(), + OpLoc, + move(First), + move(Second)); // Create the overloaded operator invocation for binary operators. BinaryOperator::Opcode Opc = diff --git a/test/Analysis/MissingDealloc.m b/test/Analysis/MissingDealloc.m index 3942391..21460a1 100644 --- a/test/Analysis/MissingDealloc.m +++ b/test/Analysis/MissingDealloc.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s --verify +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-objc-missing-dealloc '-DIBOutlet=__attribute__((iboutlet))' %s -verify typedef signed char BOOL; @protocol NSObject - (BOOL)isEqual:(id)object; @@ -39,7 +39,7 @@ typedef struct objc_selector *SEL; @end -@implementation TestSELs // no-warning +@implementation TestSELs - (id)init { if( (self = [super init]) ) { a = @selector(a); diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c index fc9e27b..bee337a 100644 --- a/test/Analysis/casts.c +++ b/test/Analysis/casts.c @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region --verify %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // Test if the 'storage' region gets properly initialized after it is cast to // 'struct sockaddr *'. diff --git a/test/Analysis/casts.m b/test/Analysis/casts.m index 4e201bf..69a4260 100644 --- a/test/Analysis/casts.m +++ b/test/Analysis/casts.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic --verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region --verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s // Test function pointer casts. Currently we track function addresses using // loc::FunctionVal. Because casts can be arbitrary, do we need to model diff --git a/test/Analysis/cfref_PR2519.c b/test/Analysis/cfref_PR2519.c index ee1da1f..d9367d4 100644 --- a/test/Analysis/cfref_PR2519.c +++ b/test/Analysis/cfref_PR2519.c @@ -1,7 +1,7 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=range -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=basic -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s typedef unsigned char Boolean; typedef signed long CFIndex; diff --git a/test/Analysis/concrete-address.c b/test/Analysis/concrete-address.c index 31802d0..96080be 100644 --- a/test/Analysis/concrete-address.c +++ b/test/Analysis/concrete-address.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic --verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region --verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s void foo() { int *p = (int*) 0x10000; // Should not crash here. diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index 811ac81..e29eefd 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -1,8 +1,8 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -verify %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -warn-dead-stores -fblocks -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -warn-dead-stores -fblocks -verify %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -warn-dead-stores -fblocks -verify %s void f1() { int k, y; @@ -34,7 +34,7 @@ void f4(int k) { k = 2; // expected-warning {{never read}} } - + void f5() { int x = 4; // no-warning @@ -55,6 +55,24 @@ int f7(int *p) { return 1; } +int f7b(int *p) { + // This is allowed for defensive programming. + p = (0); // no-warning + return 1; +} + +int f7c(int *p) { + // This is allowed for defensive programming. + p = (void*) 0; // no-warning + return 1; +} + +int f7d(int *p) { + // This is allowed for defensive programming. + p = (void*) (0); // no-warning + return 1; +} + int f8(int *p) { extern int *baz(); if ((p = baz())) // expected-warning{{Although the value}} @@ -336,3 +354,19 @@ void f22() { break; } } + +void f23_aux(const char* s); +void f23(int argc, char **argv) { + int shouldLog = (argc > 1); // no-warning + ^{ + if (shouldLog) f23_aux("I did too use it!\n"); + else f23_aux("I shouldn't log. Wait.. d'oh!\n"); + }(); +} + +void f23_pos(int argc, char **argv) { + int shouldLog = (argc > 1); // expected-warning{{Value stored to 'shouldLog' during its initialization is never read}} + ^{ + f23_aux("I did too use it!\n"); + }(); +} diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c index d6bc845..7ea6111 100644 --- a/test/Analysis/fields.c +++ b/test/Analysis/fields.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s --analyzer-store=basic -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s --analyzer-store=region -verify +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify unsigned foo(); typedef struct bf { unsigned x:2; } bf; diff --git a/test/Analysis/misc-ps-64.m b/test/Analysis/misc-ps-64.m index 506dc8b..f520784 100644 --- a/test/Analysis/misc-ps-64.m +++ b/test/Analysis/misc-ps-64.m @@ -1,7 +1,7 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=basic --verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s // - A bunch of misc. failures involving evaluating // these expressions and building CFGs. These tests are here to prevent diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m index 2b99134..2a98234 100644 --- a/test/Analysis/misc-ps-basic-store.m +++ b/test/Analysis/misc-ps-basic-store.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic --verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fblocks %s //--------------------------------------------------------------------------- // Test case 'checkaccess_union' differs for region store and basic store. diff --git a/test/Analysis/misc-ps-eager-assume.m b/test/Analysis/misc-ps-eager-assume.m index 66eb125..e702cb9 100644 --- a/test/Analysis/misc-ps-eager-assume.m +++ b/test/Analysis/misc-ps-eager-assume.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s -analyzer-eagerly-assume +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume // Delta-reduced header stuff (needed for test cases). typedef signed char BOOL; diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m index 49cc593..058c903 100644 --- a/test/Analysis/misc-ps-ranges.m +++ b/test/Analysis/misc-ps-ranges.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s // // main's 'argc' argument is always > 0 diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m index a833a65..7b0d61b 100644 --- a/test/Analysis/misc-ps-region-store-i386.m +++ b/test/Analysis/misc-ps-region-store-i386.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region --verify -fblocks %s +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s // Here is a case where a pointer is treated as integer, invalidated as an // integer, and then used again as a pointer. This test just makes sure diff --git a/test/Analysis/misc-ps-region-store-x86_64.m b/test/Analysis/misc-ps-region-store-x86_64.m index 7e614fd..8c865ab 100644 --- a/test/Analysis/misc-ps-region-store-x86_64.m +++ b/test/Analysis/misc-ps-region-store-x86_64.m @@ -1,4 +1,4 @@ -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region --verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s // Here is a case where a pointer is treated as integer, invalidated as an // integer, and then used again as a pointer. This test just makes sure diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index 7ebc4a9..e5113ba 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region --verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region --verify -fblocks %s +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s typedef struct objc_selector *SEL; typedef signed char BOOL; @@ -470,3 +470,74 @@ int pr3135() { return 0; } +//===----------------------------------------------------------------------===// +// - Test that we handle compound initializers with +// partially unspecified array values. Previously this caused a crash. +//===----------------------------------------------------------------------===// + +typedef struct RDar7403269 { + unsigned x[10]; + unsigned y; +} RDar7403269; + +void rdar7403269() { + RDar7403269 z = { .y = 0 }; + if (z.x[4] == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +typedef struct RDar7403269_b { + struct zorg { int w; int k; } x[10]; + unsigned y; +} RDar7403269_b; + +void rdar7403269_b() { + RDar7403269_b z = { .y = 0 }; + if (z.x[5].w == 0) + return; + int *p = 0; + *p = 0xDEADBEEF; // no-warning +} + +void rdar7403269_b_pos() { + RDar7403269_b z = { .y = 0 }; + if (z.x[5].w == 1) + return; + int *p = 0; + *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} +} + + +//===----------------------------------------------------------------------===// +// Test that incrementing a non-null pointer results in a non-null pointer. +// () +//===----------------------------------------------------------------------===// + +void test_increment_nonnull_rdar_7191542(const char *path) { + const char *alf = 0; + + for (;;) { + // When using basic-store, we get a null dereference here because we lose information + // about path after the pointer increment. + char c = *path++; // no-warning + if (c == 'a') { + alf = path; + } + + if (alf) + return; + } +} + +//===----------------------------------------------------------------------===// +// Test that the store (implicitly) tracks values for doubles/floats that are +// uninitialized () +//===----------------------------------------------------------------------===// + +double rdar_6811085(void) { + double u; + return u + 10; // expected-warning{{The left operand of '+' is a garbage value}} +} + diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index d2eef0d..42168b9 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -1,8 +1,8 @@ // NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued. -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -fobjc-gc -analyzer-constraints=basic --verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=basic -analyzer-constraints=range --verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=basic --verify -fblocks %s -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s typedef struct objc_ivar *Ivar; typedef struct objc_selector *SEL; @@ -750,3 +750,46 @@ void test_undefined_array_subscript() { int *p = &a[i]; // expected-warning{{Array subscript is undefined}} } @end + +//===----------------------------------------------------------------------===// +// Test using an uninitialized value as a branch condition. +//===----------------------------------------------------------------------===// + +int test_uninit_branch(void) { + int x; + if (x) // expected-warning{{Branch condition evaluates to a garbage value}} + return 1; + return 0; +} + +int test_uninit_branch_b(void) { + int x; + return x ? 1 : 0; // expected-warning{{Branch condition evaluates to a garbage value}} +} + +int test_uninit_branch_c(void) { + int x; + if ((short)x) // expected-warning{{Branch condition evaluates to a garbage value}} + return 1; + return 0; +} + +//===----------------------------------------------------------------------===// +// Test passing an undefined value in a message or function call. +//===----------------------------------------------------------------------===// + +void test_bad_call_aux(int x); +void test_bad_call(void) { + int y; + test_bad_call_aux(y); // expected-warning{{Pass-by-value argument in function call is undefined}} +} + +@interface TestBadArg {} +- (void) testBadArg:(int) x; +@end + +void test_bad_msg(TestBadArg *p) { + int y; + [p testBadArg:y]; // expected-warning{{Pass-by-value argument in message expression is undefined}} +} + diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m index 536c4a1..75cdf6e 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -1,5 +1,7 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s -verify +// RUN: clang-cc -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: clang-cc -triple i386-apple-darwin8 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin8 %s +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s 2>&1 | FileCheck -check-prefix=darwin9 %s +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-constraints=basic -analyzer-store=region %s 2>&1 | FileCheck -check-prefix=darwin9 %s @interface MyClass {} - (void *)voidPtrM; @@ -28,20 +30,20 @@ void createFoo() { void createFoo2() { MyClass *obj = 0; - long double ld = [obj longDoubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} + long double ld = [obj longDoubleM]; // expected-warning{{The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage}} } void createFoo3() { MyClass *obj; obj = 0; - long long ll = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} + long long ll = [obj longlongM]; // expected-warning{{The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage}} } void createFoo4() { MyClass *obj = 0; - double d = [obj doubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} + double d = [obj doubleM]; // expected-warning{{The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage}} } void createFoo5() { @@ -59,10 +61,22 @@ void handleNilPruneLoop(MyClass *obj) { long long j = [obj longlongM]; // no-warning } - long long j = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} + long long j = [obj longlongM]; // expected-warning{{The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage}} } int handleVoidInComma() { MyClass *obj = 0; return [obj voidM], 0; } + +int marker(void) { // control reaches end of non-void function +} + +// CHECK-darwin8: warning: The receiver of message 'longDoubleM' is nil and returns a value of type 'long double' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'doubleM' is nil and returns a value of type 'double' that will be garbage +// CHECK-darwin8: warning: The receiver of message 'longlongM' is nil and returns a value of type 'long long' that will be garbage +// CHECK-darwin8: control reaches end of non-void function +// CHECK-darwin8: 5 diagnostics generated +// CHECK-darwin9: control reaches end of non-void function +// CHECK-darwin9: 1 diagnostic generated diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c index f5c6a10..c604653 100644 --- a/test/Analysis/null-deref-ps.c +++ b/test/Analysis/null-deref-ps.c @@ -26,7 +26,7 @@ int f2(struct foo_struct* p) { if (p) p->x = 1; - return p->x++; // expected-warning{{Dereference of null pointer.}} + return p->x++; // expected-warning{{Dereference of null pointer}} } int f3(char* x) { @@ -36,7 +36,7 @@ int f3(char* x) { if (x) return x[i - 1]; - return x[i+1]; // expected-warning{{Dereference of null pointer.}} + return x[i+1]; // expected-warning{{Dereference of null pointer}} } int f3_b(char* x) { @@ -46,7 +46,7 @@ int f3_b(char* x) { if (x) return x[i - 1]; - return x[i+1]++; // expected-warning{{Dereference of null pointer.}} + return x[i+1]++; // expected-warning{{Dereference of null pointer}} } int f4(int *p) { @@ -57,7 +57,7 @@ int f4(int *p) { return 1; int *q = (int*) x; - return *q; // expected-warning{{Dereference of null pointer.}} + return *q; // expected-warning{{Dereference of null pointer loaded from variable 'q'}} } int f4_b() { diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m index 8bd616a..971d476 100644 --- a/test/Analysis/plist-output.m +++ b/test/Analysis/plist-output.m @@ -1,9 +1,42 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range -fblocks --analyzer-output=plist -o - %s | FileCheck %s +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s void test_null_init(void) { int *p = 0; *p = 0xDEADBEEF; } + +void test_null_assign(void) { + int *p; + p = 0; + *p = 0xDEADBEEF; +} + +void test_null_assign_transitive(void) { + int *p; + p = 0; + int *q = p; + *q = 0xDEADBEEF; +} + +void test_null_cond(int *p) { + if (!p) { + *p = 0xDEADBEEF; + } +} + +void test_null_cond_transitive(int *q) { + if (!q) { + int *p = q; + *p = 0xDEADBEEF; + } +} + +void test_null_field(void) { + struct s { int *p; } x; + x.p = 0; + *(x.p) = 0xDEADBEEF; +} + // CHECK: // CHECK: // CHECK: @@ -102,14 +135,14 @@ void test_null_init(void) { // CHECK: // CHECK: // CHECK: extended_message -// CHECK: Dereference of null pointer +// CHECK: Dereference of null pointer loaded from variable 'p' // CHECK: message -// CHECK: Dereference of null pointer +// CHECK: Dereference of null pointer loaded from variable 'p' // CHECK: // CHECK: -// CHECK: descriptionDereference of null pointer +// CHECK: descriptionDereference of null pointer loaded from variable 'p' // CHECK: categoryLogic error -// CHECK: typeNull pointer dereference +// CHECK: typeDereference of null pointer // CHECK: location // CHECK: // CHECK: line5 @@ -117,6 +150,702 @@ void test_null_init(void) { // CHECK: file0 // CHECK: // CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line9 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line9 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Null pointer value stored to 'p' +// CHECK: message +// CHECK: Null pointer value stored to 'p' +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line10 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line11 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line11 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line11 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line11 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line11 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer loaded from variable 'p' +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: location +// CHECK: +// CHECK: line11 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line15 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line15 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line17 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Variable 'q' initialized to a null pointer value +// CHECK: message +// CHECK: Variable 'q' initialized to a null pointer value +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line17 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line18 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line18 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line18 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line18 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line18 +// CHECK: col4 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Dereference of null pointer loaded from variable 'q' +// CHECK: message +// CHECK: Dereference of null pointer loaded from variable 'q' +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer loaded from variable 'q' +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: location +// CHECK: +// CHECK: line18 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line22 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Assuming pointer value is null +// CHECK: message +// CHECK: Assuming pointer value is null +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line22 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer loaded from variable 'p' +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: location +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line28 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Assuming pointer value is null +// CHECK: message +// CHECK: Assuming pointer value is null +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col7 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line28 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line29 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line30 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line30 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: message +// CHECK: Dereference of null pointer loaded from variable 'p' +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer loaded from variable 'p' +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: location +// CHECK: +// CHECK: line30 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line35 +// CHECK: col10 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line37 +// CHECK: col8 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Dereference of null pointer +// CHECK: message +// CHECK: Dereference of null pointer +// CHECK: +// CHECK: +// CHECK: descriptionDereference of null pointer +// CHECK: categoryLogic error +// CHECK: typeDereference of null pointer +// CHECK: location +// CHECK: +// CHECK: line37 +// CHECK: col3 +// CHECK: file0 +// CHECK: +// CHECK: // CHECK: // CHECK: // CHECK: diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m index 7b0a1a6..1d8bbd3 100644 --- a/test/Analysis/rdar-6442306-1.m +++ b/test/Analysis/rdar-6442306-1.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s --analyzer-store=basic -verify -// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s --analyzer-store=region -verify +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=basic -verify +// RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref %s -analyzer-store=region -verify typedef int bar_return_t; typedef struct { diff --git a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m index 7230f21..9d6fe5b 100644 --- a/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m +++ b/test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m @@ -15,12 +15,12 @@ typedef struct Foo { int x; } Bar; void createFoo() { MyClass *obj = 0; - Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}} + Bar f = [obj foo]; // expected-warning{{The receiver of message 'foo' is nil and returns a value of type 'Bar' that will be garbage}} } void createFoo2() { MyClass *obj = 0; [obj foo]; // no-warning - Bar f = [obj foo]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value (of type 'Bar') to be garbage or otherwise undefined.}} + Bar f = [obj foo]; // expected-warning{{The receiver of message 'foo' is nil and returns a value of type 'Bar' that will be garbage}} } diff --git a/test/Analysis/region-only-test.c b/test/Analysis/region-only-test.c deleted file mode 100644 index 8908adb..0000000 --- a/test/Analysis/region-only-test.c +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s - -// Region store must be enabled for tests in this file. - -// Exercise creating ElementRegion with symbolic super region. -void foo(int* p) { - int *x; - int a; - if (p[0] == 1) - x = &a; - if (p[0] == 1) - (void)*x; // no-warning -} diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m index 3eeebc4..ab52938 100644 --- a/test/Analysis/retain-release-gc-only.m +++ b/test/Analysis/retain-release-gc-only.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -verify %s +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify -fobjc-gc-only -fblocks %s +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fobjc-gc-only -fblocks -verify %s //===----------------------------------------------------------------------===// // Header stuff. @@ -93,6 +93,7 @@ typedef struct _NSZone NSZone; + (id)alloc; - (void)dealloc; - (void)release; +- (id)copy; @end @interface NSObject (NSCoderMethods) - (id)awakeAfterUsingCoder:(NSCoder *)aDecoder; @@ -332,6 +333,17 @@ void rdar_6250216(void) { [pool release]; // expected-warning{{Use -drain instead of -release when using NSAutoreleasePool and garbage collection}} } + +//===----------------------------------------------------------------------===// +// Don't crash when analyzing messages sent to blocks +//===----------------------------------------------------------------------===// + +@class RDar7407273; +typedef void (^RDar7407273Block)(RDar7407273 *operation); +void rdar7407273(RDar7407273Block b) { + [b copy]; +} + //===----------------------------------------------------------------------===// // Tests of ownership attributes. //===----------------------------------------------------------------------===// diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index dfea2e7..bc9f0b7 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s +// RUN: clang-cc -triple x86_64-apple-darwin10 -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s #if __has_feature(attribute_ns_returns_retained) #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) @@ -1162,6 +1162,19 @@ void rdar7306898(void) { } //===----------------------------------------------------------------------===// +// sending 'release', 'retain', etc. to a Class +// directly is not likely what the user intended +//===----------------------------------------------------------------------===// + +@interface RDar7252064 : NSObject @end +void rdar7252064(void) { + [RDar7252064 release]; // expected-warning{{The 'release' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [RDar7252064 retain]; // expected-warning{{The 'retain' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [RDar7252064 autorelease]; // expected-warning{{The 'autorelease' message should be sent to instances of class 'RDar7252064' and not the class directly}} + [NSAutoreleasePool drain]; // expected-warning{{method '+drain' not found}} expected-warning{{The 'drain' message should be sent to instances of class 'NSAutoreleasePool' and not the class directly}} +} + +//===----------------------------------------------------------------------===// // Tests of ownership attributes. //===----------------------------------------------------------------------===// @@ -1259,3 +1272,34 @@ void test_panic_pos_2(int x) { panic(); } +//===----------------------------------------------------------------------===// +// Test uses of blocks (closures) +//===----------------------------------------------------------------------===// + +void test_blocks_1_pos(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // expected-warning{{leak}} + ^{}(); +} + +void test_blocks_1_indirect_release(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^{ [number release]; }(); +} + +void test_blocks_1_indirect_retain(void) { + // Eventually this should be reported as a leak. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^{ [number retain]; }(); +} + +void test_blocks_1_indirect_release_via_call(void) { + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^(NSObject *o){ [o release]; }(number); +} + +void test_blocks_1_indirect_retain_via_call(void) { + // Eventually this should be reported as a leak. + NSNumber *number = [[NSNumber alloc] initWithInt:5]; // no-warning + ^(NSObject *o){ [o retain]; }(number); +} + diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c index f26e2f0..5d1ce25 100644 --- a/test/Analysis/stack-addr-ps.c +++ b/test/Analysis/stack-addr-ps.c @@ -1,5 +1,5 @@ -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -verify %s -// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -verify %s +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=basic -fblocks -verify %s +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -fblocks -verify %s int* f1() { int x = 0; @@ -55,3 +55,16 @@ int struct_test(struct baz byVal, int flag) { return byVal.y[0]; // no-warning } } + +typedef int (^ComparatorBlock)(int a, int b); +ComparatorBlock test_return_block(void) { + ComparatorBlock b = ^int(int a, int b){ return a > b; }; + return b; // expected-warning{{Address of stack-allocated block declared on line 61 returned to caller}} +} + +ComparatorBlock test_return_block_neg_aux(void); +ComparatorBlock test_return_block_neg(void) { + ComparatorBlock b = test_return_block_neg_aux(); + return b; // no-warning +} + diff --git a/test/Analysis/uninit-msg-expr.m b/test/Analysis/uninit-msg-expr.m index c2b7366..46e441f 100644 --- a/test/Analysis/uninit-msg-expr.m +++ b/test/Analysis/uninit-msg-expr.m @@ -42,7 +42,7 @@ extern NSString * const NSUndoManagerCheckpointNotification; unsigned f1() { NSString *aString; - return [aString length]; // expected-warning {{Receiver in message expression is an uninitialized value}} + return [aString length]; // expected-warning {{Receiver in message expression is a garbage value}} } unsigned f2() { diff --git a/test/Analysis/uninit-ps-rdar6145427.m b/test/Analysis/uninit-ps-rdar6145427.m index d9e7318..7be32b4 100644 --- a/test/Analysis/uninit-ps-rdar6145427.m +++ b/test/Analysis/uninit-ps-rdar6145427.m @@ -30,7 +30,7 @@ extern NSString * const NSUndoManagerCheckpointNotification; int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is an uninitialized value.}} + id someUnintializedPointer = [someUnintializedPointer objectAtIndex:0]; // expected-warning{{Receiver in message expression is a garbage value}} NSLog(@"%@", someUnintializedPointer); [pool drain]; return 0; diff --git a/test/Analysis/unused-ivars.m b/test/Analysis/unused-ivars.m index 754799b..bbbf6ae 100644 --- a/test/Analysis/unused-ivars.m +++ b/test/Analysis/unused-ivars.m @@ -65,3 +65,19 @@ } @end +//===----------------------------------------------------------------------===// +// - ivars referenced by lexically nested functions +// should not be flagged as unused +//===----------------------------------------------------------------------===// + +@interface RDar7254495 { +@private + int x; // no-warning +} +@end + +@implementation RDar7254495 +int radar_7254495(RDar7254495 *a) { + return a->x; +} +@end diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cd822f6..f39eb2a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -40,6 +40,11 @@ if(PYTHONINTERP_FOUND) set(CLANG_TEST_EXTRA_ARGS "--no-progress-bar") endif() + option(CLANG_TEST_USE_VG "Run Clang tests under Valgrind" OFF) + if(CLANG_TEST_USE_VG) + set(CLANG_TEST_EXTRA_ARGS ${CLANG_TEST_EXTRA_ARGS} "--vg") + endif () + foreach(testdir ${CLANG_TEST_DIRECTORIES}) add_custom_target(clang-test-${testdir} COMMAND ${PYTHON_EXECUTABLE} diff --git a/test/CXX/basic/basic.link/p9.cpp b/test/CXX/basic/basic.link/p9.cpp new file mode 100644 index 0000000..ecff3ee --- /dev/null +++ b/test/CXX/basic/basic.link/p9.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// FIXME: This test is woefully incomplete. +namespace N { } // expected-note{{here}} + +// First bullet: two names with external linkage that refer to +// different kinds of entities. +void f() { + int N(); // expected-error{{redefinition}} +} + diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp index cebc3e9..418059d 100644 --- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp +++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp @@ -13,5 +13,5 @@ try { } catch (int a) { // expected-error {{redefinition of 'a'}} int b; // expected-error {{redefinition of 'b'}} - ++c; // expected-error {{use of undeclared identifion 'c'}} + ++c; // expected-error {{use of undeclared identifier 'c'}} } diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp index 4b15828..0cb8186 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp @@ -41,8 +41,8 @@ namespace N1 { void m() { - void f(int, int); // expected-note{{candidate}} - f(4); // expected-error{{no matching}} + void f(int, int); + f(4); // expected-error{{too few arguments to function call}} void f(int, int = 5); // expected-note{{previous definition}} f(4); // okay void f(int, int = 5); // expected-error{{redefinition of default argument}} diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp index b63c56c..90bb162 100644 --- a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template struct A; diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp index 725b61c..6c82720 100644 --- a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template // expected-note{{previous template}} class X0 { public: @@ -66,3 +65,36 @@ X0::operator T*() const { namespace N { template class A {void a();}; } namespace N { template void A::a() {} } + +// PR5566 +template +struct X1 { + template + struct B { void f(); }; +}; + +template +template +void X1::template B::f() { } + +// PR5527 +template