aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
commit1569ce68681d909594d64f9b056d71f5dd7563bf (patch)
tree867cbbe32a66fd7d62dd9ce9df23a23fefdb8290
parentf5bd02d290ff15268853e0456c130a1afa15e907 (diff)
downloadsrc-1569ce68681d909594d64f9b056d71f5dd7563bf.tar.gz
src-1569ce68681d909594d64f9b056d71f5dd7563bf.zip
Update clang to r90226.
Notes
Notes: svn path=/vendor/clang/dist/; revision=199990
-rw-r--r--Makefile4
-rw-r--r--clang.xcodeproj/project.pbxproj24
-rw-r--r--include/clang/AST/ASTContext.h35
-rw-r--r--include/clang/AST/Attr.h42
-rw-r--r--include/clang/AST/Decl.h46
-rw-r--r--include/clang/AST/DeclBase.h4
-rw-r--r--include/clang/AST/DeclCXX.h41
-rw-r--r--include/clang/AST/DeclTemplate.h3
-rw-r--r--include/clang/AST/DeclarationName.h26
-rw-r--r--include/clang/AST/Expr.h86
-rw-r--r--include/clang/AST/ExprCXX.h626
-rw-r--r--include/clang/AST/RecordLayout.h112
-rw-r--r--include/clang/AST/Redeclarable.h13
-rw-r--r--include/clang/AST/Stmt.h95
-rw-r--r--include/clang/AST/StmtCXX.h6
-rw-r--r--include/clang/AST/StmtNodes.def9
-rw-r--r--include/clang/AST/TemplateBase.h36
-rw-r--r--include/clang/AST/Type.h30
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h6
-rw-r--r--include/clang/Analysis/PathDiagnostic.h19
-rw-r--r--include/clang/Analysis/PathSensitive/AnalysisContext.h14
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h21
-rw-r--r--include/clang/Analysis/PathSensitive/BugType.h30
-rw-r--r--include/clang/Analysis/PathSensitive/Checker.h101
-rw-r--r--include/clang/Analysis/PathSensitive/CheckerVisitor.def18
-rw-r--r--include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h33
-rw-r--r--include/clang/Analysis/PathSensitive/ExplodedGraph.h14
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h4
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h131
-rw-r--r--include/clang/Analysis/PathSensitive/GRState.h28
-rw-r--r--include/clang/Analysis/PathSensitive/MemRegion.h161
-rw-r--r--include/clang/Analysis/PathSensitive/ValueManager.h3
-rw-r--r--include/clang/Basic/BuiltinsX86.def4
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticGroups.td7
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td11
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td58
-rw-r--r--include/clang/Basic/IdentifierTable.h9
-rw-r--r--include/clang/Basic/LangOptions.h15
-rw-r--r--include/clang/Basic/OnDiskHashTable.h1
-rw-r--r--include/clang/Basic/TargetInfo.h3
-rw-r--r--include/clang/Basic/TokenKinds.def111
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h52
-rw-r--r--include/clang/Driver/ArgList.h83
-rw-r--r--include/clang/Driver/CC1Options.h2
-rw-r--r--include/clang/Driver/CC1Options.td395
-rw-r--r--include/clang/Driver/Makefile4
-rw-r--r--include/clang/Driver/OptParser.td15
-rw-r--r--include/clang/Driver/OptSpecifier.h3
-rw-r--r--include/clang/Driver/Options.h2
-rw-r--r--include/clang/Frontend/ASTConsumers.h1
-rw-r--r--include/clang/Frontend/ASTUnit.h43
-rw-r--r--include/clang/Frontend/AnalysisConsumer.h2
-rw-r--r--include/clang/Frontend/CommandLineSourceLoc.h49
-rw-r--r--include/clang/Frontend/CompilerInstance.h18
-rw-r--r--include/clang/Frontend/CompilerInvocation.h18
-rw-r--r--include/clang/Frontend/DeclXML.def58
-rw-r--r--include/clang/Frontend/FrontendAction.h17
-rw-r--r--include/clang/Frontend/FrontendOptions.h2
-rw-r--r--include/clang/Frontend/LangStandard.h83
-rw-r--r--include/clang/Frontend/LangStandards.def83
-rw-r--r--include/clang/Frontend/PCHBitCodes.h8
-rw-r--r--include/clang/Frontend/PathDiagnosticClients.h2
-rw-r--r--include/clang/Frontend/StmtXML.def89
-rw-r--r--include/clang/Frontend/TextDiagnosticBuffer.h4
-rw-r--r--include/clang/Lex/Lexer.h5
-rw-r--r--include/clang/Lex/Preprocessor.h6
-rw-r--r--include/clang/Parse/Action.h152
-rw-r--r--include/clang/Parse/AttributeList.h35
-rw-r--r--include/clang/Parse/DeclSpec.h21
-rw-r--r--include/clang/Parse/Parser.h74
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h22
-rw-r--r--lib/AST/ASTContext.cpp113
-rw-r--r--lib/AST/Decl.cpp205
-rw-r--r--lib/AST/DeclBase.cpp15
-rw-r--r--lib/AST/DeclCXX.cpp46
-rw-r--r--lib/AST/DeclPrinter.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp7
-rw-r--r--lib/AST/DeclarationName.cpp44
-rw-r--r--lib/AST/Expr.cpp212
-rw-r--r--lib/AST/ExprCXX.cpp244
-rw-r--r--lib/AST/ExprConstant.cpp62
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp259
-rw-r--r--lib/AST/RecordLayoutBuilder.h20
-rw-r--r--lib/AST/Stmt.cpp6
-rw-r--r--lib/AST/StmtDumper.cpp3
-rw-r--r--lib/AST/StmtPrinter.cpp52
-rw-r--r--lib/AST/StmtProfile.cpp46
-rw-r--r--lib/AST/StmtViz.cpp5
-rw-r--r--lib/AST/TemplateBase.cpp14
-rw-r--r--lib/AST/Type.cpp6
-rw-r--r--lib/AST/TypePrinter.cpp10
-rw-r--r--lib/Analysis/AnalysisContext.cpp87
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp12
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp8
-rw-r--r--lib/Analysis/BadCallChecker.cpp57
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp7
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp73
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h12
-rw-r--r--lib/Analysis/BasicStore.cpp5
-rw-r--r--lib/Analysis/BugReporter.cpp23
-rw-r--r--lib/Analysis/BugReporterVisitors.cpp4
-rw-r--r--lib/Analysis/CFG.cpp22
-rw-r--r--lib/Analysis/CFRefCount.cpp252
-rw-r--r--lib/Analysis/CMakeLists.txt7
-rw-r--r--lib/Analysis/CallAndMessageChecker.cpp267
-rw-r--r--lib/Analysis/CallGraph.cpp4
-rw-r--r--lib/Analysis/CallInliner.cpp2
-rw-r--r--lib/Analysis/CastToStructChecker.cpp4
-rw-r--r--lib/Analysis/CheckDeadStores.cpp18
-rw-r--r--lib/Analysis/CheckObjCDealloc.cpp7
-rw-r--r--lib/Analysis/CheckObjCInstMethSignature.cpp2
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp36
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp9
-rw-r--r--lib/Analysis/CheckSizeofPointer.cpp3
-rw-r--r--lib/Analysis/Checker.cpp35
-rw-r--r--lib/Analysis/DereferenceChecker.cpp68
-rw-r--r--lib/Analysis/DivZeroChecker.cpp7
-rw-r--r--lib/Analysis/Environment.cpp3
-rw-r--r--lib/Analysis/FixedAddressChecker.cpp4
-rw-r--r--lib/Analysis/GRCoreEngine.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp462
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.cpp2
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp400
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h6
-rw-r--r--lib/Analysis/GRState.cpp23
-rw-r--r--lib/Analysis/LiveVariables.cpp25
-rw-r--r--lib/Analysis/MallocChecker.cpp21
-rw-r--r--lib/Analysis/MemRegion.cpp132
-rw-r--r--lib/Analysis/NSAutoreleasePoolChecker.cpp6
-rw-r--r--lib/Analysis/NSErrorChecker.cpp7
-rw-r--r--lib/Analysis/PointerArithChecker.cpp4
-rw-r--r--lib/Analysis/PointerSubChecker.cpp4
-rw-r--r--lib/Analysis/PthreadLockChecker.cpp8
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp11
-rw-r--r--lib/Analysis/RegionStore.cpp92
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp5
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp13
-rw-r--r--lib/Analysis/ReturnUndefChecker.cpp4
-rw-r--r--lib/Analysis/SVals.cpp2
-rw-r--r--lib/Analysis/SimpleSValuator.cpp3
-rw-r--r--lib/Analysis/Store.cpp10
-rw-r--r--lib/Analysis/UndefBranchChecker.cpp117
-rw-r--r--lib/Analysis/UndefResultChecker.cpp86
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp56
-rw-r--r--lib/Analysis/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp22
-rw-r--r--lib/Analysis/UninitializedValues.cpp7
-rw-r--r--lib/Analysis/VLASizeChecker.cpp9
-rw-r--r--lib/Analysis/ValueManager.cpp11
-rw-r--r--lib/Basic/TargetInfo.cpp1
-rw-r--r--lib/Basic/Targets.cpp49
-rw-r--r--lib/Basic/TokenKinds.cpp55
-rw-r--r--lib/CodeGen/CGBlocks.cpp16
-rw-r--r--lib/CodeGen/CGBuiltin.cpp11
-rw-r--r--lib/CodeGen/CGCXX.cpp346
-rw-r--r--lib/CodeGen/CGCall.cpp62
-rw-r--r--lib/CodeGen/CGClass.cpp (renamed from lib/CodeGen/CGCXXClass.cpp)124
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp42
-rw-r--r--lib/CodeGen/CGDecl.cpp20
-rw-r--r--lib/CodeGen/CGException.cpp390
-rw-r--r--lib/CodeGen/CGExpr.cpp84
-rw-r--r--lib/CodeGen/CGExprAgg.cpp30
-rw-r--r--lib/CodeGen/CGExprCXX.cpp (renamed from lib/CodeGen/CGCXXExpr.cpp)59
-rw-r--r--lib/CodeGen/CGExprComplex.cpp31
-rw-r--r--lib/CodeGen/CGExprConstant.cpp13
-rw-r--r--lib/CodeGen/CGExprScalar.cpp181
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp13
-rw-r--r--lib/CodeGen/CGObjCMac.cpp21
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp34
-rw-r--r--lib/CodeGen/CGRtti.cpp45
-rw-r--r--lib/CodeGen/CGStmt.cpp136
-rw-r--r--lib/CodeGen/CGTemporaries.cpp (renamed from lib/CodeGen/CGCXXTemp.cpp)24
-rw-r--r--lib/CodeGen/CGVtable.cpp546
-rw-r--r--lib/CodeGen/CGVtable.h86
-rw-r--r--lib/CodeGen/CMakeLists.txt8
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp35
-rw-r--r--lib/CodeGen/CodeGenFunction.h178
-rw-r--r--lib/CodeGen/CodeGenModule.cpp182
-rw-r--r--lib/CodeGen/CodeGenModule.h18
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp9
-rw-r--r--lib/CodeGen/CodeGenTypes.h31
-rw-r--r--lib/CodeGen/Mangle.cpp816
-rw-r--r--lib/CodeGen/Mangle.h91
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp4
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp28
-rw-r--r--lib/Driver/ArgList.cpp112
-rw-r--r--lib/Driver/CC1Options.cpp9
-rw-r--r--lib/Driver/Compilation.cpp7
-rw-r--r--lib/Driver/Driver.cpp7
-rw-r--r--lib/Driver/DriverOptions.cpp5
-rw-r--r--lib/Driver/Tools.cpp179
-rw-r--r--lib/Driver/Types.cpp1
-rw-r--r--lib/Frontend/ASTUnit.cpp102
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp32
-rw-r--r--lib/Frontend/Backend.cpp79
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CacheTokens.cpp14
-rw-r--r--lib/Frontend/CompilerInstance.cpp22
-rw-r--r--lib/Frontend/CompilerInvocation.cpp807
-rw-r--r--lib/Frontend/DependencyFile.cpp3
-rw-r--r--lib/Frontend/DiagChecker.cpp3
-rw-r--r--lib/Frontend/FrontendAction.cpp9
-rw-r--r--lib/Frontend/FrontendActions.cpp13
-rw-r--r--lib/Frontend/GeneratePCH.cpp7
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp3
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp157
-rw-r--r--lib/Frontend/InitPreprocessor.cpp7
-rw-r--r--lib/Frontend/LangStandards.cpp44
-rw-r--r--lib/Frontend/PCHReader.cpp22
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp4
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp4
-rw-r--r--lib/Frontend/PCHWriter.cpp24
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp4
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp4
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp15
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp2
-rw-r--r--lib/Frontend/StmtXML.cpp5
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp21
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp8
-rw-r--r--lib/Headers/stdint.h71
-rw-r--r--lib/Index/Analyzer.cpp9
-rw-r--r--lib/Index/DeclReferenceMap.cpp3
-rw-r--r--lib/Index/ResolveLocation.cpp7
-rw-r--r--lib/Index/SelectorMap.cpp3
-rw-r--r--lib/Lex/Lexer.cpp11
-rw-r--r--lib/Lex/LiteralSupport.cpp42
-rw-r--r--lib/Lex/PPDirectives.cpp5
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PTHLexer.cpp14
-rw-r--r--lib/Parse/AttributeList.cpp24
-rw-r--r--lib/Parse/MinimalAction.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp126
-rw-r--r--lib/Parse/ParseDeclCXX.cpp270
-rw-r--r--lib/Parse/ParseExpr.cpp29
-rw-r--r--lib/Parse/ParseExprCXX.cpp113
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp187
-rw-r--r--lib/Parse/ParseTemplate.cpp50
-rw-r--r--lib/Parse/ParseTentative.cpp88
-rw-r--r--lib/Parse/Parser.cpp27
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp6
-rw-r--r--lib/Rewrite/TokenRewriter.cpp3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp492
-rw-r--r--lib/Sema/Lookup.h46
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp15
-rw-r--r--lib/Sema/Sema.h354
-rw-r--r--lib/Sema/SemaCodeComplete.cpp103
-rw-r--r--lib/Sema/SemaDecl.cpp183
-rw-r--r--lib/Sema/SemaDeclAttr.cpp223
-rw-r--r--lib/Sema/SemaDeclCXX.cpp230
-rw-r--r--lib/Sema/SemaExpr.cpp1957
-rw-r--r--lib/Sema/SemaExprCXX.cpp210
-rw-r--r--lib/Sema/SemaInit.cpp45
-rw-r--r--lib/Sema/SemaLookup.cpp52
-rw-r--r--lib/Sema/SemaOverload.cpp556
-rw-r--r--lib/Sema/SemaStmt.cpp246
-rw-r--r--lib/Sema/SemaTemplate.cpp723
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp108
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp54
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp38
-rw-r--r--lib/Sema/SemaType.cpp1
-rw-r--r--lib/Sema/TreeTransform.h673
-rw-r--r--test/Analysis/MissingDealloc.m4
-rw-r--r--test/Analysis/casts.c2
-rw-r--r--test/Analysis/casts.m4
-rw-r--r--test/Analysis/cfref_PR2519.c8
-rw-r--r--test/Analysis/concrete-address.c4
-rw-r--r--test/Analysis/dead-stores.c46
-rw-r--r--test/Analysis/fields.c4
-rw-r--r--test/Analysis/misc-ps-64.m8
-rw-r--r--test/Analysis/misc-ps-basic-store.m2
-rw-r--r--test/Analysis/misc-ps-eager-assume.m2
-rw-r--r--test/Analysis/misc-ps-ranges.m4
-rw-r--r--test/Analysis/misc-ps-region-store-i386.m2
-rw-r--r--test/Analysis/misc-ps-region-store-x86_64.m2
-rw-r--r--test/Analysis/misc-ps-region-store.m75
-rw-r--r--test/Analysis/misc-ps.m51
-rw-r--r--test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m26
-rw-r--r--test/Analysis/null-deref-ps.c8
-rw-r--r--test/Analysis/plist-output.m735
-rw-r--r--test/Analysis/rdar-6442306-1.m4
-rw-r--r--test/Analysis/rdar-6600344-nil-receiver-undefined-struct-ret.m4
-rw-r--r--test/Analysis/region-only-test.c13
-rw-r--r--test/Analysis/retain-release-gc-only.m16
-rw-r--r--test/Analysis/retain-release.m48
-rw-r--r--test/Analysis/stack-addr-ps.c17
-rw-r--r--test/Analysis/uninit-msg-expr.m2
-rw-r--r--test/Analysis/uninit-ps-rdar6145427.m2
-rw-r--r--test/Analysis/unused-ivars.m16
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/CXX/basic/basic.link/p9.cpp11
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p15.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp4
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp34
-rw-r--r--test/CXX/temp/temp.param/p2.cpp3
-rw-r--r--test/CXX/temp/temp.param/p9.cpp23
-rw-r--r--test/CodeCompletion/property.m29
-rw-r--r--test/CodeGen/2008-07-17-no-emit-on-error.c4
-rw-r--r--test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c2
-rw-r--r--test/CodeGen/2008-07-30-implicit-initialization.c2
-rw-r--r--test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c2
-rw-r--r--test/CodeGen/2008-08-04-void-pointer-arithmetic.c2
-rw-r--r--test/CodeGen/2008-08-19-cast-of-typedef.c2
-rw-r--r--test/CodeGen/PR2001-bitfield-reload.c5
-rw-r--r--test/CodeGen/arm-arguments.c4
-rw-r--r--test/CodeGen/builtins-ffs_parity_popcount.c15
-rw-r--r--test/CodeGen/builtins-powi.c28
-rw-r--r--test/CodeGen/const-init.c4
-rw-r--r--test/CodeGen/debug-info.c2
-rw-r--r--test/CodeGen/flexible-array-init.c7
-rw-r--r--test/CodeGen/func-return-member.c5
-rw-r--r--test/CodeGen/incomplete-function-type.c6
-rw-r--r--test/CodeGen/rdr-6098585-default-after-caserange.c2
-rw-r--r--test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c2
-rw-r--r--test/CodeGen/rdr-6098585-empty-case-range.c2
-rw-r--r--test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c2
-rw-r--r--test/CodeGen/rdr-6098585-unsigned-caserange.c2
-rw-r--r--test/CodeGen/stack-protector.c6
-rw-r--r--test/CodeGen/static-order.c5
-rw-r--r--test/CodeGen/switch.c27
-rw-r--r--test/CodeGen/vector.c2
-rw-r--r--test/CodeGen/visibility.c6
-rw-r--r--test/CodeGenCXX/condition.cpp110
-rw-r--r--test/CodeGenCXX/conditional-temporaries.cpp28
-rw-r--r--test/CodeGenCXX/const-global-linkage.cpp13
-rw-r--r--test/CodeGenCXX/const-init.cpp17
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-2.cpp4
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp11
-rw-r--r--test/CodeGenCXX/default-arguments.cpp58
-rw-r--r--test/CodeGenCXX/dyncast.cpp12
-rw-r--r--test/CodeGenCXX/eh.cpp68
-rw-r--r--test/CodeGenCXX/mangle-template.cpp68
-rw-r--r--test/CodeGenCXX/member-expressions.cpp27
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp18
-rw-r--r--test/CodeGenCXX/member-pointer-cast.cpp21
-rw-r--r--test/CodeGenCXX/member-templates.cpp31
-rw-r--r--test/CodeGenCXX/new-with-default-arg.cpp33
-rw-r--r--test/CodeGenCXX/new.cpp20
-rw-r--r--test/CodeGenCXX/references.cpp5
-rw-r--r--test/CodeGenCXX/temp-1.cpp83
-rw-r--r--test/CodeGenCXX/temp-order.cpp199
-rw-r--r--test/CodeGenCXX/virt-dtor-key.cpp9
-rw-r--r--test/CodeGenCXX/virt.cpp93
-rw-r--r--test/CodeGenCXX/virtual-base-cast.cpp38
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp19
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp17
-rw-r--r--test/CodeGenCXX/virtual-functions-incomplete-types.cpp30
-rw-r--r--test/CodeGenCXX/x86_64-arguments.cpp27
-rw-r--r--test/CodeGenObjC/class-obj-hidden-visibility.m6
-rw-r--r--test/CodeGenObjC/constant-strings.m2
-rw-r--r--test/CodeGenObjC/continuation-class.m2
-rw-r--r--test/CodeGenObjC/dot-syntax-1.m2
-rw-r--r--test/CodeGenObjC/dot-syntax.m2
-rw-r--r--test/CodeGenObjC/encode-test.m3
-rw-r--r--test/CodeGenObjC/hidden-synthesized-ivar.m13
-rw-r--r--test/CodeGenObjC/hidden-visibility.m2
-rw-r--r--test/CodeGenObjC/hidden.m2
-rw-r--r--test/CodeGenObjC/messages-2.m2
-rw-r--r--test/CodeGenObjC/messages.m6
-rw-r--r--test/CodeGenObjC/metadata_symbols.m2
-rw-r--r--test/CodeGenObjC/newproperty-nested-synthesis-1.m2
-rw-r--r--test/CodeGenObjC/property-getter-dot-syntax.m2
-rw-r--r--test/CodeGenObjC/property.m2
-rw-r--r--test/CodeGenObjC/protocol-definition-hidden-visibility.m19
-rw-r--r--test/CodeGenObjC/sel-as-builtin-type.m23
-rw-r--r--test/CodeGenObjC/undefined-protocol.m6
-rw-r--r--test/CodeGenObjC/variadic-sends.m20
-rw-r--r--test/Coverage/ast-printing.c8
-rw-r--r--test/Coverage/ast-printing.cpp8
-rw-r--r--test/Coverage/ast-printing.m6
-rw-r--r--test/Coverage/parse-callbacks.c4
-rw-r--r--test/Coverage/parse-callbacks.m4
-rw-r--r--test/Driver/clang-translation.c14
-rw-r--r--test/Driver/flags.c6
-rw-r--r--test/FixIt/fixit-cxx0x.cpp14
-rw-r--r--test/Frontend/mmacosx-version-min-test.c1
-rw-r--r--test/Frontend/output-failures.c4
-rw-r--r--test/Frontend/rewrite-macros.c2
-rw-r--r--test/Index/c-index-api-fn-scan.m217
-rw-r--r--test/Index/c-index-api-loadTU-test.m124
-rw-r--r--test/Index/c-index-api-test.m224
-rw-r--r--test/Index/c-index-pch.h7
-rw-r--r--test/Index/foo.h8
-rw-r--r--test/Index/objc.h11
-rw-r--r--test/Index/t1.c31
-rw-r--r--test/Index/t1.m23
-rw-r--r--test/Index/t2.c14
-rw-r--r--test/Index/t2.m16
-rw-r--r--test/Lexer/constants-ms.c12
-rw-r--r--test/Misc/diag-checker.c5
-rw-r--r--test/PCH/method_pool.m2
-rw-r--r--test/PCH/objc_import.m2
-rw-r--r--test/PCH/objc_methods.m2
-rw-r--r--test/PCH/objc_property.m2
-rw-r--r--test/PCH/reloc.c2
-rw-r--r--test/Parser/MicrosoftExtensions.c2
-rw-r--r--test/Parser/attributes.c1
-rw-r--r--test/Parser/cxx-attributes.cpp9
-rw-r--r--test/Parser/cxx-parse-member-pointer-op.cpp13
-rw-r--r--test/Parser/cxx-template-decl.cpp4
-rw-r--r--test/Parser/cxx-using-declaration.cpp5
-rw-r--r--test/Parser/cxx0x-attributes.cpp61
-rw-r--r--test/Parser/cxx0x-literal-operators.cpp5
-rw-r--r--test/Parser/if-scope-c90.c2
-rw-r--r--test/Parser/if-scope-c99.c2
-rw-r--r--test/Preprocessor/assembler-with-cpp.c4
-rw-r--r--test/Preprocessor/cxx_true.cpp6
-rw-r--r--test/Preprocessor/feature_tests.c4
-rw-r--r--test/Preprocessor/init.c101
-rw-r--r--test/Preprocessor/line-directive.c2
-rw-r--r--test/Preprocessor/macro_paste_bcpl_comment.c2
-rw-r--r--test/Preprocessor/stdint.c37
-rw-r--r--test/Rewriter/id-test-3.m2
-rw-r--r--test/Rewriter/ivar-encoding-1.m2
-rw-r--r--test/Rewriter/ivar-encoding-2.m2
-rw-r--r--test/Rewriter/metadata-test-1.m2
-rw-r--r--test/Rewriter/metadata-test-2.m2
-rw-r--r--test/Rewriter/method-encoding-1.m2
-rw-r--r--test/Rewriter/objc-encoding-bug-1.m2
-rw-r--r--test/Rewriter/objc-string-concat-1.m2
-rw-r--r--test/Rewriter/objc-synchronized-1.m2
-rw-r--r--test/Rewriter/protocol-rewrite-1.m2
-rw-r--r--test/Rewriter/rewrite-api-bug.m2
-rw-r--r--test/Rewriter/rewrite-foreach-1.m2
-rw-r--r--test/Rewriter/rewrite-foreach-2.m2
-rw-r--r--test/Rewriter/rewrite-foreach-3.m2
-rw-r--r--test/Rewriter/rewrite-foreach-4.m2
-rw-r--r--test/Rewriter/rewrite-foreach-5.m2
-rw-r--r--test/Rewriter/rewrite-foreach-6.m2
-rw-r--r--test/Rewriter/rewrite-nest.m2
-rw-r--r--test/Rewriter/rewrite-protocol-type-1.m2
-rw-r--r--test/Rewriter/rewrite-try-catch.m2
-rw-r--r--test/Rewriter/static-type-protocol-1.m2
-rw-r--r--test/Rewriter/undecl-objc-h.m2
-rw-r--r--test/Rewriter/undeclared-method-1.m2
-rw-r--r--test/Rewriter/undef-field-reference-1.m2
-rw-r--r--test/Rewriter/va-method.m2
-rw-r--r--test/Sema/align-arm-apcs.c2
-rw-r--r--test/Sema/altivec-init.c2
-rw-r--r--test/Sema/carbon.c2
-rw-r--r--test/Sema/cast.c4
-rw-r--r--test/Sema/exprs.c2
-rw-r--r--test/Sema/switch.c12
-rw-r--r--test/Sema/wchar.c4
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp9
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp36
-rw-r--r--test/SemaCXX/attr-sentinel.cpp6
-rw-r--r--test/SemaCXX/class-layout.cpp17
-rw-r--r--test/SemaCXX/class.cpp8
-rw-r--r--test/SemaCXX/condition.cpp8
-rw-r--r--test/SemaCXX/converting-constructor.cpp7
-rw-r--r--test/SemaCXX/implicit-int.cpp2
-rw-r--r--test/SemaCXX/member-pointers-2.cpp36
-rw-r--r--test/SemaCXX/nested-name-spec.cpp3
-rw-r--r--test/SemaCXX/new-delete.cpp12
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp9
-rw-r--r--test/SemaCXX/qual-id-test.cpp4
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp10
-rw-r--r--test/SemaCXX/switch-0x.cpp11
-rw-r--r--test/SemaCXX/switch.cpp27
-rw-r--r--test/SemaCXX/typedef-redecl.cpp2
-rw-r--r--test/SemaCXX/using-directive.cpp10
-rw-r--r--test/SemaObjC/cocoa.m2
-rw-r--r--test/SemaObjC/foreach.m2
-rw-r--r--test/SemaObjC/ivar-ref-misuse.m2
-rw-r--r--test/SemaTemplate/current-instantiation.cpp9
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp26
-rw-r--r--test/SemaTemplate/dependent-names.cpp70
-rw-r--r--test/SemaTemplate/dependent-sized_array.cpp17
-rw-r--r--test/SemaTemplate/destructor-template.cpp7
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp3
-rw-r--r--test/SemaTemplate/instantiate-member-template.cpp15
-rw-r--r--test/SemaTemplate/instantiate-method.cpp23
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp36
-rw-r--r--test/SemaTemplate/instantiation-depth.cpp2
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp2
-rw-r--r--test/SemaTemplate/overload-uneval.cpp42
-rw-r--r--test/SemaTemplate/qualified-id.cpp11
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp9
-rw-r--r--test/SemaTemplate/temp_explicit.cpp17
-rw-r--r--tools/CIndex/CIndex.cpp777
-rw-r--r--tools/CMakeLists.txt4
-rw-r--r--tools/c-index-test/CMakeLists.txt3
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c134
-rw-r--r--tools/clang-cc/CMakeLists.txt1
-rw-r--r--tools/clang-cc/Makefile2
-rw-r--r--tools/clang-cc/Options.cpp327
-rw-r--r--tools/clang-cc/Options.h7
-rw-r--r--tools/clang-cc/clang-cc.cpp173
-rw-r--r--tools/driver/CMakeLists.txt11
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1_main.cpp68
-rw-r--r--tools/driver/driver.cpp17
-rw-r--r--tools/index-test/CMakeLists.txt2
-rw-r--r--tools/index-test/Makefile3
-rw-r--r--tools/index-test/index-test.cpp33
-rwxr-xr-xtools/scan-build/ccc-analyzer (renamed from utils/ccc-analyzer)0
-rwxr-xr-xtools/scan-build/scan-build (renamed from utils/scan-build)2
-rw-r--r--tools/scan-build/scanview.css (renamed from utils/scanview.css)0
-rw-r--r--tools/scan-build/sorttable.js (renamed from utils/sorttable.js)0
-rw-r--r--tools/wpa/CMakeLists.txt20
-rw-r--r--tools/wpa/Makefile16
-rw-r--r--tools/wpa/clang-wpa.cpp62
-rw-r--r--utils/C++Tests/Clang-Code-Compile/lit.local.cfg2
-rw-r--r--utils/C++Tests/Clang-Syntax/lit.local.cfg1
-rw-r--r--utils/C++Tests/LLVM-Code-Compile/lit.local.cfg24
-rw-r--r--utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg23
-rw-r--r--utils/C++Tests/LLVM-Syntax/lit.local.cfg3
-rw-r--r--utils/C++Tests/lit.cfg12
-rwxr-xr-xutils/analyzer/ubiviz (renamed from utils/ubiviz)0
-rw-r--r--www/analyzer/installation.html2
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/cxx_status.html11
521 files changed, 17012 insertions, 9269 deletions
diff --git a/Makefile b/Makefile
index 17ccc7320ec8..9002123dcaa3 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 f0a2194cb2c7..1ad7019aa00b 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 = "<group>"; tabWidth = 2; };
1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A4C41BE105B4C0B0047B5E7 /* CGCXXClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXClass.cpp; path = lib/CodeGen/CGCXXClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A4C41BE105B4C0B0047B5E7 /* CGClass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGClass.cpp; path = lib/CodeGen/CGClass.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A535ED8107BC45E000C3AE7 /* CXXInheritance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXInheritance.cpp; path = lib/AST/CXXInheritance.cpp; sourceTree = "<group>"; };
1A535EDB107BC47B000C3AE7 /* CanonicalType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CanonicalType.h; path = clang/AST/CanonicalType.h; sourceTree = "<group>"; };
1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
@@ -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 = "<group>"; tabWidth = 2; };
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A6B6CD310693FC900BB4A8F /* SemaTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SemaTemplate.h; path = lib/Sema/SemaTemplate.h; sourceTree = "<group>"; tabWidth = 2; };
- 1A6B6E991069833600BB4A8F /* CGCXXExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXExpr.cpp; path = lib/CodeGen/CGCXXExpr.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6B6E991069833600BB4A8F /* CGExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprCXX.cpp; path = lib/CodeGen/CGExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A6C01F6108128710072DEE4 /* CGRtti.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRtti.cpp; path = lib/CodeGen/CGRtti.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGTemporaries.cpp; path = lib/CodeGen/CGTemporaries.cpp; sourceTree = "<group>"; tabWidth = 2; };
1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; };
1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; };
1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = "<group>"; };
@@ -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 f9d2f71b1f28..4f29e5d8a618 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 b36ff1229376..2c7ab9d67e95 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 <cassert>
#include <cstring>
#include <string>
#include <algorithm>
+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<AlignedAttr>();
+ 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 ac79a91792d7..f7944771efce 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<NamedDecl*, 4> 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 79f766356138..e1f948fdd550 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 e5bf78cd10d2..990403e7dc2e 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<CanQualType, 8> &TopConversionsTypeSet,
const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes);
void collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet);
+ llvm::SmallPtrSet<CanQualType, 8>& 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<RecordType>(getTypeForDecl())->isBeingDefined()) &&
"getConversionFunctions() called on incomplete type");
return &Conversions;
}
- const OverloadedFunctionDecl *getConversionFunctions() const {
+ const UnresolvedSet *getConversionFunctions() const {
assert((this->isDefinition() ||
cast<RecordType>(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<UsingDirectiveDecl*>(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 14f666005cd6..3ecc4bb52b4c 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 a30f6e860dde..676bd2ca7336 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<CXXLiteralOperatorIdName *>(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<uintptr_t>(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<uintptr_t> (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 dfc5b13f28d3..7cf9aabc6d6f 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<const TemplateArgumentLoc *> (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<int>.
- 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 9e6fd4fd065b..23844ce5d967 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<VarDecl>(getDecl()); }
- const VarDecl *getVarDecl() const { return cast<VarDecl>(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<typename T> 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<const ExplicitTemplateArgumentList*>(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<T>::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<T>::) refers to a dependent type. In
/// this case, X<T>::value cannot resolve to a declaration because the
/// declaration will differ from on instantiation of X<T> to the
-/// next. Therefore, UnresolvedDeclRefExpr keeps track of the
+/// next. Therefore, DependentScopeDeclRefExpr keeps track of the
/// qualifier (X<T>::) 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<FunctionDecl>.
-class TemplateIdRefExpr : public Expr {
- /// \brief If this template-id was qualified-id, e.g., @c std::sort<int>,
- /// this nested name specifier contains the @c std::.
- NestedNameSpecifier *Qualifier;
-
- /// \brief If this template-id was a qualified-id, e.g., @c std::sort<int>,
- /// 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<int>, 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<int>;
- 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<int>.
- SourceLocation getTemplateNameLoc() const { return TemplateNameLoc; }
+ /// Gets a reference to the explicit template argument list.
+ const ExplicitTemplateArgumentList &getExplicitTemplateArgs() const {
+ assert(hasExplicitTemplateArgs());
+ return *reinterpret_cast<const ExplicitTemplateArgumentList*>(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<const TemplateArgumentLoc *>(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<CXXUnresolvedMemberExpr *>(this)
+ return const_cast<CXXDependentScopeMemberExpr *>(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<int>.
- 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<ExplicitTemplateArgumentList *>(this + 1);
+ }
+
+ /// \brief Retrieve the explicit template argument list that followed the
+ /// member template name, if any.
+ const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const {
+ return const_cast<UnresolvedMemberExpr*>(this)->getExplicitTemplateArgs();
+ }
+
+ UnresolvedMemberExpr(QualType T, bool Dependent,
+ bool HasUnresolvedUsing,
+ Expr *Base, 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<Expr>(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<int>.
+ 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 9b1c640a40b2..5d2973ea9dab 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<const CXXRecordDecl *, 1, bool> 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<const CXXRecordDecl *, uint64_t> 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<const CXXRecordDecl *, uint64_t> 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<const CXXRecordDecl *, uint64_t> *bases,
unsigned numbases,
const std::pair<const CXXRecordDecl *, uint64_t> *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 867932332d09..01f4b29a61f4 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 <iterator>
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<decl_type>(
+ 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 411f215e912e..d6f6a834d9c1 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<Stmt*>(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<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(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<Stmt*>(cond);
- SubExprs[BODY] = NULL;
- }
+ SwitchStmt(VarDecl *Var, Expr *cond)
+ : Stmt(SwitchStmtClass), Var(Var), FirstCase(0)
+ {
+ SubExprs[COND] = reinterpret_cast<Stmt*>(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<Expr*>(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<Stmt*>(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<Expr*>(SubExprs[COND]); }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(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<Stmt*>(Cond);
SubExprs[INC] = reinterpret_cast<Stmt*>(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<Expr*>(SubExprs[COND]); }
Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
Stmt *getBody() { return SubExprs[BODY]; }
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index 28fe348c4591..64eea2429c5d 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 034029a16971..7102336180cf 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 6db095872b0e..b46b3dc5d2d2 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<TemplateArgumentLoc, 8> 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 c28bafe9a30f..349487f8794b 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<foo>
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<typename T, int Size>
/// 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 <p>".
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<PointerType>())
+ 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<TemplateTypeParmType>(CanonicalType);
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index 867494396020..0077a8505170 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<LiveVariables_ValueTypes,
public:
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
- LiveVariables(ASTContext& Ctx, CFG& cfg);
+ LiveVariables(AnalysisContext &AC);
/// IsLive - Return true if a variable is live at beginning of a
/// specified block.
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
index efc66776d7ca..cad702cbdb2e 100644
--- a/include/clang/Analysis/PathDiagnostic.h
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -14,31 +14,24 @@
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Diagnostic.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/FoldingSet.h"
-
-#include <vector>
#include <deque>
+#include <iterator>
#include <string>
-#include <algorithm>
+#include <vector>
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 9b58f745f0a5..8b1a329c0335 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<const BlockDecl*,void*> *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<referenced_decls_iterator, referenced_decls_iterator>
+ getReferencedBlockVars(const BlockDecl *BD);
+
/// Return the ImplicitParamDecl* associated with 'self' if this
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index f4297350ec70..58c80185435d 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<std::string> 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 8303dee49afa..4f1523a5440d 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 <typename ITER> 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 b7ed20fab250..91a4b6d1b1eb 100644
--- a/include/clang/Analysis/PathSensitive/Checker.h
+++ b/include/clang/Analysis/PathSensitive/Checker.h
@@ -40,24 +40,35 @@ class CheckerContext {
SaveAndRestore<ProgramPoint::Kind> 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 090a5d397549..4144d1a0a734 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 13437eb2ac03..000000000000
--- 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<UndefinedAssignmentChecker> {
- 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 a7bbdf939f87..76cab1ddc127 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 02e0b0275e4e..b78cc6adfc4a 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 1b6d0bdf9c10..a7302c0602ec 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<ExplodedNode*,2> ErrorNodes;
- typedef llvm::DenseMap<ExplodedNode*, Expr*> 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 <typename CHECKER>
void registerCheck(CHECKER *check) {
unsigned entry = Checkers.size();
@@ -195,58 +144,6 @@ public:
return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag()));
}
- bool isNoReturnCall(const ExplodedNode* N) const {
- return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(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 ef0c36c44d9f..d8bc2411750f 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 <functional>
@@ -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 <typename CB> CB scanReachableSymbols(SVal val) const;
+ template <typename CB> CB scanReachableSymbols(const SVal *beg,
+ const SVal *end) const;
+
+ template <typename CB> 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 <typename CB>
+CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
+ CB cb(this);
+ scanReachableSymbols(beg, end, cb);
+ return cb;
+}
+template <typename CB>
+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 06d0d976df01..ed964978a44a 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 <typename RegionTy, typename A1>
RegionTy* getRegion(const A1 a1);
@@ -667,6 +754,10 @@ public:
template <typename RegionTy, typename A1, typename A2>
RegionTy* getRegion(const A1 a1, const A2 a2);
+ template <typename RegionTy, typename A1, typename A2>
+ 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 <typename RegionTy, typename A1, typename A2>
+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<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+ InsertPos));
+
+ if (!R) {
+ R = (RegionTy*) A.Allocate<RegionTy>();
+ new (R) RegionTy(a1, a2, superRegion);
+ Regions.InsertNode(R, InsertPos);
+ }
+
+ return R;
+}
//===----------------------------------------------------------------------===//
// Traits for constructing regions.
@@ -801,18 +911,21 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> {
}
};
-template<> struct MemRegionManagerTrait<CodeTextRegion> {
+template<> struct MemRegionManagerTrait<FunctionTextRegion> {
typedef MemSpaceRegion SuperRegionTy;
static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr,
const FunctionDecl*) {
return MRMgr.getCodeRegion();
}
+};
+template<> struct MemRegionManagerTrait<BlockTextRegion> {
+ 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 8d162a681c44..ef4e069ce8e8 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<SVal> Vals) {
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 2af95808b281..bbf42ee8c7fe 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 e2f11041dce2..3f7d114dda60 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 e9b351ffe995..cbc287c58c89 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 93c655b50500..c1c833cf5c66 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 7f3f4ea1fca0..39123d9b371a 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 <FILENAME>">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3a8c5bf8f1b8..43107044720e 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 a864d8ab9e72..a0e03fed1600 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<EmptyBody>;
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 e06dfbb2cf1b..53939500e72a 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 99c100d55e7e..a16a27103b67 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 <string>
+
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<unsigned>(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 6b60f2eec097..9b50e8df02b9 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 695f51d2c4c9..49eaafec7db7 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 239712c08caf..99422332a788 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)// <foo>
// 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 02679cd99895..c8fb37b9ddc0 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 5263108d1a6d..ab1abff7409b 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<Arg*>::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<Arg*>::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 057022ce38c1..4a8bbe5feb77 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 ef8d8478282d..b34fe0340a55 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<triple>;
+
+//===----------------------------------------------------------------------===//
+// 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<analyzer_store>;
+
+def analyzer_constraints : Separate<"-analyzer-constraints">,
+ HelpText<"Source Code Analysis - Symbolic Constraint Engines">;
+def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">,
+ Alias<analyzer_constraints>;
+
+def analyzer_output : Separate<"-analyzer-output">,
+ HelpText<"Source Code Analysis - Output Options">;
+def analyzer_output_EQ : Joined<"-analyzer-output=">,
+ Alias<analyzer_output>;
+
+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<analyze_function>;
+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<code_completion_at>;
+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<"<action group>">;
+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 c0f2cc7b6777..18f3e58d7db4 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 70b59c69c264..f5b6980d8f6a 100644
--- a/include/clang/Driver/OptParser.td
+++ b/include/clang/Driver/OptParser.td
@@ -14,14 +14,20 @@
// Define the kinds of options.
-class OptionKind<string name, int predecence = 0> {
+class OptionKind<string name, int predecence = 0, bit sentinel = 0> {
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<list<OptionFlag> flags> { list<OptionFlag> Flags = flags; }
class Group<OptionGroup group> { OptionGroup Group = group; }
class HelpText<string text> { string HelpText = text; }
class MetaVarName<string name> { string MetaVarName = name; }
+
+// Predefined options.
+
+// FIXME: Have generator validate that these appear in correct position (and
+// aren't duplicated).
+def INPUT : Option<"<input>", KIND_INPUT>, Flags<[DriverOption]>;
+def UNKNOWN : Option<"<unknown>", KIND_UNKNOWN>;
diff --git a/include/clang/Driver/OptSpecifier.h b/include/clang/Driver/OptSpecifier.h
index c38b36c2f70f..bb1cd1740bbb 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 b05d5afd7578..ac312cdfd4d2 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 0e7d55e6e45b..26efa9745600 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 7dfabbadd8fd..04dc5ed8cc56 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -22,16 +22,17 @@
#include <string>
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 7a324331ecdc..24fed6e76ac1 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 d5a0598dfab2..bea468b01791 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 <cstdio>
+#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<llvm::StringRef, llvm::StringRef> ColSplit = Str.rsplit(':');
+ std::pair<llvm::StringRef, llvm::StringRef> 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 ed280508778a..d7e7d991f379 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<CodeCompleteConsumer> CompletionConsumer;
+ /// The frontend timer
+ llvm::OwningPtr<llvm::Timer> FrontendTimer;
+
/// The list of active output files.
std::list< std::pair<std::string, llvm::raw_ostream*> > 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 9d068c523c69..e7c51aabba59 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<llvm::StringRef> &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 8b80d1dc11d8..c750492a270e 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
-// <TranslationUnit> sub-nodes of the XML document.
+// This file defines the XML statement database structure as written in
+// <TranslationUnit> 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<FunctionType>()->getResultType())
ATTRIBUTE_XML(getType()->getAs<FunctionType>(), "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 469ea535f6aa..3042767af874 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -14,10 +14,6 @@
#include "llvm/ADT/OwningPtr.h"
#include <string>
-namespace llvm {
-class Timer;
-}
-
namespace clang {
class ASTUnit;
class ASTConsumer;
@@ -29,7 +25,6 @@ class FrontendAction {
std::string CurrentFile;
llvm::OwningPtr<ASTUnit> 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 197a2a05e5e0..c1ec8e70f1c6 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 000000000000..441d34f5a388
--- /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 000000000000..52aa4636084d
--- /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 b2bb9a13771d..98463c308e51 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 98831ba37fe3..f8d2eebeb687 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 <memory>
#include <string>
-#include "llvm/ADT/SmallVector.h"
namespace clang {
diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def
index fd79cf0c6ccb..2f0da9e7b117 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
-// <TranslationUnit> sub-nodes of the XML document.
+// This file defines the XML statement database structure as written in
+// <TranslationUnit> 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 4e907e1965ea..380a1dd224af 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 c2db4d357c51..52bf194883df 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 1c0036e3edcb..edd34b718969 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 3d3232b6f68e..fc56cc68476e 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<T>::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 81bb3007baea..ecaa6aee470b 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 7e7d0b3f28e8..fe899b3fdb17 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<IdentifierInfo *>(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 f7ccccac0952..81a80ebcbc61 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<std::string> &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 ed747613c385..84c179f789d1 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 dc13e7f4688c..6c9ecf089b98 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<AlignedAttr>())
- Align = std::max(Align, AA->getAlignment());
+ Align = std::max(Align, AA->getMaxAlignment());
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- 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<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
T = cast<ArrayType>(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<ReferenceType>(T)->getPointeeType().getAddressSpace();
+ Width = Target.getPointerWidth(AS);
+ Align = Target.getPointerAlign(AS);
+ break;
+ }
case Type::Pointer: {
unsigned AS = cast<PointerType>(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<ReferenceType>(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<TypedefType>(T)->getDecl();
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
- 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<TemplateArgument, 4> 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<PointerType>()) {
+ 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<TypedefType>();
- if (!TT)
- return;
- TypedefDecl *TD = TT->getDecl();
-
- // typedef struct objc_selector *SEL;
- const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>();
- 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 bdc804722c41..572d76ff72d2 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<VarDecl>(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<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ const FunctionDecl *Function = 0;
+ if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D))
+ Function = FunTmpl->getTemplatedDecl();
+ else
+ Function = cast<FunctionDecl>(D);
+
+ // Explicitly declared static.
+ if (Function->getStorageClass() == FunctionDecl::Static)
+ return NamedDecl::InternalLinkage;
+ } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // - a data member of an anonymous union.
+ if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
+ return NamedDecl::InternalLinkage;
+ }
+
+ // 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<VarDecl>(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<FunctionDecl>(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<TagDecl>(D))
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
+ return NamedDecl::ExternalLinkage;
+
+ // - an enumerator belonging to an enumeration with external linkage;
+ if (isa<EnumConstantDecl>(D))
+ if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
+ == NamedDecl::ExternalLinkage)
+ return NamedDecl::ExternalLinkage;
+
+ // - a template, unless it is a function template that has
+ // internal linkage (Clause 14);
+ if (isa<TemplateDecl>(D))
+ return NamedDecl::ExternalLinkage;
+
+ // - a namespace (7.3), unless it is declared within an unnamed
+ // namespace.
+ if (isa<NamespaceDecl>(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<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
+ (isa<TagDecl>(this) &&
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
+ cast<RecordDecl>(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<FunctionDecl>(this)) {
+ if (Function->getPreviousDeclaration())
+ if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(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<VarDecl>(this))
- return VD->hasExternalStorage() || VD->isFileVarDecl();
-
- if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this))
- return true;
-
- return false;
+ return getLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDecl() {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 831f552489f9..2dcd80b01fcc 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<NamedDecl>(TheDecl))
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(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 a21c93ffcdc9..40019880074a 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<CanQualType, 8>& ConversionsTypeSet)
+ llvm::SmallPtrSet<CanQualType, 8>& 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<FunctionTemplateDecl>(TopConv))
@@ -336,14 +331,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
bool inTopClass = (RD == this);
QualType ClassType = getASTContext().getTypeDeclType(this);
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Cs
= cast<CXXRecordDecl>(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<CXXConversionDecl>(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<CXXConversionDecl>(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<NamespaceDecl>(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<NamespaceAliasDecl>(NominatedNamespace))
+ return NA->getNamespace();
+ return cast_or_null<NamespaceDecl>(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<NamespaceDecl>(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 131de8b2e11b..a5982cfd97f1 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<DeclPrinter> {
+ class DeclPrinter : public DeclVisitor<DeclPrinter> {
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<Decl*>& 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 0c14714812f5..902339e1efcf 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<NonTypeTemplateParmDecl>(*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<TemplateTemplateParmDecl>(*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 1ff068c9862c..3471657b6523 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<void>();
+
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<clang::DeclarationName>::
getHashValue(clang::DeclarationName N) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 90b50c61f989..624a620b9fbb 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<NonTypeTemplateParmDecl>(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<VarDecl>(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<OverloadedFunctionDecl>(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<DeclRefExpr>());
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<MemberExpr>());
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<CXXDefaultArgExpr>(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<TemplateIdRefExpr>(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 0ba4608ee198..d1a0390a0a68 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<ExplicitTemplateArgumentList*>(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<ExplicitTemplateArgumentList*>(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<TemplateArgumentLoc *> (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<Stmt **>(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<CXXUnresolvedMemberExpr>());
- 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<CXXDependentScopeMemberExpr>());
+ 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<UnresolvedMemberExpr>());
+ 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 2689859e8e4a..a20e1cc6f56b 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 <cstring>
using namespace clang;
@@ -153,7 +152,7 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
}
namespace {
-class VISIBILITY_HIDDEN HasSideEffect
+class HasSideEffect
: public StmtVisitor<HasSideEffect, bool> {
EvalInfo &Info;
public:
@@ -210,7 +209,7 @@ public:
// LValue Evaluation
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN LValueExprEvaluator
+class LValueExprEvaluator
: public StmtVisitor<LValueExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -353,7 +352,7 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PointerExprEvaluator
+class PointerExprEvaluator
: public StmtVisitor<PointerExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -508,7 +507,7 @@ APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN VectorExprEvaluator
+ class VectorExprEvaluator
: public StmtVisitor<VectorExprEvaluator, APValue> {
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<IntExprEvaluator, bool> {
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<EnumConstantDecl>(E->getDecl())) {
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(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<VarDecl>(E->getDecl())) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(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<Expr*>(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<ReferenceType>())
+ 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<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
+ return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(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<ReferenceType>())
+ 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<FloatExprEvaluator, bool> {
EvalInfo &Info;
APFloat &Result;
@@ -1652,7 +1678,7 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ComplexExprEvaluator
+class ComplexExprEvaluator
: public StmtVisitor<ComplexExprEvaluator, APValue> {
EvalInfo &Info;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index b9cfcfec74f0..326a1dcd270a 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 <llvm/ADT/SmallSet.h>
#include <llvm/Support/MathExtras.h>
@@ -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<CXXRecordDecl>(i->getType()->getAs<RecordType>()->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<CXXRecordDecl>(i->getType()->getAs<RecordType>()->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<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base->isDynamicClass()) {
- // We found it.
- setPrimaryBase(Base, false);
- return;
- }
+ // Ignore virtual bases.
+ if (i->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->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<AlignedAttr>())
- 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<CXXRecordDecl>(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<const CXXRecordDecl*, 32> 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<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
@@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
+ uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+
+ if (FieldPacked)
+ FieldAlign = 1;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ 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<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
- FieldPacked |= D->hasAttr<PackedAttr>();
-
- 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<ReferenceType>()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Ctx.Target.getPointerWidth(AS);
+ FieldAlign = Ctx.Target.getPointerAlign(AS);
+ } else {
std::pair<uint64_t, unsigned> 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<AlignedAttr>())
- 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<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
- } else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- FieldSize = FieldInfo.first;
- FieldAlign = FieldInfo.second;
- }
+ if (FieldPacked)
+ FieldAlign = 8;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
- if (FieldPacked)
- FieldAlign = 8;
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- 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<CXXRecordDecl>(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 077072343b1b..69e0498917c7 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<uint64_t, 16> 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<std::pair<const CXXRecordDecl *,
uint64_t>, 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 6e0da4714912..fad80ec0cf23 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 93bf8755d580..bbe6a7120141 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 <cstdio>
using namespace clang;
@@ -26,7 +25,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
+ class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
FILE *F;
unsigned IndentLevel;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 4bd7f964be6c..205ea0d182d4 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<StmtPrinter> {
+ class StmtPrinter : public StmtVisitor<StmtPrinter> {
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 4458c2b9cd25..d832a4649e75 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<StmtProfiler> {
+ class StmtProfiler : public StmtVisitor<StmtProfiler> {
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 61fd750ccc83..8be287e7cb21 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -30,8 +30,9 @@ void Stmt::viewAST() const {
namespace llvm {
template<>
struct DOTGraphTraits<const Stmt*> : 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 ff02f9a31cb2..f341b45fb971 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<TemplateTemplateParmDecl>(
+ 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 297534eaf1fc..5a2434da3c37 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 a48233378286..562e830b367e 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 640912ad6b39..339e2c93cea9 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<FindBlockDeclRefExprsVals>{
+ BumpVector<const VarDecl*> &BEVals;
+ BumpVectorContext &BC;
+public:
+ FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &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<VarDecl>(DR->getDecl()))
+ BEVals.push_back(VD, BC);
+ }
+};
+} // end anonymous namespace
+
+typedef BumpVector<const VarDecl*> 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<DeclVec>();
+ new (BV) DeclVec(BC, 10);
+
+ // Find the referenced variables.
+ FindBlockDeclRefExprsVals F(*BV, BC);
+ F.Visit(BD->getBody());
+
+ Vec = BV;
+ return BV;
+}
+
+std::pair<AnalysisContext::referenced_decls_iterator,
+ AnalysisContext::referenced_decls_iterator>
+AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
+ if (!ReferencedBlockVars)
+ ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
+
+ DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
+ return std::make_pair(V->begin(), V->end());
+}
+
+//===----------------------------------------------------------------------===//
+// 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 549a22bec172..3d95ab183471 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<ArrayBoundChecker> {
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 01e1a1fcf69b..aa21700c2483 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<AttrNonNullChecker> {
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 7a7ea188ba59..000000000000
--- 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<BadCallChecker> {
- 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<loc::ConcreteInt>(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 d0b828952854..6c3f7b2245df 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<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
@@ -46,7 +45,7 @@ struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
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 c2ecfa1f417f..c91377986496 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<ClassReleaseChecker> {
+ 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 ea4d3ecfcaee..679c6dc1df2d 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 800a76fb0aee..45fc11a534a5 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<const MemRegion*,SVal> 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 8235f4acb179..c26a60af9c85 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -119,7 +119,7 @@ typedef llvm::DenseMap<const ExplodedNode*,
const ExplodedNode*> 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<ParentMap> 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<SymbolRef, 10> 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<ContextLocation> CLocs;
typedef std::vector<ContextLocation>::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 89c9ca10ec57..87de30ae7aec 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 31417597f798..c97692f57082 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> 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<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
StmtMapTy StmtMap;
@@ -1668,7 +1670,7 @@ public:
namespace {
-class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
+class CFGBlockTerminatorPrint
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
llvm::raw_ostream& OS;
@@ -2047,8 +2049,10 @@ void CFG::viewCFG(const LangOptions &LO) const {
namespace llvm {
template<>
struct DOTGraphTraits<const CFG*> : 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 55e5f174cb9f..b95f981275e6 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 <stdarg.h>
@@ -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<ObjCSummaryKey> {
} // end llvm namespace
namespace {
-class VISIBILITY_HIDDEN ObjCSummaryCache {
+class ObjCSummaryCache {
typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
MapTy M;
public:
@@ -776,7 +777,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RetainSummaryManager {
+class RetainSummaryManager {
//==-----------------------------------------------------------------==//
// Typedefs.
@@ -1865,8 +1866,8 @@ typedef llvm::ImmutableList<SymbolRef> 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<AutoreleaseStack>
@@ -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<FunctionDecl*>(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<BlockDataRegion>(L.getAsRegion())) {
+ Summ = Summaries.getPersistentStopSummary();
+ }
+ else {
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ Summ = !FD ? Summaries.getDefaultSummary() :
+ Summaries.getSummary(const_cast<FunctionDecl*>(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<DefinedOrUnknownSVal>(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<CFRefBug*>(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<RetainReleaseChecker> {
+ 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<BlockDataRegion>(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<StopTrackingCallback>(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 8e8c1e7b25ed..409292d451d8 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 000000000000..d8dd16c57b81
--- /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<CallAndMessageChecker> {
+ 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<loc::ConcreteInt>(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<DefinedOrUnknownSVal>(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 06e3317691e3..c1040f0c9949 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -137,8 +137,10 @@ namespace llvm {
template <>
struct DOTGraphTraits<CallGraph> : 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 cca8584a61fa..43523c293d58 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 ccd4a3333e22..a3663421a082 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<CastToStructChecker> {
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 d5cb7ca7fdd3..ad63eb4122b0 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<DeclRefExpr>(B->getLHS()))
if (VarDecl *VD = dyn_cast<VarDecl>(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<IntegerLiteral>(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<DeclRefExpr>(RHS))
@@ -226,7 +224,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
+class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
CFG *cfg;
public:
FindEscaped(CFG *c) : cfg(c) {}
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp
index 92e3e112d9f1..87c1f270a65c 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 8c0d39629d50..10ba896557df 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 2d9b53163f6a..d4067c900f3f 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<FunctionDecl>(*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 f1b9c2194f8b..e6ab17a75905 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<WalkAST> {
+class WalkAST : public StmtVisitor<WalkAST> {
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 174beefbca45..4f5da9f5a716 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<WalkAST> {
+class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
public:
diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp
new file mode 100644
index 000000000000..0d907e501686
--- /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 c3aa8f3a2879..98243874d7d9 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<ExplodedNode*, 2> 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<UnaryOperator>(S);
+ const Expr *SU = U->getSubExpr()->IgnoreParens();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ llvm::raw_svector_ostream os(buf);
+ os << "Dereference of null pointer loaded from variable '"
+ << VD->getName() << '\'';
+ }
+ }
+ }
+ 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 a8630f10088e..266c23609422 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<DivZeroChecker> {
+class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
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 1610ad4d271d..dd2f08b48f76 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 80096dcb70d0..031ca44b602e 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<FixedAddressChecker> {
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 b99ba4f257ef..644dd199bead 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 <vector>
@@ -30,7 +29,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DFS : public GRWorkList {
+class DFS : public GRWorkList {
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
@@ -49,7 +48,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BFS : public GRWorkList {
+class BFS : public GRWorkList {
std::queue<GRWorkListUnit> 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<GRWorkListUnit> Queue;
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 26331776141f..20820d4f3833 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<GRSimpleAPICheck*> Checks;
typedef llvm::DenseMap<void*,Checks> 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<AsmStmt>(S), Pred, Dst);
break;
+ case Stmt::BlockExprClass:
+ VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ break;
+
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(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<DefinedSVal>(&X);
-
- if (!V) {
- if (X.isUnknown()) {
- if (const Expr *Ex = dyn_cast<Expr>(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<Expr>(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<DefinedSVal>(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<loc::ConcreteInt>(V) || isa<UndefinedVal>(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<DefinedOrUnknownSVal>(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<DefinedOrUnknownSVal>(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<IdentifierInfo*, NUM_RAISE_SELECTORS> 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<IdentifierInfo*, NUM_RAISE_SELECTORS> 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<bool> 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<bool> 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<SVal> 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<ExplodedNode*> :
+struct DOTGraphTraits<ExplodedNode*> :
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<ExplodedNode*> :
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 2fb7e9fa482f..33479b0cb7e5 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 d0f60fde5b1b..000000000000
--- 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 <typename ITERATOR> 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<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
-}
-
-template <typename ITER>
-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<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(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<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(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<PostStmt>()->getStmt();
- BuiltinBugReport *report = NULL;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(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<StmtPoint>()->getStmt();
- const Stmt *X = S;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(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<ArgReport*>(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<PostStmt>(N->getLocation()).getStmt();
- const Expr* E = cast<ObjCMessageExpr>(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<Expr>(*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<BlockEdge>((*I)->getLocation());
- Expr* Ex = cast<Expr>(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<PostStmt>(&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<ArgReport*>(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 a9077bf75715..5b7a7572ed7d 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 23ee0b2258bd..a56859dde5bf 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<const MemRegion*> 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 2510445a7f31..84e268f3fdaa 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<RegisterDecls> {
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<TransferFuncs>{
+class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
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<VarDecl>(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 93e708332ed7..204c7b320e65 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<MallocChecker> {
+class MallocChecker : public CheckerVisitor<MallocChecker> {
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<RegionState>(Sym, RefState::getAllocated(CE));
- C.addTransition(C.GenerateNode(CE, AllocState));
+ C.addTransition(state->set<RegionState>(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<RegionState>(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<bool> OldHasGen(B.HasGeneratedNode);
const GRState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
SymMap M = state->get<RegionState>();
@@ -212,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
if (RS->isAllocated())
state = state->set<RegionState>(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 8c0b85c0c729..af8bd16ee681 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<VarRegion>(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<StackFrameContext>(LC))
+ LC = LC->getParent();
+
+ return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+}
+
CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
return getRegion<CompoundLiteralRegion>(CL);
@@ -287,10 +342,17 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) {
- return getRegion<CodeTextRegion>(FD);
+FunctionTextRegion *
+MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+ return getRegion<FunctionTextRegion>(FD);
+}
+
+BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD,
+ CanQualType locTy) {
+ return getRegion<BlockTextRegion>(BD, locTy);
}
+
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getRegion<SymbolicRegion>(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<const MemRegion*> VarVec;
+ VarVec *BV = (VarVec*) A.Allocate<VarVec>();
+ 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<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->begin();
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->end();
+}
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp
index e0a8d0dc5f73..2ff04878f7ab 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<NSAutoreleasePoolChecker> {
Selector releaseS;
@@ -65,6 +64,9 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// the type of the expression.
const ObjCObjectPointerType* PT =
receiver->getType()->getAs<ObjCObjectPointerType>();
+
+ if (!PT)
+ return;
const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
if (!OD)
return;
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp
index 93b617b115d9..e3cf57fd0c1b 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 93823484e1d0..370233ce38bd 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<PointerArithChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(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 4c7906f4beba..c597a2580751 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<PointerSubChecker> {
BuiltinBug *BT;
public:
@@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(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 66206616b008..e95095c7975e 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<PthreadLockChecker> {
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<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
@@ -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<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+ const FunctionTextRegion *R =
+ dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
if (!R)
return;
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index f5cae698f924..7330b6261479 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<const llvm::APSInt*,
+class Range : public std::pair<const llvm::APSInt*,
const llvm::APSInt*> {
public:
Range(const llvm::APSInt &from, const llvm::APSInt &to)
@@ -59,7 +58,7 @@ public:
};
-class VISIBILITY_HIDDEN RangeTrait : public llvm::ImutContainerInfo<Range> {
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
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<Range, RangeTrait> PrimRangeSet;
PrimRangeSet ranges; // no need to make const, since it is an
// ImmutableSet - this allows default operator=
@@ -232,7 +231,7 @@ struct GRStateTrait<ConstraintRange>
}
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 ae3fa14c2a26..e645172a5b66 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<const MemRegion*, BindingVal> 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<RegionExtents>
@@ -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<const MemRegion*> SetTy;
typedef llvm::DenseMap<const MemRegion*, SetTy> 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<SVal> 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<nonloc::CompoundVal>(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<RegionStoreSubRegionMap>
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<const MemRegion*, 10> 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<SymbolicRegion>(R))
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
+
+ // For BlockDataRegions, enqueue all VarRegions for that are referenced
+ // via BlockDeclRefExprs.
+ if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
+ RI != RE; ++RI)
+ 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 44887b2625da..ab0fcab4219e 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<ReturnPointerRangeChecker> {
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 e4be8712d09b..3a6d8a41c069 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<ReturnStackAddressChecker> {
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<BlockDataRegion>(R)) {
+ const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+ SourceLocation L = BD->getLocStart();
+ range = BD->getSourceRange();
+ os << "Address of stack-allocated block declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
else {
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 796c7608c86d..7cd71265805b 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<ReturnUndefChecker> {
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 d5d36e3b9090..9163b2725273 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<loc::MemRegionVal>(this)) {
const MemRegion* R = X->getRegion();
- if (const CodeTextRegion *CTR = R->getAs<CodeTextRegion>())
+ if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
return CTR->getDecl();
}
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 4487aa9d3028..2afcd3e847cd 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 2fd72ac0a148..2fd573c4764d 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 000000000000..c739d1ac4b22
--- /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<Expr>(*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<BlockEdge>(N->getLocation());
+ Expr* Ex = cast<Expr>(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<PostStmt>(&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 000000000000..acc86dda5a97
--- /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<UndefResultChecker> {
+
+ 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 923a7e1bed0b..000000000000
--- 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<UndefinedArgChecker> {
- 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 887c7755fe45..d6aacaf1f85e 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<UndefinedArraySubscriptChecker> {
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 b8062f359562..4630b823a91e 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<UndefinedAssignmentChecker> {
+ 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 8e7b15862d66..6fa4b539dc40 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<RegisterDecls> {
UninitializedValues::AnalysisDataTy& AD;
@@ -52,7 +51,7 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN TransferFuncs
+class TransferFuncs
: public CFGStmtVisitor<TransferFuncs,bool> {
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 799a73e293c8..2690d6f0cffc 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<VLASizeChecker> {
+class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
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 fe670e79b3b5..22a821149dbb 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 b6c4df87f272..a1f97f4eeb24 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 07c2bb960bcf..e5a4c434c341 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -313,6 +313,42 @@ public:
}
};
+// PS3 PPU Target
+template<typename Target>
+class PS3PPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &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<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
+// FIXME: Need a real SPU target.
+// PS3 SPU Target
+template<typename Target>
+class PS3SPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PS3 PPU defines.
+ Define(Defs, "__SPU__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PS3SPUTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// AuroraUX target
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
@@ -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<PPC64TargetInfo>(T);
+ else if (os == llvm::Triple::Lv2)
+ return new PS3PPUTargetInfo<PPC64TargetInfo>(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<PPC64TargetInfo>(T);
+
case llvm::Triple::systemz:
return new SystemZTargetInfo(T);
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 4afeaf01b776..8cdc1e31950c 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 bc9eb67674ff..2df779ce9f52 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<NamedDecl>(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<FunctionType>()->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 399b8733e720..be4c27ce53ad 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<llvm::PointerType>(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 b1d30a68bbb7..34d1c8d984a1 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<CXXDestructorDecl>(MD))
- if (Destructor->isTrivial())
- return RValue::get(0);
-
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
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<CXXDestructorDecl>(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<FunctionProtoType>();
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<llvm::Function>(
@@ -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<FunctionType>()->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<NonNullAttr>() */ );
@@ -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<CXXDestructorDecl>(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<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, 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<CXXRecordDecl>(BaseType->getAs<RecordType>()->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<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ 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/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d0c7d03f20ef..decc73c6d458 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<QualType, 16> 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<FunctionProtoType>();
+ 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<QualType, 16> 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<FunctionProtoType>();
+ 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<CXXMethodDecl>(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<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (const TagType *TT = T->getArgType(i)->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const llvm::Type *
+CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ 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/CGCXXClass.cpp b/lib/CodeGen/CGClass.cpp
index 533aabc8616e..b3c2b986d190 100644
--- a/lib/CodeGen/CGCXXClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===//
+//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -31,9 +31,6 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
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 =
@@ -75,7 +72,7 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
if (!const_cast<CXXRecordDecl *>(ClassDecl)->
isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
@@ -84,21 +81,20 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
unsigned Start = 0;
llvm::Value *VirtualOffset = 0;
- if (const RecordType *RT = Paths.getDetectedVirtual()) {
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(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;
+
+ const CXXBasePath &Path = Paths.front();
+ const CXXRecordDecl *VBase = 0;
+ for (unsigned i = 0, e = Path.size(); i != e; ++i) {
+ const CXXBasePathElement& Element = Path[i];
+ if (Element.Base->isVirtual()) {
+ Start = i+1;
+ QualType VBaseType = Element.Base->getType();
+ VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
}
}
+ if (VBase)
+ VirtualOffset =
+ CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
uint64_t Offset =
ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
@@ -117,10 +113,10 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
}
llvm::Value *
-CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- bool NullCheckValue) {
+CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue) {
QualType BTy =
getContext().getCanonicalType(
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
@@ -128,7 +124,7 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
if (ClassDecl == BaseClassDecl) {
// Just cast back.
- return Builder.CreateBitCast(BaseValue, BasePtrTy);
+ return Builder.CreateBitCast(Value, BasePtrTy);
}
llvm::BasicBlock *CastNull = 0;
@@ -141,8 +137,8 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
CastEnd = createBasicBlock("cast.end");
llvm::Value *IsNull =
- Builder.CreateICmpEQ(BaseValue,
- llvm::Constant::getNullValue(BaseValue->getType()));
+ Builder.CreateICmpEQ(Value,
+ llvm::Constant::getNullValue(Value->getType()));
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
@@ -150,16 +146,16 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
llvm::Value *Offset =
- GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
+ GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
if (Offset) {
// Apply the offset.
- BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
- BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, Offset, "add.ptr");
}
// Cast back.
- BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
+ Value = Builder.CreateBitCast(Value, BasePtrTy);
if (NullCheckValue) {
Builder.CreateBr(CastEnd);
@@ -167,13 +163,73 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
Builder.CreateBr(CastEnd);
EmitBlock(CastEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
+ 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<CXXRecordDecl*>(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(BaseValue, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
CastNull);
- BaseValue = PHI;
+ Value = PHI;
}
- return BaseValue;
+ return Value;
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 055166721085..317da7e46a75 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 349ede51c63b..c0472830925d 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 adfd0055f936..420e275becd1 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<const llvm::Type*> 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<const llvm::Type*> 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<const llvm::Type*> 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<CXXRecordDecl>(ObjectType->getAs<RecordType>()->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<FunctionType>()->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<CXXRecordDecl>(ObjectType->getAs<RecordType>()->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<FunctionType>()->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<llvm::Value*, 8> 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; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ 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; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ 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<llvm::Value*, 8> 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 2a544c560931..63fca2d4ddab 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<BlockDeclRefExpr>(E));
- case Expr::CXXConditionDeclExprClass:
- return EmitCXXConditionDeclLValue(cast<CXXConditionDeclExpr>(E));
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXConstructExprClass:
return EmitCXXConstructLValue(cast<CXXConstructExpr>(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<FunctionProtoType>()) {
+ // 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<BlocksAttr>()) {
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<FunctionDecl>(ND)) {
- llvm::Value* V = CGM.GetAddrOfFunction(FD);
- if (!FD->hasPrototype()) {
- if (const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>()) {
- // 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<FunctionDecl>(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<VarDecl>(ND))
return EmitGlobalVarDeclLValue(*this, E, VD);
-
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(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<RecordType>();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseClassTy->getDecl());
+
+ const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
+ CXXRecordDecl *DerivedClassDecl =
+ cast<CXXRecordDecl>(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 0e10368ab04e..d225d907c8ae 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<AggExprEmitter> {
+class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
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<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
- const CXXRecordDecl *DstDecl =
+ const CXXRecordDecl *DerivedDecl =
cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->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/CGCXXExpr.cpp b/lib/CodeGen/CGExprCXX.cpp
index cd7d21b3b951..b982c15683ec 100644
--- a/lib/CodeGen/CGCXXExpr.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ expressions ---------------===//
+//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -83,38 +83,41 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
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 (!E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end());
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
- return;
- }
+ return;
+ }
- // We have a POD type.
- if (E->getNumConstructorArgs() == 0)
- 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.");
+ assert(E->getNumConstructorArgs() == 1 &&
+ "Can only have one argument to initializer of POD type.");
- const Expr *Init = E->getConstructorArg(0);
+ 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);
+ 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) {
@@ -359,7 +362,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
Expr *subE = E->getExprOperand();
Ty = subE->getType();
@@ -403,7 +406,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
}
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 9e81e4fbeabe..7fa8ffbd5515 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<ComplexExprEmitter, ComplexPairTy> {
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 40b845dba050..9289f78d557a 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<ConstExprEmitter, llvm::Constant*> {
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 e9bbf35fcd8d..c1cbecc9fa85 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 <cstdarg>
@@ -45,7 +44,7 @@ struct BinOpInfo {
};
namespace {
-class VISIBILITY_HIDDEN ScalarExprEmitter
+class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
@@ -141,8 +140,11 @@ public:
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (const EnumConstantDecl *EC = dyn_cast<EnumConstantDecl>(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<CXXThisExpr>(E)) {
+ // We always assume that 'this' is never null.
+ return false;
+ }
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(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<Expr*>(E));
+ case CastExpr::CK_BaseToDerived: {
+ const CXXRecordDecl *BaseClassDecl =
+ E->getType()->getCXXRecordDeclForPointerType();
+ const CXXRecordDecl *DerivedClassDecl =
+ DestTy->getCXXRecordDeclForPointerType();
+
+ Value *Src = Visit(const_cast<Expr*>(E));
+
+ bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
+ return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
+ NullCheckValue);
+ }
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -787,23 +829,19 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
- bool NullCheckValue = true;
-
- if (isa<CXXThisExpr>(E)) {
- // We always assume that 'this' is never null.
- NullCheckValue = false;
- } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(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<Expr*>(E));
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(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<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(CE->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->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<Expr*>(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<Expr*>(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<Expr*>(E));
- const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
- return CGF.EmitDynamicCast(V, DCE);
- }
-
case CastExpr::CK_VectorSplat: {
const llvm::Type *DstTy = ConvertType(DestTy);
Value *Elt = Visit(const_cast<Expr*>(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<MemberPointerType>();
+
+ 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<Expr*>(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 b431daa958f0..be772c7fa311 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -747,9 +747,14 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
std::vector<llvm::Constant*> 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<llvm::Constant*>::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 4355e66feecd..2e8ab2987db3 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 a63c8325ffa7..1a9bc3917092 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<CXXRecordDecl>(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 79d866427f0b..43fcb31858f8 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<RecordType>())
- if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(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<MemberPointerType>())
@@ -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<RecordType>())
+ if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(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 b6d7b3990452..bbd546261800 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<Expr>(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/CGCXXTemp.cpp b/lib/CodeGen/CGTemporaries.cpp
index 4768556f6bca..5cfc7efade42 100644
--- a/lib/CodeGen/CGCXXTemp.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXTemp.cpp - Emit LLVM Code for C++ temporaries ---------------===//
+//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
// Check if temporaries need to be conditional. If so, we'll create a
// condition boolean, initialize it to 0 and
- if (!ConditionalTempDestructionStack.empty()) {
+ if (ConditionalBranchLevel != 0) {
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
// Initialize it to false. This initialization takes place right after
@@ -141,23 +141,3 @@ LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
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/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 9be1a3b22b33..715aa4c03c10 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 <cstdio>
using namespace clang;
using namespace CodeGen;
+namespace {
class VtableBuilder {
public:
/// Index_t - Vtable index type.
@@ -52,54 +54,110 @@ private:
llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
- typedef llvm::DenseMap<GlobalDecl, int> Pures_t;
- Pures_t Pures;
- typedef std::pair<Index_t, Index_t> CallOffset;
- typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t;
- Thunks_t Thunks;
- typedef llvm::DenseMap<GlobalDecl,
- std::pair<std::pair<CallOffset, CallOffset>,
- 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<GlobalDecl, Thunk> 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<GlobalDecl, CovariantThunk> CovariantThunksMapTy;
+ CovariantThunksMapTy CovariantThunks;
+
+ /// PureVirtualMethods - Pure virtual methods.
+ typedef llvm::DenseSet<GlobalDecl> PureVirtualMethodsSetTy;
+ PureVirtualMethodsSetTy PureVirtualMethods;
+
std::vector<Index_t> VCalls;
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable
- // for use in computing the initializers for the VTT.
- llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints;
+ // subAddressPoints - Used to hold the AddressPoints (offsets) into the built
+ // vtable for use in computing the initializers for the VTT.
+ llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
typedef CXXRecordDecl::method_iterator method_iter;
const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
- llvm::Constant *cxa_pure;
+ static llvm::DenseMap<CtorVtable_t, int64_t>&
+ 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<CtorVtable_t, int64_t> *&ref = (*oref)[c];
+ if (ref == 0)
+ ref = new llvm::DenseMap<CtorVtable_t, int64_t>;
+ 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<llvm::Constant *> &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<CtorVtable_t, int64_t>),
+ 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<const llvm::Type*> 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<GlobalDecl, Index_t> &getIndex() { return Index; }
llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
{ return VBIndex; }
- llvm::DenseMap<CtorVtable_t, int64_t> *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<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
if (D != Class)
- return VBlookup(D, B);
+ return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
llvm::DenseMap<const CXXRecordDecl *, Index_t>::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<FunctionType>()->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<CXXMethodDecl>(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<CXXMethodDecl>(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<CXXDestructorDecl>(MD))
return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- 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<CXXRecordDecl *>(DerivedDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return false;
+ }
+
+ // If we found a virtual base we always want to require adjustment.
+ if (Paths.getDetectedVirtual())
+ return true;
+
+ const CXXBasePath &Path = Paths.front();
+
+ for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
+ const CXXBasePathElement &Element = Path[Start];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ if (Layout.getBaseClassOffset(Base) != 0) {
+ // This requires an adjustment.
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+TypeConversionRequiresAdjustment(ASTContext &Ctx,
+ QualType DerivedType, QualType BaseType) {
+ // Canonicalize the types.
+ QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
+ QualType CanBaseType = Ctx.getCanonicalType(BaseType);
+
+ assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
+ CanDerivedType = RT->getPointeeType();
+ CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
+ } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
+ CanDerivedType = PT->getPointeeType();
+ CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
+
+ return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
+}
+
+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<FunctionType>()->getResultType();
+ QualType OverriddenReturnType =
+ OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
+
+ if (!TypeConversionRequiresAdjustment(CGM.getContext(),
+ ReturnType, OverriddenReturnType)) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
+
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ ShouldAddEntryForMethod = false;
+ break;
+ }
+ }
+ }
+
+ if (!ShouldAddEntryForMethod)
+ continue;
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(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<const CXXRecordDecl *, uint64_t>::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<CXXMethodDecl>(GD.getDecl())->getParent();
-
- std::vector<llvm::Constant *> 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<llvm::Constant *> 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<CXXMethodDecl>(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<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
+ return;
+
+ // Emit the data.
+ GenerateClassData(RD);
+}
+
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 78ae670cf35a..5c2b74c9dd86 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<GlobalDecl, int64_t> MethodVtableIndicesTy;
MethodVtableIndicesTy MethodVtableIndices;
-
+
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
-
+
/// VirtualBaseClassIndicies - Contains the index into the vtable where the
/// offsets for virtual bases of a class are stored.
typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
+
+ /// NumVirtualFunctionPointers - Contains the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> 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 10884a7560f5..92814169d0ab 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 475c7bfefd1d..6e0a77ca1b0b 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<CXXMethodDecl>(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<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
void CodeGenFunction::GenerateCode(GlobalDecl GD,
llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(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 d96c3551010e..7f3204587a95 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<CXXLiveTemporaryInfo, 4> 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<size_t, 4> 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 195acc5bc157..4b3b122b71cf 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<AlignedAttr>())
- F->setAlignment(AA->getAlignment()/8);
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) {
+ unsigned width = Context.Target.getCharWidth();
+ F->setAlignment(AA->getAlignment() / width);
+ while ((AA = AA->getNext<AlignedAttr>()))
+ F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width));
+ }
// C++ ABI requires 2-byte alignment for member functions.
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(D))
+ getVtableInfo().MaybeEmitVtable(GD);
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(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<CXXConstructorDecl>(FD)) {
- const CXXRecordDecl *ClassDecl =
- cast<CXXRecordDecl>(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<CXXDestructorDecl>(FD)) {
+ if (DD->isImplicit())
+ DeferredDeclsToEmit.push_back(D);
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isCopyAssignment() && MD->isImplicit())
DeferredDeclsToEmit.push_back(D);
}
- else if (isa<CXXDestructorDecl>(FD))
- DeferredDestructorToEmit(D);
- else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<CXXConstructorDecl>(CopyCtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(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<CXXMethodDecl>(CopyAssignDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(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<CXXDestructorDecl>(DtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(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<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->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<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(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<SectionAttr>()) {
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<FunctionDecl>(D)->getDescribedFunctionTemplate())
+ return;
+
EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index c8562d6745eb..78bc4ed845d8 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<const CXXRecordDecl *, uint64_t> CtorVtable_t;
typedef llvm::DenseMap<const CXXRecordDecl *,
@@ -427,9 +428,6 @@ private:
llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
const llvm::PointerType *PTy,
const VarDecl *D);
- void DeferredCopyConstructorToEmit(GlobalDecl D);
- void DeferredCopyAssignmentToEmit(GlobalDecl D);
- void DeferredDestructorToEmit(GlobalDecl D);
/// SetCommonAttributes - Set attributes which are common to any
/// form of a global definition (alias, Objective-C method,
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 1f83f37e0479..c89879fdb6c4 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -38,7 +38,13 @@ CodeGenTypes::~CodeGenTypes() {
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
- CGRecordLayouts.clear();
+ {
+ llvm::FoldingSet<CGFunctionInfo>::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 f447549f669c..2ff602f900fa 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -20,6 +20,7 @@
#include <vector>
#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 0a7124de3621..d6f7808c4073 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<uintptr_t, unsigned> 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<NamedDecl>(ND->getCanonicalDecl());
+
+static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Passed in decl is not a ctor or dtor!");
+
+ if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
+ MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
- addSubstitution(reinterpret_cast<uintptr_t>(ND));
- }
- void addSubstitution(QualType T);
- void addSubstitution(uintptr_t Ptr);
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(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<uintptr_t, unsigned> Substitutions;
+
+public:
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res)
+ : Context(C), Out(Res), Structor(0), StructorType(0) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &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<NamedDecl>(ND->getCanonicalDecl());
+
+ addSubstitution(reinterpret_cast<uintptr_t>(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<AsmLabelAttr>())
+ 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<OverloadableAttr>() && !isa<CXXMethodDecl>(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<FunctionDecl>(D);
+ if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(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<AsmLabelAttr>()) {
// 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;
}
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
-
- // FIXME: Actually use a visitor to decode these?
+ Out << Prefix;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return mangleFunctionDecl(FD);
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(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) {
- // <special-name> ::= TV <type> # virtual table
- Out << "_ZTV";
- mangleName(RD);
-}
-
-void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
- // <special-name> ::= TT <type> # VTT structure
- Out << "_ZTT";
- mangleName(RD);
-}
-
-void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type) {
- // <special-name> ::= TC <type> <offset number> _ <base type>
- Out << "_ZTC";
- mangleName(RD);
- Out << Offset;
- Out << "_";
- mangleName(Type);
-}
-
-void CXXNameMangler::mangleCXXRtti(QualType Ty) {
- // <special-name> ::= TI <type> # typeinfo structure
- Out << "_ZTI";
-
- mangleType(Ty);
-}
-
-void CXXNameMangler::mangleCXXRttiName(QualType Ty) {
- // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
- Out << "_ZTS";
-
- mangleType(Ty);
-}
-
-void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
- // <special-name> ::= GV <object name> # Guard variable for one-time
- // # initialization
-
- Out << "_ZGV";
- mangleName(D);
+ mangleFunctionEncoding(FD);
+ else
+ mangleName(cast<VarDecl>(D));
}
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
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<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
isa<CXXConversionDecl>(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<NamespaceDecl>(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<NamespaceDecl>(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<LinkageSpecDecl>(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<FunctionDecl>(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<LinkageSpecDecl>(DC)) {
- assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
+ assert(cast<LinkageSpecDecl>(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 <unqualified-name> # ::std::
if (isStdNamespace(ND->getDeclContext()))
Out << "St";
-
+
mangleUnqualifiedName(ND);
}
@@ -381,61 +333,39 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
// ::= <substitution>
if (mangleSubstitution(ND))
return;
-
+
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
-void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) {
+void CXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [n] <non-negative decimal integer>
+ if (Number < 0) {
+ Out << 'n';
+ Number = -Number;
+ }
+
+ Out << Number;
+}
+
+void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number> # non-virtual base override
- // <v-offset> ::= <offset nubmer> _ <virtual offset number>
+ // <v-offset> ::= <offset number> _ <virtual offset number>
// # 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) {
- // <special-name> ::= T <call-offset> <base encoding>
- // # 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) {
- // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
- // # 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<TagDecl>(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] $_<id>
+ // [n] $_<id>
// where n is the length of the string.
llvm::SmallString<8> Str;
Str += "$_";
@@ -525,6 +455,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
cast<FunctionDecl>(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<CXXMethodDecl>(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) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
-
+
mangleTemplatePrefix(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
-
+
Out << 'E';
}
@@ -591,23 +527,23 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
-
+
if (DC->isTranslationUnit())
return;
-
+
if (mangleSubstitution(cast<NamedDecl>(DC)))
return;
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(DC->getParent());
mangleUnqualifiedName(cast<NamedDecl>(DC));
}
-
+
addSubstitution(cast<NamedDecl>(DC));
}
@@ -618,12 +554,12 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
if (mangleSubstitution(ND))
return;
-
+
// FIXME: <template-param>
-
+
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<TemplateSpecializationType>(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<TemplateTypeParmType>(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<DeclRefExpr>(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<UnresolvedDeclRefExpr>(E);
+
+ case Expr::DependentScopeDeclRefExprClass: {
+ const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
const Type *QTy = DRE->getQualifier()->getAsType();
assert(QTy && "Qualifier was not type!");
// ::= sr <type> <unqualified-name> # 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) {
// <template-args> ::= I <template-arg>+ 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) {
// <template-args> ::= I <template-arg>+ 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: {
// <expr-primary> ::= L <type> <value number> 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: {
+ // <expr-primary> ::= L <mangled-name> 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<NamedDecl>(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<NamedDecl>(ND->getCanonicalDecl());
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
@@ -1208,79 +1152,79 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
if (const RecordType *RT = T->getAs<RecordType>())
return mangleSubstitution(RT->getDecl());
}
-
+
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
return mangleSubstitution(TypePtr);
}
bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I =
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I =
Substitutions.find(Ptr);
if (I == Substitutions.end())
return false;
-
+
unsigned SeqID = I->second;
if (SeqID == 0)
Out << "S_";
else {
SeqID--;
-
+
// <seq-id> 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<unsigned char>(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<RecordType>();
if (!RT)
return false;
-
- const ClassTemplateSpecializationDecl *SD =
+
+ const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(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<ClassTemplateDecl>(ND)) {
if (!isStdNamespace(TD->getDeclContext()))
return false;
-
+
// <substitution> ::= Sa # ::std::allocator
if (TD->getIdentifier()->isStr("allocator")) {
Out << "Sa";
return true;
}
-
+
// <<substitution> ::= Sb # ::std::basic_string
if (TD->getIdentifier()->isStr("basic_string")) {
Out << "Sb";
return true;
}
}
-
- if (const ClassTemplateSpecializationDecl *SD =
+
+ if (const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
// <substitution> ::= Ss # ::std::basic_string<char,
// ::std::char_traits<char>,
// ::std::allocator<char> >
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;
}
-
- // <substitution> ::= So # ::std::basic_ostream<char,
+
+ // <substitution> ::= So # ::std::basic_ostream<char,
// ::std::char_traits<char> >
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<uintptr_t>(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<CXXConstructorDecl>(D) &&
- "Use mangleCXXCtor for constructor decls!");
- assert(!isa<CXXDestructorDecl>(D) &&
- "Use mangleCXXDtor for destructor decls!");
-
- PrettyStackTraceDecl CrashInfo(const_cast<NamedDecl *>(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<CXXDestructorDecl>(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<CXXDestructorDecl>(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<char> &Res) {
+ assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
+ "Invalid mangleName() call, argument is not a variable or function!");
+ assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(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<char> &Res) {
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.mangle(D);
+}
+
+void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &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<char> &Res) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(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);
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # 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<char> &Res) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(FD) &&
+ "Use mangleCXXDtor for destructor decls!");
- os.flush();
- }
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # 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<char> &Res) {
+ // <special-name> ::= GV <object name> # 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<char> &Res) {
+ // <special-name> ::= TV <type> # 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<char> &Res) {
+ // <special-name> ::= TT <type> # 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<char> &Res) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ 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<char> &Res) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTI";
+ Mangler.mangleType(Ty);
+}
- os.flush();
- }
+void MangleContext::mangleCXXRttiName(QualType Ty,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TS <type> # 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 458708fca6ad..65b1d9f9618d 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<typename T> class SmallVectorImpl;
}
namespace clang {
@@ -34,50 +34,59 @@ namespace clang {
class NamedDecl;
class VarDecl;
- class MangleContext {
- ASTContext &Context;
-
- llvm::DenseMap<const TagDecl *, uint64_t> 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<const TagDecl *, uint64_t> AnonStructIds;
+
+public:
+ explicit MangleContext(ASTContext &Context)
: Context(Context) { }
-
- ASTContext &getASTContext() const { return Context; }
-
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *,
- uint64_t>::iterator, bool> Result =
+
+ ASTContext &getASTContext() const { return Context; }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::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<char> &);
+ void mangleThunk(const FunctionDecl *FD,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCovariantThunk(const FunctionDecl *FD,
+ const CovariantThunkAdjustment& Adjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCXXRtti(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &);
+
+ /// @}
+};
+
+}
}
#endif
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 1d8f31dd9b24..017059df80fa 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<const llvm::TargetData> TD;
ASTContext *Ctx;
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index ba0bc6668e27..2bc61753a031 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<CXXRecordDecl>(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<CXXRecordDecl>(i->getType()->getAs<RecordType>()->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 ea75c34ea566..8a57d14932d3 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 672fe0401e48..13f84c07df50 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
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 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 ffa627ad2810..b819cda89c09 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 b40dc27740d0..87357cf08a3b 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -965,10 +965,9 @@ void Driver::BuildJobs(Compilation &C) const {
if (isa<FlagOption>(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 eddaee0546cc..d1af95cd4504 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
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 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 5f0551b138ed..eb165cf6a531 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 750286b66c96..339767722716 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 e3cd6ddd08d6..f647c8a23705 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<ASTUnit> 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 ede3d474c848..5df1eceb8850 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<GRTransferFuncs> 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<ExplodedNode::Auditor> 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<GRTransferFuncs> 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 bc56029e73d2..9dc109da65ef 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<const char *> 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<std::string>::iterator
+ for (std::vector<std::string>::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 3f0f43099c69..03123d303f0c 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 339a1c466bc9..7296246df21a 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<const IdentifierInfo*,uint32_t> IDMap;
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> 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 0365761c840e..1083d5ef1c02 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<llvm::raw_fd_ostream> 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 b4a79c6d1efb..c5375079506b 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<llvm::StringRef> &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<std::string> &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<std::string> &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<std::string> &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<std::string>
+getAllArgValues(ArgList &Args, cc1options::ID ID) {
+ llvm::SmallVector<const char *, 16> Values;
+ Args.AddAllArgValues(Values, ID);
+ return std::vector<std::string>(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<AnalysisStores>(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<AnalysisConstraints>(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<AnalysisDiagClients>(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<FrontendOptions::InputKind>(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<std::string> 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/<version>/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<LangStandard::Kind>(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<OptTable> Opts(createCC1OptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ llvm::OwningPtr<InputArgList> 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 c7f93595e1ea..478c33939cd7 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 <string>
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
+class DependencyFileCallback : public PPCallbacks {
std::vector<std::string> Files;
llvm::StringSet<> FilesSet;
const Preprocessor *PP;
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
index 26bb6ccfa7c7..e7a66b1729c4 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 ff63a0dab5f9..91c946c9cf25 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 7a7537bce40f..27e194e6f108 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 0e4f83ff09f5..6251bac04758 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 <string>
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<unsigned char> 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 3ba7abf38168..93421ca4013d 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 d19ae9861ed6..a40a569d92f7 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 b77c24093f5f..972c21f88d4d 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 000000000000..771a58c60501
--- /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<Kind>(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 c9679b7d1e7f..cb96bcb48aec 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<PCHMethodPoolLookupTrait>
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<uint64_t> &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<PCHStatLookupTrait> 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 6a92a2db51a8..03f3b4767994 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 01af67dd50a1..00734a0854a4 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<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast<Expr>(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<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast<Expr>(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<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setCond(cast_or_null<Expr>(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<Expr>(StmtStack[StmtStack.size() - 3]));
+ S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
S->setInc(cast_or_null<Expr>(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 8a45ebce1b9d..e79f9c9dac19 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 <cstdio>
@@ -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<AsmLabelAttr>(Attr)->getLabel(), Record);
break;
+ case Attr::BaseCheck:
+ break;
+
case Attr::Blocks:
Record.push_back(cast<BlocksAttr>(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 78a56db7edcd..27b83ed6cbb2 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 6bcf39a92a24..80ee2c2e8eba 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<const PathDiagnostic*> BatchedDiags;
const std::string OutputFile;
const LangOptions &LangOpts;
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index deb5498b906e..c5dc979f654b 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 b5d59c0aa401..0bcbd4ff0ee4 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 06955e5c30b6..710fa55b69bf 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 4a3c0bf1c60f..c0977b5b2707 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<StmtXML> {
+ class StmtXML : public StmtVisitor<StmtXML> {
DocumentXML& Doc;
//static const char *getOpcodeStr(UnaryOperator::Opcode Op);
@@ -61,8 +60,6 @@ namespace {
Doc.PrintDecl(*DI);
}
} else {
- if (CXXConditionDeclExpr* CCDE = dyn_cast<CXXConditionDeclExpr>(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 34bc3c796aa8..fdf2ec8ccf5d 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 2891aec50444..99ec910be0af 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 ccaf3499a425..15b6eaa62708 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 300a46922056..fb3529d5405c 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 366cf1b10830..d6e30ab39658 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<RefMapper> {
+class RefMapper : public ASTVisitor<RefMapper> {
DeclReferenceMap::MapTy &Map;
public:
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index ed905f364f0d..c7379f7a8352 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<StmtLocResolver,
ASTLocation > {
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<DeclLocResolver,
ASTLocation > {
public:
diff --git a/lib/Index/SelectorMap.cpp b/lib/Index/SelectorMap.cpp
index 325b3711e804..0f11e31a0dec 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<SelMapper> {
+class SelMapper : public ASTVisitor<SelMapper> {
SelectorMap::SelMethMapTy &SelMethMap;
SelectorMap::SelRefMapTy &SelRefMap;
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index f4a44324106a..52a7a04567a6 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 42dd75e59b94..ab669422b277 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 dc7d95e70118..9caca339be32 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 41ed991436b9..8a61d7b9c247 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 d6a73cc74f6a..a64008ab1806 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<unsigned char, const char*> 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<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index dde4bc866ac5..df48e3a7861f 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 7681eac6ed8a..aa0b89b1a3a2 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<TypeNameInfo>())
if (TI->isTypeName)
return TI;
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index c34653ee425c..b9314d242442 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 2bfda30a951b..b13dc7335670 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<TypeTy*, 2> Exceptions;
llvm::SmallVector<SourceRange, 2> 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 914bfc9db89d..505a4d800ded 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 d2b3b84eb7fc..f780cf1a6054 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 b2ecc9e827f1..52003e6fa1b2 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 5ba1dd17bdf8..295625ae272d 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 7637382ac032..c87010e356a0 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 16b1c800800f..0dbf37c830fc 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 7ac297710965..dabd065a979a 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 a9152745b3f7..e321564336f1 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 b4bf419bc5f4..342b0e6ef5e5 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<Token> 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 0effbb18b8ac..789d53f4afaf 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 a9d83010576a..91b16d3774d4 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 <algorithm>
#include <cstring>
@@ -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 << "&lt;"; break;
- case '>': OS << "&gt;"; break;
- case '&': OS << "&amp;"; break;
- case '"': OS << "&quot;"; break;
- case '\'': OS << "&apos;"; 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<char>(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 << "<typed-text>" << EscapedString(C->Text) << "</>";
- break;
case CK_Text:
- OS << "<text>" << EscapedString(C->Text) << "</>";
- break;
- case CK_Optional:
- OS << "<optional>";
- C->Optional->Serialize(OS);
- OS << "</>";
- break;
case CK_Placeholder:
- OS << "<placeholder>" << EscapedString(C->Text) << "</>";
- break;
case CK_Informative:
- OS << "<informative>" << 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 << "<current-parameter>" << EscapedString(C->Text) << "</>";
+ }
+
+ case CK_Optional:
+ C->Optional->Serialize(OS);
break;
+
case CK_LeftParen:
- OS << "<lparen/>";
- break;
case CK_RightParen:
- OS << "<rparen/>";
- break;
case CK_LeftBracket:
- OS << "<lbracket/>";
- break;
case CK_RightBracket:
- OS << "<rbracket/>";
- break;
case CK_LeftBrace:
- OS << "<lbrace/>";
- break;
case CK_RightBrace:
- OS << "<rbrace/>";
- break;
case CK_LeftAngle:
- OS << "<langle/>";
- break;
case CK_RightAngle:
- OS << "<rangle/>";
- break;
case CK_Comma:
- OS << "<comma/>";
break;
- }
+ }
}
}
-/// \brief Parse the next XML-ish tag of the form <blah>.
-///
-/// \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., <comma/>.
-///
-/// \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<unsigned>(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<CodeCompletionString> Optional(Deserialize(Str));
+
+ case CK_Optional: {
+ std::auto_ptr<CodeCompletionString> 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<RecordDecl>(Results[I].Declaration)) {
- if (Record->isStruct())
- OS << "Struct:";
- else if (Record->isUnion())
- OS << "Union:";
- else
- OS << "Class:";
- } else if (ObjCMethodDecl *Method
- = dyn_cast<ObjCMethodDecl>(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 << "<typed-text>"
- << 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<RecordDecl>(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<ObjCMethodDecl>(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:<typed-text>" << 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 << "<typed-text>" << 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 10cc818b8baa..e2134a2683d6 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 <class DeclClass>
+ DeclClass *getAsSingle() const {
+ if (getResultKind() != Found) return 0;
+ return dyn_cast<DeclClass>(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<FunctionTemplateDecl>(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<UnresolvedUsingValueDecl>(*I))
+ return true;
+ return false;
+ }
+
static void deletePaths(CXXBasePaths *);
// Results.
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index 7b223a8fa3b6..7c7df4bb61b4 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 fe2d7448b42f..f0812bfe7fdb 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 ad4c90bdc2a5..b594eceaf3c6 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<std::pair<SourceLocation, Decl *> >
+ /// \brief The set of declarations that have been referenced within
+ /// a potentially evaluated expression.
+ typedef std::vector<std::pair<SourceLocation, Decl *> >
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<PotentiallyReferencedDecls> 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<ExpressionEvaluationContextRecord, 8> 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<NamedDecl*>& 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<NamedDecl*> &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<FieldDecl *> &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<NamedDecl*>& 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<TemplateArgumentLoc> &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<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &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<Expr *, 8> &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 6dbb4426c20c..b386adb9df57 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<OverloadedFunctionDecl>(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<FunctionDecl>(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<FunctionTemplateDecl>(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<TemplateDecl>(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<ObjCMethodDecl>(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<NamedDecl*,8> 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 b5109f825e57..520d7de710bd 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<OverloadedFunctionDecl>(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<OverloadedFunctionDecl>(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<StringLiteral>(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<RecordType>()->getDecl();
-
+
FindOverriddenMethodData *Data
= reinterpret_cast<FindOverriddenMethodData*>(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<CXXMethodDecl>(*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<CXXMethodDecl>(*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<CXXMethodDecl>(NewFD))
AddOverriddenMethods(cast<CXXRecordDecl>(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<StringLiteral>(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<TemplateArgumentLoc, 16> 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<CXXMethodDecl>(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 c96ab4681cc5..b2124fe01459 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<Expr>();
+ CXXScopeSpec SS;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+ sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
} 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<BlockDecl>(d)) {
ValueDecl *VD = dyn_cast<ValueDecl>(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<ParmVarDecl>(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<CXXRecordDecl>(d)
+ && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(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<FinalAttr>()) {
+ 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<CXXRecordDecl>(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<BaseCheckAttr>()) {
+ 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<RecordDecl>(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<HidingAttr>()) {
+ 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<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(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<OverrideAttr>()) {
+ 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 bda1a6993934..f161cb5546a2 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 <algorithm> // for std::equal
#include <map>
#include <set>
@@ -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<CheckDefaultArgumentVisitor, bool> {
Expr *DefaultArg;
Sema *S;
@@ -354,9 +352,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
if (CheckEquivalentExceptionSpec(
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation())) {
+ New->getType()->getAs<FunctionProtoType>(), 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<FinalAttr>()) {
+ 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<Expr*>(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<Decl>();
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<AbstractClassUsageDiagnoser, bool> {
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<NamespaceAliasDecl>(D))
+ return AD->getNamespace();
+ return dyn_cast_or_null<NamespaceDecl>(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<NamespaceDecl>(NS) && "expected namespace decl");
+ NamedDecl *Named = R.getFoundDecl();
+ assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(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<DeclContext>(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<NamespaceDecl>(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<NamespaceAliasDecl>(D))
- return AD->getNamespace();
- return dyn_cast_or_null<NamespaceDecl>(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<CXXRecordDecl>(ClassType->getAs<RecordType>()->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<FunctionProtoType>();
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<Expr>();
- }
-
- 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<Expr *, 8> 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<CXXRecordDecl>(T2->getAs<RecordType>()->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<FunctionTemplateDecl>(*Func);
+ = dyn_cast<FunctionTemplateDecl>(*I);
CXXConversionDecl *Conv;
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*Func);
+ Conv = cast<CXXConversionDecl>(*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<FinalAttr>()) {
+ 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<VarDecl>(Dcl.getAs<Decl>());
+ VD->setDeclaredInCondition(true);
+ return Dcl;
+}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4f08ffe9db94..f653cf63d803 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<GNUNullExpr>(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<TemplateName>();
+
+ 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<TemplateName>();
+
+ 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<NestedNameSpecifier *>(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<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(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<CXXRecordDecl>(DC)) return false;
+
+ // We can't look into record types unless they're fully-formed.
+ if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(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<CXXMethodDecl>(SemaRef.CurContext))
+ CurRecord = cast<CXXRecordDecl>(CurMethod->getParent());
+ else
+ CurRecord = dyn_cast<CXXRecordDecl>(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<Expr>(), 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<Expr>();
+ 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<VarDecl>(D)) {
+ // This is guaranteed from this point on.
+ assert(!R.empty() || ADL);
+
+ if (VarDecl *Var = R.getAsSingle<VarDecl>()) {
// 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<FunctionDecl>(D)) {
+ } else if (FunctionDecl *Func = R.getAsSingle<FunctionDecl>()) {
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<FunctionProtoType>())
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<CXXRecordDecl>((*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<Expr>(), 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<FunctionTemplateDecl>(D))
+ Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
+ ->getTemplatedDecl());
+ else if (isa<CXXMethodDecl>(D))
+ Method = cast<CXXMethodDecl>(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<CXXRecordDecl>(DC)) {
- QualType DType;
- if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- DType = FD->getType().getNonReferenceType();
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- DType = Method->getType();
- } else if (isa<OverloadedFunctionDecl>(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<FieldDecl>(D))
+ // FIXME: template-ids inside anonymous structs?
+ if (FieldDecl *FD = R.getAsSingle<FieldDecl>())
if (cast<RecordDecl>(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<CXXMethodDecl>(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<FieldDecl>(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<FieldDecl>()) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<TypedefDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name);
- if (isa<ObjCInterfaceDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name);
- if (isa<NamespaceDecl>(D))
- return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name);
-
- // Make the DeclRefExpr or BlockDeclRefExpr for the decl.
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
- return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
- false, false, SS);
- else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
- return BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
- false, false, SS);
- else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(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<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(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<FunctionDecl>(D)) {
+ FunctionDecl *FDecl = cast<FunctionDecl>(D);
+
+ // But also builtin functions.
+ if (FDecl->getBuiltinID() && FDecl->isImplicit())
+ return false;
+ } else if (!isa<FunctionTemplateDecl>(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<TypedefDecl>(D)) {
+ S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName();
+ return true;
+ }
+
+ if (isa<ObjCInterfaceDecl>(D)) {
+ S.Diag(Loc, diag::err_unexpected_interface) << D->getDeclName();
+ return true;
+ }
+
+ if (isa<NamespaceDecl>(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<FunctionTemplateDecl>(D) &&
+ "Cannot refer unambiguously to a function template");
+ DeclarationName Name = D->getDeclName();
+
+ if (CheckDeclInExpr(*this, Loc, D))
+ return ExprError();
ValueDecl *VD = cast<ValueDecl>(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<FunctionDecl>(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<CXXRecordDecl>(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<NonTypeTemplateParmDecl>(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<VarDecl>(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<ReferenceType>())
+ 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<Expr>();
+
+ // 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<PointerType>();
+ 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<NestedNameSpecifier*>(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<TypeDecl>((*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<Expr>();
+
+ 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<Expr>();
+ QualType BaseType = BaseExpr->getType();
+ if (IsArrow) {
+ assert(BaseType->isPointerType());
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
+
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(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<RecordType>()->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<CXXMethodDecl>(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<FieldDecl>(MemberDecl)) {
+ // We may have found a field within an anonymous union or struct
+ // (C++ [class.union]).
+ if (cast<RecordDecl>(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<ReferenceType>())
+ 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<VarDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, Var);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Var, MemberLoc,
+ Var->getType().getNonReferenceType()));
+ }
+
+ if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ MemberFn, MemberLoc,
+ MemberFn->getType()));
+ }
+
+ if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ MarkDeclarationReferenced(MemberLoc, MemberDecl);
+ return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
+ Enum, MemberLoc, Enum->getType()));
+ }
+
+ Owned(BaseExpr);
+
+ if (isa<TypeDecl>(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<PointerType>()) {
@@ -1767,8 +2270,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
= Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
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<PointerType>()->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<Expr>();
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<NestedNameSpecifier *>(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<PointerType>())
+ if (IsArrow) {
+ if (const PointerType *PT = BaseType->getAs<PointerType>())
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<PointerType>();
-
- if (!PT || (getLangOptions().ObjC1 &&
- !PT->getPointeeType()->isRecordType())) {
- NestedNameSpecifier *Qualifier = 0;
- if (SS) {
- Qualifier = static_cast<NestedNameSpecifier *>(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<RecordType>()) {
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<TypeDecl>(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<TypeDecl>(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<CXXMethodDecl>(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<FieldDecl>(MemberDecl)) {
- // We may have found a field within an anonymous union or struct
- // (C++ [class.union]).
- if (cast<RecordDecl>(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<ReferenceType>())
- 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<VarDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- Var, MemberLoc,
- Var->getType().getNonReferenceType()));
- }
- if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- MemberFn, MemberLoc,
- MemberFn->getType()));
- }
- if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(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<OverloadedFunctionDecl>(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<EnumConstantDecl>(MemberDecl)) {
- MarkDeclarationReferenced(MemberLoc, MemberDecl);
- return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
- Enum, MemberLoc, Enum->getType()));
- }
- if (isa<TypeDecl>(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<ObjCObjectPointerType>();
const ObjCInterfaceType *IFaceT =
OPT ? OPT->getInterfaceType() : BaseType->getAs<ObjCInterfaceType>();
@@ -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<ObjCObjectPointerType>();
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<CXXPseudoDestructorExpr>(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<NestedNameSpecifier*>(SS.getScopeRep())));
+
+ // This is a postfix expression, so get rid of ParenListExprs.
+ BaseArg = MaybeConvertParenListExprToParenExpr(S, move(BaseArg));
+
+ Expr *Base = BaseArg.takeAs<Expr>();
+ 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<TemplateArgumentLoc, 16> 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<CXXPseudoDestructorExpr>(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<Expr *, 8> AllArgs;
+ VariadicCallType CallType =
+ Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
+ if (Fn->getType()->isBlockPointerType())
+ CallType = VariadicBlock; // Block
+ else if (isa<MemberExpr>(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<Expr *, 8> &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<Expr>();
} 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<Expr>();
}
-
- 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<MemberExpr>(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<NamedDecl*> &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<ImplicitCastExpr>(FnExpr))
FnExpr = IcExpr->getSubExpr();
else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
- // Parentheses around a function disable ADL
- // (C++0x [basic.lookup.argdep]p1).
- ArgumentDependentLookup = false;
FnExpr = PExpr->getSubExpr();
} else if (isa<UnaryOperator>(FnExpr) &&
cast<UnaryOperator>(FnExpr)->getOpcode()
== UnaryOperator::AddrOf) {
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
} else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) {
- Function = dyn_cast<NamedDecl>(DRExpr->getDecl());
- if ((Qualifier = DRExpr->getQualifier())) {
- ArgumentDependentLookup = false;
+ Fns.push_back(cast<NamedDecl>(DRExpr->getDecl()));
+ ArgumentDependentLookup = false;
+ if ((Qualifier = DRExpr->getQualifier()))
QualifierRange = DRExpr->getQualifierRange();
- }
break;
- } else if (UnresolvedFunctionNameExpr *DepName
- = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) {
- Name = DepName->getName();
- break;
- } else if (TemplateIdRefExpr *TemplateIdRef
- = dyn_cast<TemplateIdRefExpr>(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<UnresolvedLookupExpr>(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>();
Expr **Args = reinterpret_cast<Expr**>(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<UnresolvedMemberExpr>(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<FunctionTemplateDecl>(*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<MemberExpr>(Fn->IgnoreParens())) {
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
NamedDecl *MemDecl = MemExpr->getMemberDecl();
- if (isa<OverloadedFunctionDecl>(MemDecl) ||
- isa<CXXMethodDecl>(MemDecl) ||
- (isa<FunctionTemplateDecl>(MemDecl) &&
- isa<CXXMethodDecl>(
- cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
+ if (isa<CXXMethodDecl>(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<BinaryOperator>(Fn->IgnoreParens())) {
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(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<NamedDecl*,8> 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<FunctionDecl>(NDecl);
- if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(NDecl)))
- FDecl = FunctionTemplate->getTemplatedDecl();
- else
- FDecl = dyn_cast<FunctionDecl>(NDecl);
- Ovl = dyn_cast<OverloadedFunctionDecl>(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<FunctionDecl>(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<FunctionTemplateDecl>(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<FunctionDecl>(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<Expr**>(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<UnresolvedLookupExpr>(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<OverloadedFunctionDecl>(dcl) ||
- isa<FunctionTemplateDecl>(dcl)) {
+ } else if (isa<FunctionTemplateDecl>(dcl)) {
return Context.OverloadTy;
} else if (FieldDecl *FD = dyn_cast<FieldDecl>(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 462bf13540eb..00fb65df92c7 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<Expr *, 8> AllPlaceArgs;
+ if (OperatorNew) {
+ // Add default arguments, if any.
+ const FunctionProtoType *Proto =
+ OperatorNew->getType()->getAs<FunctionProtoType>();
+ 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<RecordType>()) {
llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(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<FunctionTemplateDecl>(*Func))
+ if (isa<FunctionTemplateDecl>(*I))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -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<VarDecl>(Dcl.getAs<Decl>());
- 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<CXXConstructorDecl>(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<Expr>();
+
+ // 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<Expr>();
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<Expr>(),
- 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<CXXMethodDecl>(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<FieldDecl>(D)) {
+ if (R.isUnresolvableResult()) {
+ // FIXME: this is just picking one at random
+ Ctx = R.getRepresentativeDecl()->getDeclContext();
+ } else if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) {
Ctx = FD->getDeclContext();
- MemberType = FD->getType();
-
- if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
- 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<CXXMethodDecl>(*Ovl);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I);
FunctionTemplateDecl *FunTmpl = 0;
- if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)))
+ if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*I)))
Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
// FIXME: Do we have to know if there are explicit template arguments?
if (Method && !Method->isStatic()) {
Ctx = Method->getParent();
- if (isa<CXXMethodDecl>(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<CXXRecordDecl>(Ctx));
QualType ClassType
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 0f973d6d9ba3..2eba704ff3a3 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<InitListExpr>(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 1957d7ff11b7..8f0982740d4a 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<UnresolvedUsingValueDecl>(Decls[0]))
+ if (isa<FunctionTemplateDecl>(Decls[0]))
+ ResultKind = FoundOverloaded;
+ else if (isa<UnresolvedUsingValueDecl>(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<FunctionTemplateDecl>(D)) {
+ HasFunction = true;
+ HasFunctionTemplate = true;
+ } else if (isa<FunctionDecl>(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<UnaryOperator>(Arg)) {
- if (unaryOp->getOpcode() == UnaryOperator::AddrOf) {
- DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
- TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr());
- }
- } else {
- DRE = dyn_cast<DeclRefExpr>(Arg);
- TIRE = dyn_cast<TemplateIdRefExpr>(Arg);
- }
+ if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(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<NamedDecl*, 8> Functions;
- OverloadedFunctionDecl *Ovl = 0;
- if (DRE)
- Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
- else if (TIRE)
- Ovl = TIRE->getTemplateName().getAsOverloadedFunctionDecl();
- if (!Ovl)
+ if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(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<FunctionDecl>(*Func);
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Functions.begin(),
+ E = Functions.end(); I != E; ++I) {
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I);
if (!FDecl)
- FDecl = cast<FunctionTemplateDecl>(*Func)->getTemplatedDecl();
+ FDecl = cast<FunctionTemplateDecl>(*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 daf5b7f36008..6ea6a145576d 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 <algorithm>
#include <cstdio>
@@ -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<typename T>
-static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
- FunctionTemplateDecl *&FunctionTemplate) {
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
- if (FunctionTemplate)
- Function = cast<T>(FunctionTemplate->getTemplatedDecl());
- else
- Function = cast<T>(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<CXXRecordDecl>(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<FunctionTemplateDecl>(*I)))
Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = dyn_cast<CXXConversionDecl>(*Func);
+ Conv = dyn_cast<CXXConversionDecl>(*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<CXXConstructorDecl>(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<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) &&
!cast<CXXMethodDecl>(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<FunctionTemplateDecl>(Decl)) {
assert(isa<CXXMethodDecl>(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<CXXRecordDecl>(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<FunctionTemplateDecl>(*I))
continue;
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*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<CXXRecordDecl>(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<CXXConversionDecl>(*Func)) {
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
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<FunctionDecl>(*Func)) {
- if (HasExplicitTemplateArgs)
+ if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
false, false, PartialOverloading);
} else
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*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<NamedDecl*,8> Fns;
- // Try to dig out the overloaded function.
- FunctionTemplateDecl *FunctionTemplate = 0;
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) {
- Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl());
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl());
- HasExplicitTemplateArgs = DR->hasExplicitTemplateArgumentList();
- ExplicitTemplateArgs = DR->getTemplateArgs();
- NumExplicitTemplateArgs = DR->getNumTemplateArgs();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) {
- Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl());
- FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl());
- HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList();
- ExplicitTemplateArgs = ME->getTemplateArgs();
- NumExplicitTemplateArgs = ME->getNumTemplateArgs();
- } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) {
- TemplateName Name = TIRE->getTemplateName();
- Ovl = Name.getAsOverloadedFunctionDecl();
- FunctionTemplate =
- dyn_cast_or_null<FunctionTemplateDecl>(Name.getAsTemplateDecl());
-
- HasExplicitTemplateArgs = true;
- ExplicitTemplateArgs = TIRE->getTemplateArgs();
- NumExplicitTemplateArgs = TIRE->getNumTemplateArgs();
+ // Look into the overloaded expression.
+ if (UnresolvedLookupExpr *UL
+ = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
+ Fns.append(UL->decls_begin(), UL->decls_end());
+ if (UL->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
+ } else if (UnresolvedMemberExpr *ME
+ = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
+ Fns.append(ME->decls_begin(), ME->decls_end());
+ if (ME->hasExplicitTemplateArgs()) {
+ HasExplicitTemplateArgs = true;
+ ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+ }
}
-
- // If 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<FunctionDecl *, 4> Matches;
bool FoundNonTemplateFunction = false;
- for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) {
+ for (llvm::SmallVectorImpl<NamedDecl*>::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<FunctionTemplateDecl>(*Fun)) {
+ = dyn_cast<FunctionTemplateDecl>(*I)) {
if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(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<FunctionDecl>(Specialization->getCanonicalDecl()));
}
+
+ continue;
}
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*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<FunctionDecl>(*Fun)) {
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) {
if (FunctionType == Context.getCanonicalType(FunDecl->getType())) {
- Matches.insert(cast<FunctionDecl>(Fun->getCanonicalDecl()));
+ Matches.insert(cast<FunctionDecl>(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<UsingShadowDecl>(Callee))
+ Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl();
+
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(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<FunctionTemplateDecl>(Callee);
- S.AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- Args, NumArgs, CandidateSet);
-
- if (FuncTemplate->getDeclContext()->isRecord())
- ArgumentDependentLookup = false;
+ }
+
+ if (FunctionTemplateDecl *FuncTemplate
+ = dyn_cast<FunctionTemplateDecl>(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<NamedDecl*> &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<OverloadedFunctionDecl>(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<FunctionDecl>(Callee) || isa<FunctionTemplateDecl>(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<UsingShadowDecl>(Fns[I]) ||
+ !Fns[I]->getDeclContext()->isFunctionOrMethod());
+ assert(Fns[I]->getUnderlyingDecl()->isFunctionOrFunctionTemplate());
+ }
+ }
+#endif
+
+ for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
+ E = Fns.end(); I != E; ++I)
+ AddOverloadedCallCandidate(*this, *I, ExplicitTemplateArgs,
+ Args, NumArgs, CandidateSet,
PartialOverloading);
- // FIXME: assert isa<FunctionDecl> || isa<FunctionTemplateDecl> 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<NamedDecl*> &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<FunctionTemplateDecl>(*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<ParenExpr>(MemExprE))
- MemExpr = dyn_cast<MemberExpr>(ParenE->getSubExpr());
- else
- MemExpr = dyn_cast<MemberExpr>(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<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
- isa<FunctionTemplateDecl>(MemExpr->getMemberDecl())) {
+ if (isa<MemberExpr>(NakedMemExpr)) {
+ MemExpr = cast<MemberExpr>(NakedMemExpr);
+ ObjectArg = MemExpr->getBase();
+ Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ } else {
+ UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(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<CXXMethodDecl>(*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<CXXMethodDecl>(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<FunctionTemplateDecl>(*Func),
- MemExpr->hasExplicitTemplateArgumentList(),
- MemExpr->getTemplateArgs(),
- MemExpr->getNumTemplateArgs(),
+ } else {
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgs;
+ if (UnresExpr->hasExplicitTemplateArgs())
+ UnresExpr->copyTemplateArgumentsInto(TemplateArgs);
+
+ AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(MemExpr->getMemberDecl());
+ MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+ MemExpr = cast<MemberExpr>(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<CXXRecordDecl>(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<FunctionTemplateDecl>(*I))
continue;
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*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<ParenExpr>(E)) {
- Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
- PE->setSubExpr(NewExpr);
- PE->setType(NewExpr->getType());
- } else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(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<ImplicitCastExpr>(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<UnaryOperator>(E)) {
+ if (SubExpr == ICE->getSubExpr())
+ return ICE->Retain();
+
+ return new (Context) ImplicitCastExpr(ICE->getType(),
+ ICE->getCastKind(),
+ SubExpr,
+ ICE->isLvalueCast());
+ }
+
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
"Can only take the address of an overloaded function");
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
if (Method->isStatic()) {
// Do nothing: static member functions aren't any different
// from non-member functions.
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(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<RecordDecl>(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<DeclRefExpr>(SubExpr)
+ && "fixed to something other than a decl ref");
+ assert(cast<DeclRefExpr>(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<RecordDecl>(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<DeclRefExpr>(E)) {
- assert((isa<OverloadedFunctionDecl>(DR->getDecl()) ||
- isa<FunctionTemplateDecl>(DR->getDecl()) ||
- isa<FunctionDecl>(DR->getDecl())) &&
- "Expected function or function template");
- DR->setDecl(Fn);
- E->setType(Fn->getType());
- } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
- MemExpr->setMemberDecl(Fn);
- E->setType(Fn->getType());
- } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(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<UnresolvedFunctionNameExpr>(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<UnresolvedLookupExpr>(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<UnresolvedMemberExpr>(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 d0f214fbd83d..de67a5f1a75f 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<DeclGroupRef>();
+
+ // 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<Expr>(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<Expr>();
-
- assert(condExpr && "ActOnIfStmt(): missing expression");
- if (CheckBooleanCondition(condExpr, IfLoc)) {
- CondResult = condExpr;
+ VarDecl *ConditionVar = 0;
+ if (CondVar.get()) {
+ ConditionVar = CondVar.getAs<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
+ }
+ Expr *ConditionExpr = CondResult.takeAs<Expr>();
+ 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<Expr>();
-
- 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<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
}
-
- SwitchStmt *SS = new (Context) SwitchStmt(Cond);
+ SwitchStmt *SS = new (Context) SwitchStmt(ConditionVar,
+ CondResult.takeAs<Expr>());
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<CXXConversionDecl *, 4> ViableConversions;
+ llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
+ if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
+ const UnresolvedSet *Conversions
+ = cast<CXXRecordDecl>(RecordTy->getDecl())
+ ->getVisibleConversionFunctions();
+ for (UnresolvedSet::iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*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<Expr>();
- 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<VarDecl>();
+ CondResult = CheckConditionVariable(ConditionVar);
+ if (CondResult.isInvalid())
+ return StmtError();
+ }
+ Expr *ConditionExpr = CondResult.takeAs<Expr>();
+ if (!ConditionExpr)
+ return StmtError();
+
+ if (CheckBooleanCondition(ConditionExpr, WhileLoc)) {
+ CondResult = ConditionExpr;
return StmtError();
}
Stmt *bodyStmt = Body.takeAs<Stmt>();
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<Stmt*>(first.get());
- Expr *Second = second.takeAs<Expr>();
- Expr *Third = static_cast<Expr*>(third.get());
- Stmt *Body = static_cast<Stmt*>(body.get());
if (!getLangOptions().CPlusPlus) {
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
@@ -676,20 +795,33 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
}
+
+ OwningExprResult SecondResult(second.release());
+ VarDecl *ConditionVar = 0;
+ if (secondVar.get()) {
+ ConditionVar = secondVar.getAs<VarDecl>();
+ SecondResult = CheckConditionVariable(ConditionVar);
+ if (SecondResult.isInvalid())
+ return StmtError();
+ }
+
+ Expr *Second = SecondResult.takeAs<Expr>();
if (Second && CheckBooleanCondition(Second, ForLoc)) {
- second = Second;
+ SecondResult = Second;
return StmtError();
}
+ Expr *Third = third.release().takeAs<Expr>();
+ Stmt *Body = static_cast<Stmt*>(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 31cd30083ed4..f47577e9097e 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<OverloadedFunctionDecl>(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<FunctionTemplateDecl>(*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<FunctionTemplateDecl>(*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<FunctionTemplateDecl>(*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<NestedNameSpecifier *>(SS.getScopeRep());
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template))
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ Ovl));
+ else
+ TemplateResult
+ = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
+ cast<TemplateDecl>(Template)));
+ } else if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(Template)) {
+ TemplateResult = TemplateTy::make(TemplateName(Ovl));
+ } else {
+ TemplateResult = TemplateTy::make(
+ TemplateName(cast<TemplateDecl>(Template)));
+ }
+
+ if (isa<ClassTemplateDecl>(Template) ||
+ isa<TemplateTemplateParmDecl>(Template))
+ return TNK_Type_template;
+
+ assert((isa<FunctionTemplateDecl>(Template) ||
+ isa<OverloadedFunctionDecl>(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<ClassTemplateDecl>(OuterTemplate)) {
+ } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>()) {
// - 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<NestedNameSpecifier *>(SS.getScopeRep());
- if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(Template))
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
- Ovl));
- else
- TemplateResult
- = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false,
- cast<TemplateDecl>(Template)));
- } else if (OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(Template)) {
- TemplateResult = TemplateTy::make(TemplateName(Ovl));
- } else {
- TemplateResult = TemplateTy::make(
- TemplateName(cast<TemplateDecl>(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 T> class A : Base<T> {
+ // class Inner : A<T> {
+ // void foo() {
+ // Base<T>::foo(); // statically known to be an implicit member
+ // reference
+ // }
+ // };
+ // };
+
+ CanQual<RecordType> RT = BaseT->getAs<RecordType>();
+
+ // Base might be a dependent member type, in which case we
+ // obviously can't look into it.
+ if (!RT) continue;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
+ if (BaseRecord->isDefinition() &&
+ HasDependentTypeAsBase(Context, BaseRecord, T))
+ return true;
}
- if (isa<ClassTemplateDecl>(Template) ||
- isa<TemplateTemplateParmDecl>(Template))
- return TNK_Type_template;
+ return false;
+}
- assert((isa<FunctionTemplateDecl>(Template) ||
- isa<OverloadedFunctionDecl>(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<CXXMethodDecl>(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 T> class Base { ... };
+ // template <class T> class Derived : Base<T> {
+ // void foo() {
+ // Base<T>::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<CXXRecordDecl>(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<NestedNameSpecifier*>(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<NestedNameSpecifier*>(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<TemplateArgumentLoc> &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<TemplateTypeParmDecl>(*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<TemplateTypeParmDecl>(*OldParam) : 0;
@@ -929,6 +1126,15 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*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<NonTypeTemplateParmDecl>(*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<TemplateTemplateParmDecl>(*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<TemplateTemplateParmDecl>(*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<const TemplateSpecializationType *, 4>
TemplateIdsInSpecifier;
+ llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
+ ExplicitSpecializationsInSpecifier;
for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
NNS; NNS = NNS->getPrefix()) {
if (const TemplateSpecializationType *SpecType
@@ -1062,10 +1277,10 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
= cast<ClassTemplateSpecializationDecl>(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<TemplateName>();
// Translate the parser's template argument list in our AST format.
- llvm::SmallVector<TemplateArgumentLoc, 16> 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<NestedNameSpecifier*>(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<TemplateName>();
+// 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<TemplateArgumentLoc, 16> TemplateArgs;
- translateTemplateArguments(TemplateArgsIn, TemplateArgs);
- TemplateArgsIn.release();
+ if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) {
+ 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<TemplateTypeParmDecl>(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<NonTypeTemplateParmDecl>(Param)) {
+ if (!NonTypeParm->hasDefaultArgument())
+ return TemplateArgumentLoc();
+
+ OwningExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ NonTypeParm,
+ Converted);
+ if (Arg.isInvalid())
+ return TemplateArgumentLoc();
+
+ Expr *ArgE = Arg.takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE);
+ }
+
+ TemplateTemplateParmDecl *TempTempParm
+ = cast<TemplateTemplateParmDecl>(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<FunctionDecl>(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<VarDecl>(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<TemplateArgumentLoc, 16> 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<TemplateArgumentLoc, 16> 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<TemplateArgumentLoc, 16> 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<CurrentInstantiationRebuilder> {
SourceLocation Loc;
DeclarationName Entity;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 10594c728fbe..613ffde5734a 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 <algorithm>
namespace clang {
@@ -1050,35 +1049,34 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
unsigned N = Partial->getNumTemplateArgsAsWritten();
- llvm::SmallVector<TemplateArgumentLoc, 16> 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<NamedDecl *>(
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<TemplateArgument&>(ConvertedInstArgs.getFlatArguments()[I]);
+ TemplateArgument InstArg = ConvertedInstArgs.getFlatArguments()[I];
Decl *Param = const_cast<NamedDecl *>(
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<TemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &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<NamedDecl *>(TemplateParams->getParam(I)));
+ const_cast<NamedDecl *>(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<NamedDecl *>(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<FunctionDecl>(
@@ -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<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> 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<TemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> 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 58fe59e321cf..623cde87a9c8 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<TemplateInstantiator> {
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<UsingDecl>(InstD)) {
- UsingDecl *UD = cast<UsingDecl>(InstD);
-
- bool HasNonFunction = false;
-
- llvm::SmallVector<NamedDecl*, 8> 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<NamedDecl*>::iterator I = Decls.begin(),
- E = Decls.end(); I != E; ++I)
- if (isa<FunctionDecl>(*I))
- OFD->addOverload(cast<FunctionDecl>(*I));
- else
- OFD->addOverload(cast<FunctionTemplateDecl>(*I));
-
- InstD = OFD;
- } else {
- // FIXME
- assert(false && "using declaration resolved to mixed set");
- return SemaRef.ExprError();
- }
- }
+ assert(!isa<UsingDecl>(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 3f40ffcdc178..a1258572ccb4 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<TemplateDeclInstantiator, Decl *> {
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<Expr>());
}
else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
@@ -1153,11 +1153,12 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
= PartialSpec->getTemplateArgsAsWritten();
unsigned N = PartialSpec->getNumTemplateArgsAsWritten();
- llvm::SmallVector<TemplateArgumentLoc, 4> 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<int>.
NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(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<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 00dc809f51a8..afce5e33ba6b 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 ca680c279bdb..28b217403564 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<FunctionDecl>(*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<Derived>::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<Derived>::TransformTemplateName(TemplateName Name,
TransTemplate);
}
- OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl();
- assert(Ovl && "Not a template name or an overload set?");
- OverloadedFunctionDecl *TransOvl
- = cast_or_null<OverloadedFunctionDecl>(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<Derived>::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<OverloadedFunctionDecl>(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<typename Derived>
@@ -2879,21 +2801,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
if (Template.isNull())
return QualType();
- llvm::SmallVector<TemplateArgumentLoc, 4> 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<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::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<VarDecl>(
+ 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<Derived>::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<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::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<VarDecl>(
+ 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<typename Derived>
Sema::OwningStmtResult
TreeTransform<Derived>::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<VarDecl>(
+ 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<Derived>::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<typename Derived>
@@ -3207,9 +3171,20 @@ TreeTransform<Derived>::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<VarDecl>(
+ 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<Derived>::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<Derived>::TransformMemberExpr(MemberExpr *E,
!E->hasExplicitTemplateArgumentList())
return SemaRef.Owned(E->Retain());
- llvm::SmallVector<TemplateArgumentLoc, 4> 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<Derived>::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<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E,
- bool isAddressOfOperand) {
- VarDecl *Var
- = cast_or_null<VarDecl>(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<typename Derived>
-Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E,
bool isAddressOfOperand) {
// Transform the type that we're allocating
@@ -4558,11 +4516,66 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr(
- UnresolvedFunctionNameExpr *E,
+TreeTransform<Derived>::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<NamedDecl*>(getDerived().TransformDecl(*I));
+ if (!InstD)
+ return SemaRef.ExprError();
+
+ // Expand using declarations.
+ if (isa<UsingDecl>(InstD)) {
+ UsingDecl *UD = cast<UsingDecl>(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<typename Derived>
@@ -4592,8 +4605,8 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E,
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformUnresolvedDeclRefExpr(
- UnresolvedDeclRefExpr *E,
+TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *E,
bool isAddressOfOperand) {
NestedNameSpecifier *NNS
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
@@ -4606,56 +4619,30 @@ TreeTransform<Derived>::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<typename Derived>
-Sema::OwningExprResult
-TreeTransform<Derived>::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<TemplateArgumentLoc, 4> 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<typename Derived>
@@ -4828,8 +4815,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
template<typename Derived>
Sema::OwningExprResult
-TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
- CXXUnresolvedMemberExpr *E,
+TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
+ CXXDependentScopeMemberExpr *E,
bool isAddressOfOperand) {
// Transform the base of the expression.
OwningExprResult Base = getDerived().TransformExpr(E->getBase());
@@ -4878,52 +4865,99 @@ TreeTransform<Derived>::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<TemplateArgumentLoc, 4> 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<typename Derived>
+Sema::OwningExprResult
+TreeTransform<Derived>::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<NamedDecl*>(getDerived().TransformDecl(*I));
+ if (!InstD)
+ return SemaRef.ExprError();
+
+ // Expand using declarations.
+ if (isa<UsingDecl>(InstD)) {
+ UsingDecl *UD = cast<UsingDecl>(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<typename Derived>
@@ -5266,12 +5300,8 @@ template<typename Derived>
QualType TreeTransform<Derived>::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<typename Derived>
@@ -5280,7 +5310,7 @@ TreeTransform<Derived>::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<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
- bool TemplateKW,
- OverloadedFunctionDecl *Ovl) {
- return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl);
-}
-
-template<typename Derived>
-TemplateName
-TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
const IdentifierInfo &II,
QualType ObjectType) {
CXXScopeSpec SS;
@@ -5349,7 +5371,8 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
/*FIXME:*/getDerived().getBaseLocation(),
SS,
Name,
- ObjectType.getAsOpaquePtr())
+ ObjectType.getAsOpaquePtr(),
+ /*EnteringContext=*/false)
.template getAsVal<TemplateName>();
}
@@ -5369,7 +5392,8 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
/*FIXME:*/getDerived().getBaseLocation(),
SS,
Name,
- ObjectType.getAsOpaquePtr())
+ ObjectType.getAsOpaquePtr(),
+ /*EnteringContext=*/false)
.template getAsVal<TemplateName>();
}
@@ -5382,8 +5406,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
ExprArg Second) {
Expr *FirstExpr = (Expr *)First.get();
Expr *SecondExpr = (Expr *)Second.get();
- DeclRefExpr *DRE
- = cast<DeclRefExpr>(((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<Derived>::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<Derived>::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<UnresolvedLookupExpr>(CalleeExpr)) {
+ assert(ULE->requiresADL());
+
+ // FIXME: Do we have to check
+ // IsAcceptableNonMemberOperatorCandidate for each of these?
+ for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(),
+ E = ULE->decls_end(); I != E; ++I)
+ Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I));
+ } else {
+ Functions.insert(AnyFunctionDecl::getFromNamedDecl(
+ cast<DeclRefExpr>(CalleeExpr)->getDecl()));
+ }
// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { FirstExpr, SecondExpr };
@@ -5447,8 +5478,10 @@ TreeTransform<Derived>::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 3942391ee982..21460a1a324d 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 fc9e27bfe755..bee337a44572 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 4e201bf7eb4c..69a4260537bd 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 ee1da1fff972..d9367d4af61c 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 31802d038019..96080bec3243 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 811ac813c7e2..e29eefd8eb8b 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 d6bc84575ef4..7ea6111bd48c 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 506dc8b0e530..f520784e11d3 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
// <rdar://problem/6440393> - A bunch of misc. failures involving evaluating
// these expressions and building CFGs. These tests are here to prevent
diff --git a/test/Analysis/misc-ps-basic-store.m b/test/Analysis/misc-ps-basic-store.m
index 2b9913461718..2a982347a7b6 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 66eb1256f42a..e702cb968a57 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 49cc5933ccad..058c903722c0 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
// <rdar://problem/6776949>
// main's 'argc' argument is always > 0
diff --git a/test/Analysis/misc-ps-region-store-i386.m b/test/Analysis/misc-ps-region-store-i386.m
index a833a653a425..7b0d61bcbaeb 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 7e614fd24833..8c865ab27ff2 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 7ebc4a9fe5e5..e5113ba351c8 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;
}
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7403269> - 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.
+// (<rdar://problem/7191542>)
+//===----------------------------------------------------------------------===//
+
+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 (<rdar://problem/6811085>)
+//===----------------------------------------------------------------------===//
+
+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 d2eef0d7fdbd..42168b9e3e4b 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 536c4a1b6731..75cdf6ed3932 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 f5c6a10ab3b9..c604653ea516 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 8bd616ade0e8..971d47654fdd 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: <?xml version="1.0" encoding="UTF-8"?>
// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
// CHECK: <plist version="1.0">
@@ -102,6 +135,702 @@ void test_null_init(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>9</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>10</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>11</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>15</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>17</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>4</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>18</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>22</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>23</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Assuming pointer value is null</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>7</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>28</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>29</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>6</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>message</key>
+// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>category</key><string>Logic error</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>30</integer>
+// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>path</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>control</string>
+// CHECK: <key>edges</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>start</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>35</integer>
+// CHECK: <key>col</key><integer>10</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: <key>end</key>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>kind</key><string>event</string>
+// CHECK: <key>location</key>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <key>ranges</key>
+// CHECK: <array>
+// CHECK: <array>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>line</key><integer>37</integer>
+// CHECK: <key>col</key><integer>8</integer>
+// CHECK: <key>file</key><integer>0</integer>
+// CHECK: </dict>
+// CHECK: </array>
+// CHECK: </array>
+// CHECK: <key>extended_message</key>
// CHECK: <string>Dereference of null pointer</string>
// CHECK: <key>message</key>
// CHECK: <string>Dereference of null pointer</string>
@@ -109,10 +838,10 @@ void test_null_init(void) {
// CHECK: </array>
// CHECK: <key>description</key><string>Dereference of null pointer</string>
// CHECK: <key>category</key><string>Logic error</string>
-// CHECK: <key>type</key><string>Null pointer dereference</string>
+// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
// CHECK: <dict>
-// CHECK: <key>line</key><integer>5</integer>
+// CHECK: <key>line</key><integer>37</integer>
// CHECK: <key>col</key><integer>3</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 7b0a1a685bdf..1d8bbd39d8d1 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 7230f21c08c3..9d6fe5b27d34 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 8908adb1057c..000000000000
--- 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 3eeebc4a8f0a..ab52938505f6 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}}
}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7407273> 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 dfea2e7738d0..bc9f0b7ef444 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) {
}
//===----------------------------------------------------------------------===//
+// <rdar://problem/7252064> 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 f26e2f0c6352..5d1ce253fc35 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 c2b73668dd95..46e441f608d7 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 d9e73188003f..7be32b4d157e 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 754799b2dbd8..bbbf6aec23dd 100644
--- a/test/Analysis/unused-ivars.m
+++ b/test/Analysis/unused-ivars.m
@@ -65,3 +65,19 @@
}
@end
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7254495> - 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 cd822f623a79..f39eb2accb45 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 000000000000..ecff3eebafec
--- /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 cebc3e99d09f..418059dc74ce 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 4b1582840c39..0cb8186cdb6f 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 b63c56c40fe8..90bb16256c5b 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<typename T, int N>
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 725b61c27162..6c827209ef0e 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<typename T, typename U> // expected-note{{previous template}}
class X0 {
public:
@@ -66,3 +65,36 @@ X0<T, U>::operator T*() const {
namespace N { template <class X> class A {void a();}; }
namespace N { template <class X> void A<X>::a() {} }
+
+// PR5566
+template<typename T>
+struct X1 {
+ template<typename U>
+ struct B { void f(); };
+};
+
+template<typename T>
+template<typename U>
+void X1<T>::template B<U>::f() { }
+
+// PR5527
+template <template <class> class T>
+class X2 {
+ template <class F>
+ class Bar {
+ void Func();
+ };
+};
+
+template <template <class> class T>
+template <class F>
+void X2<T>::Bar<F>::Func() {}
+
+// PR5528
+template <template <class> class T>
+class X3 {
+ void F();
+};
+
+template <template <class> class T>
+void X3<T>::F() {}
diff --git a/test/CXX/temp/temp.param/p2.cpp b/test/CXX/temp/temp.param/p2.cpp
index a402cf6f888d..d40f99b58a29 100644
--- a/test/CXX/temp/temp.param/p2.cpp
+++ b/test/CXX/temp/temp.param/p2.cpp
@@ -8,7 +8,8 @@ template<typename T> struct X;
// typename followed by aqualified-id denotes the type in a non-type
// parameter-declaration.
-// FIXME: template<typename T, typename T::type Value> struct Y;
+template<typename T, typename T::type Value> struct Y0;
+template<typename T, typename X<T>::type Value> struct Y1;
// A storage class shall not be specified in a template-parameter declaration.
template<static int Value> struct Z; // FIXME: expect an error
diff --git a/test/CXX/temp/temp.param/p9.cpp b/test/CXX/temp/temp.param/p9.cpp
new file mode 100644
index 000000000000..d6b740544d02
--- /dev/null
+++ b/test/CXX/temp/temp.param/p9.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
+
+// A default template-argument shall not be specified in a function
+// template declaration or a function template definition
+template<typename T = int> // expected-error{{cannot have a default argument}}
+ void foo0(T);
+template<typename T = int> // expected-error{{cannot have a default argument}}
+ void foo1(T) { }
+
+// [...] nor in the template-parameter-list of the definition of a
+// member of a class template.
+template<int N>
+struct X0 {
+ void f();
+};
+
+template<int N = 0> // expected-error{{cannot add a default template argument}}
+void X0<N>::f() { }
+
+class X1 {
+ template<template<int> class TT = X0> // expected-error{{not permitted on a friend template}}
+ friend void f2();
+};
diff --git a/test/CodeCompletion/property.m b/test/CodeCompletion/property.m
deleted file mode 100644
index 184519b408fa..000000000000
--- a/test/CodeCompletion/property.m
+++ /dev/null
@@ -1,29 +0,0 @@
-// Note: the run lines follow their respective tests, since line/column
-// matter in this test.
-
-@interface Foo {
- void *isa;
-}
-@property(copy) Foo *myprop;
-@property(retain, nonatomic) id xx;
-// RUN: clang-cc -fsyntax-only -code-completion-at=%s:7:11 %s -o - | FileCheck -check-prefix=CC1 %s
-// CC1: assign
-// CC1-NEXT: copy
-// CC1-NEXT: getter
-// CC1-NEXT: nonatomic
-// CC1-NEXT: readonly
-// CC1-NEXT: readwrite
-// CC1-NEXT: retain
-// CC1-NEXT: setter
-// RUN: clang-cc -fsyntax-only -code-completion-at=%s:8:18 %s -o - | FileCheck -check-prefix=CC2 %s
-// CC2: assign
-// CC2-NEXT: copy
-// CC2-NEXT: getter
-// CC2-NEXT: nonatomic
-// CC2-NEXT: readonly
-// CC2-NEXT: readwrite
-// CC2-NEXT: setter
-@end
-
-
-
diff --git a/test/CodeGen/2008-07-17-no-emit-on-error.c b/test/CodeGen/2008-07-17-no-emit-on-error.c
index fbff54149bcc..6266b504fd04 100644
--- a/test/CodeGen/2008-07-17-no-emit-on-error.c
+++ b/test/CodeGen/2008-07-17-no-emit-on-error.c
@@ -1,10 +1,14 @@
// RUN: rm -f %t1.bc
+// RUN: clang-cc -DPASS %s -emit-llvm-bc -o %t1.bc
+// RUN: test -f %t1.bc
// RUN: not clang-cc %s -emit-llvm-bc -o %t1.bc
// RUN: not test -f %t1.bc
void f() {
}
+#ifndef PASS
void g() {
*10;
}
+#endif
diff --git a/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
index db3c4b25d375..4aa28f8eb484 100644
--- a/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
+++ b/test/CodeGen/2008-07-22-bitfield-init-after-zero-len-array.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple=i686-apple-darwin9 --emit-llvm -o - %s | FileCheck %s
+// RUN: clang-cc -triple=i686-apple-darwin9 -emit-llvm -o - %s | FileCheck %s
struct et7 {
float lv7[0];
diff --git a/test/CodeGen/2008-07-30-implicit-initialization.c b/test/CodeGen/2008-07-30-implicit-initialization.c
index 9cd530045bca..b225a14e6f0a 100644
--- a/test/CodeGen/2008-07-30-implicit-initialization.c
+++ b/test/CodeGen/2008-07-30-implicit-initialization.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32" %t | count 2
// RUN: grep "ret i32 0" %t | count 2
// <rdar://problem/6113085>
diff --git a/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c b/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c
index c374f8d00843..9fce0aedce41 100644
--- a/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c
+++ b/test/CodeGen/2008-07-30-redef-of-bitcasted-decl.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o - %s
+// RUN: clang-cc -emit-llvm -o - %s
// <rdar://problem/6108358>
/* For posterity, the issue here begins initial "char []" decl for
diff --git a/test/CodeGen/2008-08-04-void-pointer-arithmetic.c b/test/CodeGen/2008-08-04-void-pointer-arithmetic.c
index 22815f32ccc4..bd4d8f8c18e7 100644
--- a/test/CodeGen/2008-08-04-void-pointer-arithmetic.c
+++ b/test/CodeGen/2008-08-04-void-pointer-arithmetic.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o - %s
+// RUN: clang-cc -emit-llvm -o - %s
// <rdar://problem/6122967>
int f0(void *a, void *b) {
diff --git a/test/CodeGen/2008-08-19-cast-of-typedef.c b/test/CodeGen/2008-08-19-cast-of-typedef.c
index 3db5e903090a..3435384a5829 100644
--- a/test/CodeGen/2008-08-19-cast-of-typedef.c
+++ b/test/CodeGen/2008-08-19-cast-of-typedef.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
typedef short T[4];
struct s {
diff --git a/test/CodeGen/PR2001-bitfield-reload.c b/test/CodeGen/PR2001-bitfield-reload.c
index 1fef3c56b53d..4dec65fd5472 100644
--- a/test/CodeGen/PR2001-bitfield-reload.c
+++ b/test/CodeGen/PR2001-bitfield-reload.c
@@ -1,6 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t
-// RUN: grep "ret i32" %t | count 1
-// RUN: grep "ret i32 1" %t | count 1
+// RUN: clang-cc -triple i386-unknown-unknown -O3 -emit-llvm -o - %s | FileCheck %s
// PR2001
/* Test that the result of the assignment properly uses the value *in
@@ -13,5 +11,6 @@ static int foo(int i) {
}
int bar() {
+ // CHECK: ret i32 1
return foo(-5) == -1;
}
diff --git a/test/CodeGen/arm-arguments.c b/test/CodeGen/arm-arguments.c
index 3b2c433a89ff..945c1f2e668d 100644
--- a/test/CodeGen/arm-arguments.c
+++ b/test/CodeGen/arm-arguments.c
@@ -1,5 +1,5 @@
-// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi=apcs-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=APCS-GNU %s
-// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi=aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=AAPCS %s
+// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi apcs-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=APCS-GNU %s
+// RUN: clang-cc -triple armv7-apple-darwin9 -target-abi aapcs -emit-llvm -w -o - %s | FileCheck -check-prefix=AAPCS %s
// APCS-GNU: define arm_apcscc signext i8 @f0()
// AAPCS: define arm_aapcscc signext i8 @f0()
diff --git a/test/CodeGen/builtins-ffs_parity_popcount.c b/test/CodeGen/builtins-ffs_parity_popcount.c
deleted file mode 100644
index 74e104b437c6..000000000000
--- a/test/CodeGen/builtins-ffs_parity_popcount.c
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: clang-cc -emit-llvm -o - %s > %t
-// RUN: not grep "__builtin" %t
-
-#include <stdio.h>
-
-void test(int M, long long N) {
- printf("%d %lld: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
- M, N,
- __builtin_ffs(M), __builtin_ffsl(M), __builtin_ffsll(M),
- __builtin_parity(M), __builtin_parityl(M), __builtin_parityll(M),
- __builtin_popcount(M), __builtin_popcountl(M), __builtin_popcountll(M),
- __builtin_ffs(N), __builtin_ffsl(N), __builtin_ffsll(N),
- __builtin_parity(N), __builtin_parityl(N), __builtin_parityll(N),
- __builtin_popcount(N), __builtin_popcountl(N), __builtin_popcountll(N));
-}
diff --git a/test/CodeGen/builtins-powi.c b/test/CodeGen/builtins-powi.c
deleted file mode 100644
index 945ec5dd13ea..000000000000
--- a/test/CodeGen/builtins-powi.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// RUN: clang-cc -emit-llvm -o - %s > %t
-// RUN: not grep "__builtin" %t
-
-#include <stdio.h>
-#include <stdlib.h>
-
-void test(long double a, int b) {
- printf("%Lf**%d: %08x %08x %016Lx\n",
- a, b,
- __builtin_powi(a, b),
- __builtin_powif(a, b),
- __builtin_powil(a, b)
- );
-}
-
-int main() {
- int i;
-
- test(-1,-1LL);
- test(0,0);
- test(1,1);
-
- for (i=0; i<3; i++) {
- test(random(), i);
- }
-
- return 0;
-}
diff --git a/test/CodeGen/const-init.c b/test/CodeGen/const-init.c
index 06cdde9c9575..5f196ca5a43d 100644
--- a/test/CodeGen/const-init.c
+++ b/test/CodeGen/const-init.c
@@ -1,6 +1,6 @@
-// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o - %s | FileCheck %s
+// RUN: clang-cc -triple i386-pc-linux-gnu -ffreestanding -verify -emit-llvm -o - %s | FileCheck %s
-typedef __INTPTR_TYPE__ intptr_t;
+#include <stdint.h>
// Brace-enclosed string array initializers
char a[] = { "asdf" };
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index 856b91964ebc..d7a54d643937 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -o %t --emit-llvm -g %s
+// RUN: clang-cc -o %t -emit-llvm -g %s
// RUN: FileCheck --input-file=%t %s
// PR3023
diff --git a/test/CodeGen/flexible-array-init.c b/test/CodeGen/flexible-array-init.c
index 2f0df9057a9a..bf8f057c2a06 100644
--- a/test/CodeGen/flexible-array-init.c
+++ b/test/CodeGen/flexible-array-init.c
@@ -1,8 +1,7 @@
-// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 7 | count 1
-// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 11 | count 1
-// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 13 | count 1
-// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | grep 15 | count 1
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
struct { int x; int y[]; } a = { 1, 7, 11 };
+// CHECK: @a = global %0 { i32 1, [2 x i32] [i32 7, i32 11] }
struct { int x; int y[]; } b = { 1, { 13, 15 } };
+// CHECK: @b = global %0 { i32 1, [2 x i32] [i32 13, i32 15] }
diff --git a/test/CodeGen/func-return-member.c b/test/CodeGen/func-return-member.c
index e6fc5623904b..68a48fc1041f 100644
--- a/test/CodeGen/func-return-member.c
+++ b/test/CodeGen/func-return-member.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-llvm < %s 2>&1 | not grep 'cannot codegen this l-value expression yet'
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
struct frk { float _Complex c; int x; };
struct faz { struct frk f; };
@@ -10,14 +10,17 @@ int X;
struct frk F;
float _Complex C;
+// CHECK: define void @bar
void bar(void) {
X = foo().f.f.x;
}
+// CHECK: define void @bun
void bun(void) {
F = foo().f.f;
}
+// CHECK: define void @ban
void ban(void) {
C = foo().f.f.c;
}
diff --git a/test/CodeGen/incomplete-function-type.c b/test/CodeGen/incomplete-function-type.c
index a641268cf50f..c760e04a08f5 100644
--- a/test/CodeGen/incomplete-function-type.c
+++ b/test/CodeGen/incomplete-function-type.c
@@ -1,4 +1,7 @@
-// RUN: clang-cc -emit-llvm %s -o - | not grep opaque
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+// CHECK: ModuleID
+// CHECK-NOT: opaque
+// CHECK: define void @f0
enum teste1 test1f(void), (*test1)(void) = test1f;
struct tests2 test2f(), (*test2)() = test2f;
@@ -8,3 +11,4 @@ enum teste1 { TEST1 };
struct tests2 { int x,y,z,a,b,c,d,e,f,g; };
struct tests3 { float x; };
+void f0() {}
diff --git a/test/CodeGen/rdr-6098585-default-after-caserange.c b/test/CodeGen/rdr-6098585-default-after-caserange.c
index 239383a4bdca..2c58548744d6 100644
--- a/test/CodeGen/rdr-6098585-default-after-caserange.c
+++ b/test/CodeGen/rdr-6098585-default-after-caserange.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32" %t | count 1
// RUN: grep "ret i32 10" %t | count 1
diff --git a/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c b/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c
index 39a6bc662dcb..257a9d7f8acd 100644
--- a/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c
+++ b/test/CodeGen/rdr-6098585-default-fallthrough-to-caserange.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32 10" %t
// Ensure that this doesn't compile to infinite loop in g() due to
diff --git a/test/CodeGen/rdr-6098585-empty-case-range.c b/test/CodeGen/rdr-6098585-empty-case-range.c
index f80b599ed5a0..2dd1eaac9df8 100644
--- a/test/CodeGen/rdr-6098585-empty-case-range.c
+++ b/test/CodeGen/rdr-6098585-empty-case-range.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32" %t | count 2
// RUN: grep "ret i32 3" %t | count 2
diff --git a/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c b/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c
index 6c51a3706716..c12cf82ba0cc 100644
--- a/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c
+++ b/test/CodeGen/rdr-6098585-fallthrough-to-empty-range.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32 %" %t
// Make sure return is not constant (if empty range is skipped or miscompiled)
diff --git a/test/CodeGen/rdr-6098585-unsigned-caserange.c b/test/CodeGen/rdr-6098585-unsigned-caserange.c
index 3b4384bdd70f..a2b85d989530 100644
--- a/test/CodeGen/rdr-6098585-unsigned-caserange.c
+++ b/test/CodeGen/rdr-6098585-unsigned-caserange.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown --emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
+// RUN: clang-cc -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t
// RUN: grep "ret i32" %t | count 1
// RUN: grep "ret i32 3" %t | count 1
diff --git a/test/CodeGen/stack-protector.c b/test/CodeGen/stack-protector.c
index c29d1f7f33d9..57635976d05f 100644
--- a/test/CodeGen/stack-protector.c
+++ b/test/CodeGen/stack-protector.c
@@ -1,8 +1,8 @@
-// RUN: clang-cc -emit-llvm -o - %s -stack-protector=0 | FileCheck -check-prefix=NOSSP %s
+// RUN: clang-cc -emit-llvm -o - %s -stack-protector 0 | FileCheck -check-prefix=NOSSP %s
// NOSSP: define void @test1(i8* %msg) nounwind {
-// RUN: clang-cc -emit-llvm -o - %s -stack-protector=1 | FileCheck -check-prefix=WITHSSP %s
+// RUN: clang-cc -emit-llvm -o - %s -stack-protector 1 | FileCheck -check-prefix=WITHSSP %s
// WITHSSP: define void @test1(i8* %msg) nounwind ssp {
-// RUN: clang-cc -emit-llvm -o - %s -stack-protector=2 | FileCheck -check-prefix=SSPREQ %s
+// RUN: clang-cc -emit-llvm -o - %s -stack-protector 2 | FileCheck -check-prefix=SSPREQ %s
// SSPREQ: define void @test1(i8* %msg) nounwind sspreq {
int printf(const char * _Format, ...);
diff --git a/test/CodeGen/static-order.c b/test/CodeGen/static-order.c
index 243e96bf3e65..58340b691302 100644
--- a/test/CodeGen/static-order.c
+++ b/test/CodeGen/static-order.c
@@ -1,4 +1,7 @@
-// RUN: clang-cc -emit-llvm -o - %s | not grep "zeroinitializer"
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+// CHECK: ModuleID
+// CHECK-NOT: zeroinitializer
+// CHECK: define i8* @f
struct s {
int a;
diff --git a/test/CodeGen/switch.c b/test/CodeGen/switch.c
index 3254fbf3c938..96118f6e6fc3 100644
--- a/test/CodeGen/switch.c
+++ b/test/CodeGen/switch.c
@@ -1,11 +1,11 @@
-// RUN: clang-cc %s -emit-llvm-bc -o - | opt -std-compile-opts -disable-output
+// RUN: clang-cc -triple i386-unknown-unknown -O3 %s -emit-llvm -o - | FileCheck %s
int foo(int i) {
int j = 0;
switch (i) {
case -1:
j = 1; break;
- case 1 :
+ case 1 :
j = 2; break;
case 2:
j = 3; break;
@@ -16,11 +16,10 @@ int foo(int i) {
return j;
}
-
int foo2(int i) {
int j = 0;
switch (i) {
- case 1 :
+ case 1 :
j = 2; break;
case 2 ... 10:
j = 3; break;
@@ -31,7 +30,6 @@ int foo2(int i) {
return j;
}
-
int foo3(int i) {
int j = 0;
switch (i) {
@@ -48,7 +46,7 @@ int foo3(int i) {
}
-int foo4(int i) {
+static int foo4(int i) {
int j = 0;
switch (i) {
case 111:
@@ -65,6 +63,17 @@ int foo4(int i) {
return j;
}
+// CHECK: define i32 @foo4t()
+// CHECK: ret i32 376
+// CHECK: }
+int foo4t() {
+ // 111 + 1 + 222 + 42 = 376
+ return foo4(111) + foo4(99) + foo4(222) + foo4(601);
+}
+
+// CHECK: define void @foo5()
+// CHECK-NOT: switch
+// CHECK: }
void foo5(){
switch(0){
default:
@@ -74,11 +83,17 @@ void foo5(){
}
}
+// CHECK: define void @foo6()
+// CHECK-NOT: switch
+// CHECK: }
void foo6(){
switch(0){
}
}
+// CHECK: define void @foo7()
+// CHECK-NOT: switch
+// CHECK: }
void foo7(){
switch(0){
foo7();
diff --git a/test/CodeGen/vector.c b/test/CodeGen/vector.c
index 2945ebaa4d05..21a03d0593d6 100644
--- a/test/CodeGen/vector.c
+++ b/test/CodeGen/vector.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-apple-darwin9 -mcpu=pentium4 -g -emit-llvm %s -o -
+// RUN: clang-cc -triple i386-apple-darwin9 -mcpu pentium4 -g -emit-llvm %s -o -
typedef short __v4hi __attribute__ ((__vector_size__ (8)));
void test1() {
diff --git a/test/CodeGen/visibility.c b/test/CodeGen/visibility.c
index 7c837ba823e9..c19004a5a2cb 100644
--- a/test/CodeGen/visibility.c
+++ b/test/CodeGen/visibility.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=default -emit-llvm -o %t %s
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility default -emit-llvm -o %t %s
// RUN: grep '@g_com = common global i32 0' %t
// RUN: grep '@g_def = global i32 0' %t
// RUN: grep '@g_ext = external global i32' %t
@@ -6,7 +6,7 @@
// RUN: grep 'declare void @f_ext()' %t
// RUN: grep 'define internal void @f_deferred()' %t
// RUN: grep 'define i32 @f_def()' %t
-// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=protected -emit-llvm -o %t %s
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility protected -emit-llvm -o %t %s
// RUN: grep '@g_com = common protected global i32 0' %t
// RUN: grep '@g_def = protected global i32 0' %t
// RUN: grep '@g_ext = external global i32' %t
@@ -14,7 +14,7 @@
// RUN: grep 'declare void @f_ext()' %t
// RUN: grep 'define internal void @f_deferred()' %t
// RUN: grep 'define protected i32 @f_def()' %t
-// RUN: clang-cc -triple i386-unknown-unknown -fvisibility=hidden -emit-llvm -o %t %s
+// RUN: clang-cc -triple i386-unknown-unknown -fvisibility hidden -emit-llvm -o %t %s
// RUN: grep '@g_com = common hidden global i32 0' %t
// RUN: grep '@g_def = hidden global i32 0' %t
// RUN: grep '@g_ext = external global i32' %t
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
new file mode 100644
index 000000000000..a6b74efff389
--- /dev/null
+++ b/test/CodeGenCXX/condition.cpp
@@ -0,0 +1,110 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+void *f();
+
+template <typename T> T* g() {
+ if (T* t = f())
+ return t;
+
+ return 0;
+}
+
+void h() {
+ void *a = g<void>();
+}
+
+struct X {
+ X();
+ ~X();
+ operator bool();
+};
+
+struct Y {
+ Y();
+ ~Y();
+};
+
+void if_destruct(int z) {
+ // Verify that the condition variable is destroyed at the end of the
+ // "if" statement.
+ // CHECK: call void @_ZN1XC1Ev
+ // CHECK: call zeroext i1 @_ZN1XcvbEv
+ if (X x = X()) {
+ // CHECK: store i32 18
+ z = 18;
+ }
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: store i32 17
+ z = 17;
+
+ // CHECK: call void @_ZN1XC1Ev
+ if (X x = X())
+ Y y;
+ // CHECK: if.then
+ // CHECK: call void @_ZN1YC1Ev
+ // CHECK: call void @_ZN1YD1Ev
+ // CHECK: if.end
+ // CHECK: call void @_ZN1XD1Ev
+}
+
+struct ConvertibleToInt {
+ ConvertibleToInt();
+ ~ConvertibleToInt();
+ operator int();
+};
+
+void switch_destruct(int z) {
+ // CHECK: call void @_ZN16ConvertibleToIntC1Ev
+ switch (ConvertibleToInt conv = ConvertibleToInt()) {
+ case 0:
+ break;
+
+ default:
+ // CHECK: sw.default:
+ // CHECK: store i32 19
+ z = 19;
+ break;
+ }
+ // CHECK: sw.epilog:
+ // CHECK: call void @_ZN16ConvertibleToIntD1Ev
+ // CHECK: store i32 20
+ z = 20;
+}
+
+int foo();
+
+void while_destruct(int z) {
+ // CHECK: define void @_Z14while_destructi
+ // CHECK: while.cond:
+ while (X x = X()) {
+ // CHECK: call void @_ZN1XC1Ev
+
+ // CHECK: while.body:
+ // CHECK: store i32 21
+ z = 21;
+
+ // CHECK: while.cleanup:
+ // CHECK: call void @_ZN1XD1Ev
+ }
+ // CHECK: while.end
+ // CHECK: store i32 22
+ z = 22;
+}
+
+void for_destruct(int z) {
+ // CHECK: define void @_Z12for_destruct
+ // CHECK: call void @_ZN1YC1Ev
+ for(Y y = Y(); X x = X(); ++z)
+ // CHECK: for.cond:
+ // CHECK: call void @_ZN1XC1Ev
+ // CHECK: for.body:
+ // CHECK: store i32 23
+ z = 23;
+ // CHECK: for.inc:
+ // CHECK: br label %for.cond.cleanup
+ // CHECK: for.cond.cleanup:
+ // CHECK: call void @_ZN1XD1Ev
+ // CHECK: for.end:
+ // CHECK: call void @_ZN1YD1Ev
+ // CHECK: store i32 24
+ z = 24;
+}
diff --git a/test/CodeGenCXX/conditional-temporaries.cpp b/test/CodeGenCXX/conditional-temporaries.cpp
new file mode 100644
index 000000000000..f6c466a93135
--- /dev/null
+++ b/test/CodeGenCXX/conditional-temporaries.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct I {
+ int i;
+ I();
+ ~I();
+};
+
+void g(int);
+
+volatile int i;
+
+void f1() {
+ // CHECK: call void @_ZN1IC1Ev
+ g(i ? I().i : 0);
+ // CHECK: call void @_Z1gi
+ // CHECK: call void @_ZN1ID1Ev
+
+ // CHECK: call void @_ZN1IC1Ev
+ g(i || I().i);
+ // CHECK: call void @_Z1gi
+ // CHECK: call void @_ZN1ID1Ev
+
+ // CHECK: call void @_ZN1IC1Ev
+ g(i && I().i);
+ // CHECK: call void @_Z1gi
+ // CHECK: call void @_ZN1ID1Ev
+}
diff --git a/test/CodeGenCXX/const-global-linkage.cpp b/test/CodeGenCXX/const-global-linkage.cpp
new file mode 100644
index 000000000000..f12c569d9428
--- /dev/null
+++ b/test/CodeGenCXX/const-global-linkage.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+
+const int x = 10;
+const int y = 20;
+// CHECK-NOT: @x
+// CHECK: @y = internal constant i32 20
+const int& b() { return y; }
+
+const char z1[] = "asdf";
+const char z2[] = "zxcv";
+// CHECK-NOT: @z1
+// CHECK: @z2 = internal constant
+const char* b2() { return z2; }
diff --git a/test/CodeGenCXX/const-init.cpp b/test/CodeGenCXX/const-init.cpp
index 427ba5372992..42da6346daf3 100644
--- a/test/CodeGenCXX/const-init.cpp
+++ b/test/CodeGenCXX/const-init.cpp
@@ -1,11 +1,26 @@
-// RUN: clang-cc -verify -emit-llvm -o %t %s
+// RUN: clang-cc -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// CHECK: @a = global i32 10
int a = 10;
+// CHECK: @ar = global i32* @a
int &ar = a;
void f();
+// CHECK: @fr = global void ()* @_Z1fv
void (&fr)() = f;
struct S { int& a; };
+// CHECK: @s = global %0 { i32* @a }
S s = { a };
+// PR5581
+namespace PR5581 {
+class C {
+public:
+ enum { e0, e1 };
+ unsigned f;
+};
+
+// CHECK: @_ZN6PR55812g0E = global %1 { i32 1 }
+C g0 = { C::e1 };
+}
diff --git a/test/CodeGenCXX/copy-assign-synthesis-2.cpp b/test/CodeGenCXX/copy-assign-synthesis-2.cpp
new file mode 100644
index 000000000000..60d52f57de98
--- /dev/null
+++ b/test/CodeGenCXX/copy-assign-synthesis-2.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+struct A {};
+A& (A::*x)(const A&) = &A::operator=;
+// CHECK: define linkonce_odr %struct.A* @_ZN1AaSERKS_
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
index 3b8f7821abcf..2e950eb9e9b2 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -102,6 +102,17 @@ int main() {
m1.pr();
}
+struct A {
+};
+
+struct B : A {
+ A &a;
+};
+
+void f(const B &b1) {
+ B b2(b1);
+}
+
// CHECK-LP64: .globl __ZN1XC1ERKS_
// CHECK-LP64: .weak_definition __ZN1XC1ERKS_
// CHECK-LP64: __ZN1XC1ERKS_:
diff --git a/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp
index 5028ce99c7b7..71d4baa47566 100644
--- a/test/CodeGenCXX/default-arguments.cpp
+++ b/test/CodeGenCXX/default-arguments.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin10
+// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// PR5484
namespace PR5484 {
@@ -11,3 +11,59 @@ void g() {
f();
}
}
+
+struct A1 {
+ A1();
+ ~A1();
+};
+
+struct A2 {
+ A2();
+ ~A2();
+};
+
+struct B {
+ B(const A1& = A1(), const A2& = A2());
+};
+
+// CHECK: define void @_Z2f1v()
+void f1() {
+
+ // CHECK: call void @_ZN2A1C1Ev(
+ // CHECK: call void @_ZN2A2C1Ev(
+ // CHECK: call void @_ZN1BC1ERK2A1RK2A2(
+ // CHECK: call void @_ZN2A2D1Ev
+ // CHECK: call void @_ZN2A1D1Ev
+ B bs[2];
+}
+
+struct C {
+ B bs[2];
+ C();
+};
+
+// CHECK: define void @_ZN1CC1Ev(
+// CHECK: call void @_ZN2A1C1Ev(
+// CHECK: call void @_ZN2A2C1Ev(
+// CHECK: call void @_ZN1BC1ERK2A1RK2A2(
+// CHECK: call void @_ZN2A2D1Ev
+// CHECK: call void @_ZN2A1D1Ev
+
+// CHECK: define void @_ZN1CC2Ev(
+// CHECK: call void @_ZN2A1C1Ev(
+// CHECK: call void @_ZN2A2C1Ev(
+// CHECK: call void @_ZN1BC1ERK2A1RK2A2(
+// CHECK: call void @_ZN2A2D1Ev
+// CHECK: call void @_ZN2A1D1Ev
+C::C() { }
+
+// CHECK: define void @_Z2f3v()
+void f3() {
+ // CHECK: call void @_ZN2A1C1Ev(
+ // CHECK: call void @_ZN2A2C1Ev(
+ // CHECK: call void @_ZN1BC1ERK2A1RK2A2(
+ // CHECK: call void @_ZN2A2D1Ev
+ // CHECK: call void @_ZN2A1D1Ev
+ B *bs = new B[2];
+ delete bs;
+}
diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp
index 4719f80a5b41..0f78fb0deb60 100644
--- a/test/CodeGenCXX/dyncast.cpp
+++ b/test/CodeGenCXX/dyncast.cpp
@@ -97,7 +97,7 @@ void test1() {
// CHECK-LL-NEXT: br i1 %4, label %5, label %9
// CHECK-LL: ; <label>:5
// CHECK-LL-NEXT: %6 = bitcast %class.test1_A* %tmp to i8*
-// CHECK-LL-NEXT: %7 = call i8* @__dynamic_cast(i8* %6, i8* bitcast (i8** @_ZTI7test1_B to i8*), i8* bitcast (i8** @_ZTI7test1_D to i8*), i64 -1)
+// CHECK-LL-NEXT: %7 = call i8* @__dynamic_cast(i8* %6, i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i8* bitcast (i8** @_ZTI7test1_D to i8*), i64 -1)
// CHECK-LL-NEXT: %8 = bitcast i8* %7 to %class.test1_D*
// CHECK-LL-NEXT: br label %10
// CHECK-LL: ; <label>:9
@@ -120,7 +120,7 @@ void test1() {
// CHECK-LL-NEXT: br i1 %12, label %13, label %17
// CHECK-LL: ; <label>:13
// CHECK-LL-NEXT: %14 = bitcast %class.test1_A* %tmp6 to i8*
-// CHECK-LL-NEXT: %15 = call i8* @__dynamic_cast(i8* %14, i8* bitcast (i8** @_ZTI7test1_B to i8*), i8* bitcast (i8** @_ZTI7test1_A to i8*), i64 -1)
+// CHECK-LL-NEXT: %15 = call i8* @__dynamic_cast(i8* %14, i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i64 -1)
// CHECK-LL-NEXT: %16 = bitcast i8* %15 to %class.test1_A*
// CHECK-LL-NEXT: br label %18
// CHECK-LL: ; <label>:17
@@ -143,7 +143,7 @@ void test1() {
// CHECK-LL-NEXT: br i1 %20, label %21, label %25
// CHECK-LL: ; <label>:21
// CHECK-LL-NEXT: %22 = bitcast %class.test1_A* %tmp14 to i8*
-// CHECK-LL-NEXT: %23 = call i8* @__dynamic_cast(i8* %22, i8* bitcast (i8** @_ZTI7test1_A to i8*), i8* bitcast (i8** @_ZTI7test1_B to i8*), i64 -1)
+// CHECK-LL-NEXT: %23 = call i8* @__dynamic_cast({{.*}} %22, i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i64 -1)
// CHECK-LL-NEXT: %24 = bitcast i8* %23 to %class.test1_A*
// CHECK-LL-NEXT: br label %26
// CHECK-LL: ; <label>:25
@@ -214,7 +214,7 @@ void test1() {
// CHECK-LL-NEXT: br i1 %34, label %35, label %39
// CHECK-LL: ; <label>:35
// CHECK-LL-NEXT: %36 = bitcast %class.test1_A* %tmp54 to i8*
-// CHECK-LL-NEXT: %37 = call i8* @__dynamic_cast(i8* %36, i8* bitcast (i8** @_ZTI7test1_A to i8*), i8* bitcast (i8** @_ZTI7test1_D to i8*), i64 -1)
+// CHECK-LL-NEXT: %37 = call i8* @__dynamic_cast(i8* %36, i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
// CHECK-LL-NEXT: %38 = bitcast i8* %37 to %class.test1_D*
// CHECK-LL-NEXT: br label %40
// CHECK-LL: ; <label>:39
@@ -237,7 +237,7 @@ void test1() {
// CHECK-LL-NEXT: br i1 %42, label %43, label %47
// CHECK-LL: ; <label>:43
// CHECK-LL-NEXT: %44 = bitcast %class.test1_A* %tmp63 to i8*
-// CHECK-LL-NEXT: %45 = call i8* @__dynamic_cast(i8* %44, i8* bitcast (i8** @_ZTI7test1_A to i8*), i8* bitcast (i8** @_ZTI7test1_E to i8*), i64 -1)
+// CHECK-LL-NEXT: %45 = call i8* @__dynamic_cast(i8* %44, i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_E to i8*), i64 -1)
// CHECK-LL-NEXT: %46 = bitcast i8* %45 to %class.test1_E*
// CHECK-LL-NEXT: br label %48
// CHECK-LL: ; <label>:47
@@ -279,7 +279,7 @@ void test1() {
// CHECK-LL: if.end85:
// CHECK-LL-NEXT: br i1 false, label %50, label %53
// CHECK-LL: ; <label>:50
-// CHECK-LL-NEXT: %51 = call i8* @__dynamic_cast(i8* null, i8* bitcast (i8** @_ZTI7test1_A to i8*), i8* bitcast (i8** @_ZTI7test1_D to i8*), i64 -1)
+// CHECK-LL-NEXT: %51 = call i8* @__dynamic_cast(i8* null, i8* bitcast ({{.*}}* @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
// CHECK-LL-NEXT: %52 = bitcast i8* %51 to %class.test1_D*
// CHECK-LL-NEXT: br label %54
// CHECK-LL: ; <label>:53
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
new file mode 100644
index 000000000000..3dd7219d9afd
--- /dev/null
+++ b/test/CodeGenCXX/eh.cpp
@@ -0,0 +1,68 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s
+
+struct test1_D {
+ double d;
+} d1;
+
+void test1() {
+ throw d1;
+}
+
+// CHECK: define void @_Z5test1v() nounwind {
+// CHECK-NEXT:entry:
+// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test1_D*
+// CHECK-NEXT: %tmp = bitcast %struct.test1_D* %0 to i8*
+// CHECK-NEXT: call void @llvm.memcpy.i64(i8* %tmp, i8* bitcast (%struct.test1_D* @d1 to i8*), i64 8, i32 8)
+// CHECK-NEXT: call void @__cxa_throw(i8* %exception, i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
+// CHECK-NEXT: unreachable
+
+
+struct test2_D {
+ test2_D(const test2_D&o);
+ test2_D();
+ virtual void bar() { }
+ int i; int j;
+} d2;
+
+void test2() {
+ throw d2;
+}
+
+// CHECK: define void @_Z5test2v() nounwind {
+// CHECK-NEXT:entry:
+// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 16)
+// CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test2_D*
+// CHECK-NEXT: call void @_ZN7test2_DC1ERKS_(%struct.test2_D* %0, %struct.test2_D* @d2)
+// CHECK-NEXT: call void @__cxa_throw(i8* %exception, i8* bitcast (%0* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK-NEXT: unreachable
+
+
+struct test3_D {
+ test3_D() { }
+ test3_D(volatile test3_D&o);
+ virtual void bar();
+};
+
+void test3() {
+ throw (volatile test3_D *)0;
+}
+
+// CHECK: define void @_Z5test3v() nounwind {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test3_D**
+// CHECK-NEXT: store %struct.test3_D* null, %struct.test3_D** %0
+// CHECK-NEXT: call void @__cxa_throw(i8* %exception, i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
+// CHECK-NEXT: unreachable
+
+
+void test4() {
+ throw;
+}
+
+// CHECK: define void @_Z5test4v() nounwind {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxa_rethrow() noreturn
+// CHECK-NEXT: unreachable
diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp
new file mode 100644
index 000000000000..32ce33da952c
--- /dev/null
+++ b/test/CodeGenCXX/mangle-template.cpp
@@ -0,0 +1,68 @@
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+
+namespace test1 {
+int x;
+template <int& D> class T { };
+// CHECK: void @_ZN5test12f0ENS_1TILZNS_1xEEEE(
+void f0(T<x> a0) {}
+}
+
+namespace test1 {
+// CHECK: void @_ZN5test12f0Ef
+void f0(float) {}
+template<void (&)(float)> struct t1 {};
+// CHECK: void @_ZN5test12f1ENS_2t1ILZNS_2f0EfEEE(
+void f1(t1<f0> a0) {}
+}
+
+namespace test2 {
+// CHECK: void @_ZN5test22f0Ef
+void f0(float) {}
+template<void (*)(float)> struct t1 {};
+// FIXME: Fails because we don't treat as an expression.
+// CHECK-FIXME: void @_ZN5test22f1ENS_2t1IXadL_ZNS_2f0EfEEEE(
+void f1(t1<f0> a0) {}
+}
+
+namespace test3 {
+// CHECK: void @test3_f0
+extern "C" void test3_f0(float) {}
+template<void (&)(float)> struct t1 {};
+// FIXME: Fails because we tack on a namespace.
+// CHECK-FIXME: void @_ZN5test32f1ENS_2t1ILZ8test3_f0EEE(
+void f1(t1<test3_f0> a0) {}
+}
+
+namespace test4 {
+// CHECK: void @test4_f0
+extern "C" void test4_f0(float) {}
+template<void (*)(float)> struct t1 {};
+// FIXME: Fails because we don't treat as an expression.
+// CHECK-FIXME: void @_ZN5test42f1ENS_2t1IXadL_Z8test4_f0EEEE(
+void f1(t1<test4_f0> a0) {}
+}
+
+// CHECK: void @test5_f0
+extern "C" void test5_f0(float) {}
+int main(int) {}
+
+namespace test5 {
+template<void (&)(float)> struct t1 {};
+// CHECK: void @_ZN5test52f1ENS_2t1ILZ8test5_f0EEE(
+void f1(t1<test5_f0> a0) {}
+
+template<int (&)(int)> struct t2 {};
+// CHECK: void @_ZN5test52f2ENS_2t2ILZ4mainEEE
+void f2(t2<main> a0) {}
+}
+
+// FIXME: This fails.
+namespace test6 {
+struct A { void im0(float); };
+// CHECK: void @_ZN5test61A3im0Ef
+void A::im0(float) {}
+template <void(A::*)(float)> class T { };
+// FIXME: Fails because we don't treat as an expression.
+// CHECK-FAIL: void @_ZN5test62f0ENS_1TIXadL_ZNS_1A3im0EfEEEE(
+void f0(T<&A::im0> a0) {}
+}
diff --git a/test/CodeGenCXX/member-expressions.cpp b/test/CodeGenCXX/member-expressions.cpp
index f90b80733905..a38d5f9eaa2c 100644
--- a/test/CodeGenCXX/member-expressions.cpp
+++ b/test/CodeGenCXX/member-expressions.cpp
@@ -17,3 +17,30 @@ void f()
}
}
+
+struct A {
+ A();
+ ~A();
+ enum E { Foo };
+};
+
+A *g();
+
+void f(A *a) {
+ A::E e1 = a->Foo;
+
+ // CHECK: call %struct.A* @_Z1gv()
+ A::E e2 = g()->Foo;
+ // CHECK: call void @_ZN1AC1Ev(
+ // CHECK: call void @_ZN1AD1Ev(
+ A::E e3 = A().Foo;
+}
+
+namespace test3 {
+struct A {
+ static int foo();
+};
+int f() {
+ return A().foo();
+}
+}
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 7792560e067b..05bf39632517 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -34,6 +34,11 @@ void f() {
// CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 {{.*}}, 16
// CHECK: store i64 [[ADJ]], i64* getelementptr inbounds (%0* @pc, i32 0, i32 1)
pc = pa;
+
+ // CHECK: store i64 {{.*}}, i64* getelementptr inbounds (%0* @pa, i32 0, i32 0)
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub i64 {{.*}}, 16
+ // CHECK: store i64 [[ADJ]], i64* getelementptr inbounds (%0* @pa, i32 0, i32 1)
+ pa = static_cast<void (A::*)()>(pc);
}
void f2() {
@@ -55,6 +60,10 @@ void f3(A *a, A &ar) {
(ar.*pa)();
}
+bool f4() {
+ return pa;
+}
+
// PR5177
namespace PR5177 {
struct A {
@@ -87,3 +96,12 @@ namespace PR5138 {
void (foo::*ptr3)(void) = (void (foo::*)(void))&foo::bar;
}
+
+// PR5593
+namespace PR5593 {
+ struct A { };
+
+ bool f(void (A::*f)()) {
+ return f && f;
+ }
+}
diff --git a/test/CodeGenCXX/member-pointer-cast.cpp b/test/CodeGenCXX/member-pointer-cast.cpp
new file mode 100644
index 000000000000..794996881e2f
--- /dev/null
+++ b/test/CodeGenCXX/member-pointer-cast.cpp
@@ -0,0 +1,21 @@
+// RUN: clang-cc %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+
+struct A { int a; };
+struct B { int b; };
+struct C : B, A { };
+
+int A::*pa;
+int C::*pc;
+
+void f() {
+ // CHECK: store i64 -1, i64* @pa
+ pa = 0;
+
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 {{.*}}, 4
+ // CHECK: store i64 [[ADJ]], i64* @pc
+ pc = pa;
+
+ // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub i64 {{.*}}, 4
+ // CHECK: store i64 [[ADJ]], i64* @pa
+ pa = static_cast<int A::*>(pc);
+}
diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp
new file mode 100644
index 000000000000..c8494c42cef9
--- /dev/null
+++ b/test/CodeGenCXX/member-templates.cpp
@@ -0,0 +1,31 @@
+// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: ; ModuleID
+struct A {
+ template<typename T>
+ A(T);
+};
+
+template<typename T> A::A(T) {}
+
+struct B {
+ template<typename T>
+ B(T);
+};
+
+template<typename T> B::B(T) {}
+
+// CHECK: define void @_ZN1BC1IiEET_(%struct.B* %this, i32)
+// CHECK: define void @_ZN1BC2IiEET_(%struct.B* %this, i32)
+template B::B(int);
+
+template<typename T>
+struct C {
+ void f() {
+ int a[] = { 1, 2, 3 };
+ }
+};
+
+void f(C<int>& c) {
+ c.f();
+}
diff --git a/test/CodeGenCXX/new-with-default-arg.cpp b/test/CodeGenCXX/new-with-default-arg.cpp
new file mode 100644
index 000000000000..b73b7f0865ec
--- /dev/null
+++ b/test/CodeGenCXX/new-with-default-arg.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -emit-llvm -o - %s
+// pr5547
+
+struct A {
+ void* operator new(__typeof(sizeof(int)));
+ A();
+};
+
+A* x() {
+ return new A;
+}
+
+struct B {
+ void* operator new(__typeof(sizeof(int)), int = 1, int = 4);
+ B(float);
+};
+
+B* y() {
+ new (3,4) B(1);
+ return new(1) B(2);
+}
+
+struct C {
+ void* operator new(__typeof(sizeof(int)), int, int = 4);
+ C();
+};
+
+C* z() {
+ new (3,4) C;
+ return new(1) C;
+}
+
+
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 3f191de23bcf..13f26b253cd9 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+// RUN: clang-cc -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s
#include <stddef.h>
void t1() {
@@ -72,3 +72,21 @@ void t8(int n) {
new U[10];
new U[n];
}
+
+void t9() {
+ bool b;
+
+ new bool(true);
+ new (&b) bool(true);
+}
+
+struct A {
+ void* operator new(__typeof(sizeof(int)), int, float, ...);
+ A();
+};
+
+A* t10() {
+ // CHECK: @_ZN1AnwEmifz
+ return new(1, 2, 3.45, 100) A;
+}
+
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 8e0e1cbe84e8..eaaf346d7ccd 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -136,3 +136,8 @@ void f(int &a) {
(a = 10) = 20;
}
}
+
+// PR5590
+struct s0;
+struct s1 { struct s0 &s0; };
+void f0(s1 a) { s1 b = a; }
diff --git a/test/CodeGenCXX/temp-1.cpp b/test/CodeGenCXX/temp-1.cpp
deleted file mode 100644
index 9b97f0083c83..000000000000
--- a/test/CodeGenCXX/temp-1.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-// RUN: clang-cc -emit-llvm %s -o %t -triple=x86_64-apple-darwin9 &&
-struct A {
- A();
- ~A();
- void f();
-};
-
-// RUN: grep "call void @_ZN1AC1Ev" %t | count 2 &&
-// RUN: grep "call void @_ZN1AD1Ev" %t | count 2 &&
-void f1() {
- (void)A();
- A().f();
-}
-
-// Function calls
-struct B {
- B();
- ~B();
-};
-
-B g();
-
-// RUN: grep "call void @_ZN1BC1Ev" %t | count 0 &&
-// RUN: grep "call void @_ZN1BD1Ev" %t | count 1 &&
-void f2() {
- (void)g();
-}
-
-// Member function calls
-struct C {
- C();
- ~C();
-
- C f();
-};
-
-// RUN: grep "call void @_ZN1CC1Ev" %t | count 1 &&
-// RUN: grep "call void @_ZN1CD1Ev" %t | count 2 &&
-void f3() {
- C().f();
-}
-
-// Function call operator
-struct D {
- D();
- ~D();
-
- D operator()();
-};
-
-// RUN: grep "call void @_ZN1DC1Ev" %t | count 1 &&
-// RUN: grep "call void @_ZN1DD1Ev" %t | count 2 &&
-void f4() {
- D()();
-}
-
-// Overloaded operators
-struct E {
- E();
- ~E();
- E operator+(const E&);
- E operator!();
-};
-
-// RUN: grep "call void @_ZN1EC1Ev" %t | count 3 &&
-// RUN: grep "call void @_ZN1ED1Ev" %t | count 5 &&
-void f5() {
- E() + E();
- !E();
-}
-
-struct F {
- F();
- ~F();
- F& f();
-};
-
-// RUN: grep "call void @_ZN1FC1Ev" %t | count 1 &&
-// RUN: grep "call void @_ZN1FD1Ev" %t | count 1
-void f6() {
- F().f();
-}
-
diff --git a/test/CodeGenCXX/temp-order.cpp b/test/CodeGenCXX/temp-order.cpp
new file mode 100644
index 000000000000..ecf075fcc11d
--- /dev/null
+++ b/test/CodeGenCXX/temp-order.cpp
@@ -0,0 +1,199 @@
+// Output file should have no calls to error() with folding.
+// RUN: clang-cc -triple i386-unknown-unknown -O3 -emit-llvm -o %t %s
+// RUN: FileCheck %s < %t
+
+static unsigned pow(unsigned Base, unsigned Power) {
+ unsigned Val = 1;
+ while (Power--)
+ Val *= Base;
+ return Val;
+}
+
+struct TempTracker {
+ unsigned Product, Index;
+
+ TempTracker() : Product(1), Index(0) {}
+
+};
+
+// FIXME: This can be used to check elision as well, if P = 0 hacks are removed.
+struct A {
+ TempTracker &TT;
+ mutable unsigned P;
+ bool Truth;
+
+ A(TempTracker &_TT, unsigned _P, bool _Truth = true)
+ : TT(_TT), P(_P), Truth(_Truth) {}
+ A(const A &RHS) : TT(RHS.TT), P(RHS.P), Truth(RHS.Truth) { RHS.P = 0; }
+ ~A() {
+ if (P)
+ TT.Product *= pow(P, ++TT.Index);
+ }
+
+ A &operator=(const A &RHS) {
+ TT = RHS.TT;
+ P = RHS.P;
+ Truth = RHS.Truth;
+ RHS.P = 0;
+ return *this;
+ }
+
+ operator bool () { return Truth; }
+};
+
+// 3, 7, 2
+static unsigned f0(bool val = false) {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ if ((A(tt, 3), val))
+ A b(tt, 5);
+ A c(tt, 7);
+ }
+ return tt.Product;
+}
+
+// 3, 5, 7, 2
+static unsigned f1(bool val = true) {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ if ((A(tt, 3), val))
+ A b(tt, 5);
+ A c(tt, 7);
+ }
+ return tt.Product;
+}
+
+// 5, 3, 7, 2
+static unsigned f2() {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ if (A b = A(tt, 3))
+ A c(tt, 5);
+ A d(tt, 7);
+ }
+ return tt.Product;
+}
+
+// 7, 3, 11, 2
+static unsigned f3() {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ if (A b = A(tt, 3, false))
+ A c(tt, 5);
+ else
+ A c(tt, 7);
+ A d(tt, 11);
+ }
+ return tt.Product;
+}
+
+// 3, 7, 2
+static unsigned f4() {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ while (A b = A(tt, 3, false))
+ A c(tt, 5);
+ A c(tt, 7);
+ }
+ return tt.Product;
+}
+
+// 5, 3, 7, 2
+static unsigned f5() {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ while (A b = A(tt, 3, true)) {
+ A c(tt, 5);
+ break;
+ }
+ A c(tt, 7);
+ }
+ return tt.Product;
+}
+
+// 3, 7, 11, 5, 13, 2
+static unsigned f6() {
+ TempTracker tt;
+ {
+ A a(tt, 2);
+ for (A b = (A(tt, 3), A(tt, 5)), c = (A(tt, 7), A(tt, 11));;)
+ break;
+ A c(tt, 13);
+ }
+ return tt.Product;
+}
+
+extern "C" void error();
+extern "C" void print(const char *Name, unsigned N);
+
+#define ORDER3(a, b, c) (pow(a, 1) * pow(b, 2) * pow(c, 3))
+#define ORDER4(a, b, c, d) (ORDER3(a, b, c) * pow(d, 4))
+#define ORDER5(a, b, c, d, e) (ORDER4(a, b, c, d) * pow(e, 5))
+#define ORDER6(a, b, c, d, e, f) (ORDER5(a, b, c, d, e) * pow(f, 6))
+void test() {
+// CHECK: call void @print(i8* {{.*}}, i32 1176)
+ print("f0", f0());
+ if (f0() != ORDER3(3, 7, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 411600)
+ print("f1", f1());
+ if (f1() != ORDER4(3, 5, 7, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 246960)
+ print("f2", f2());
+ if (f2() != ORDER4(5, 3, 7, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 1341648)
+ print("f3", f3());
+ if (f3() != ORDER4(7, 3, 11, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 1176)
+ print("f4", f4());
+ if (f4() != ORDER3(3, 7, 2))
+ error();
+
+// CHECK: call void @print(i8* {{.*}}, i32 246960)
+ print("f5", f5());
+ if (f5() != ORDER4(5, 3, 7, 2))
+ error();
+
+// FIXME: Clang/LLVM currently can't fold this to a constant. If the error check
+// is present (since it avoids single-caller inlining). PR5645.
+
+// CHECK: call void @print(i8* {{.*}}, i32 1251552576)
+ print("f6", f6());
+// if (f6() != ORDER6(3, 7, 11, 5, 13, 2))
+// error();
+}
+
+
+
+#ifdef HARNESS
+
+#include <cstdlib>
+#include <cstdio>
+
+extern "C" void error() {
+ abort();
+}
+
+extern "C" void print(const char *name, unsigned N) {
+ printf("%s: %d\n", name, N);
+}
+
+int main() {
+ test();
+ return 0;
+}
+
+#endif
diff --git a/test/CodeGenCXX/virt-dtor-key.cpp b/test/CodeGenCXX/virt-dtor-key.cpp
new file mode 100644
index 000000000000..30f3563d8a2f
--- /dev/null
+++ b/test/CodeGenCXX/virt-dtor-key.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm %s -o - | FileCheck %s
+// CHECK: @_ZTI3foo = linkonce_odr constant
+class foo {
+ foo();
+ virtual ~foo();
+};
+
+foo::~foo() {
+}
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index b453ed55df3e..7135aaf81ec7 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -4,6 +4,11 @@
// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t-64.ll
// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s
+
+// CHECK-LP64: main:
+// CHECK-LP64: movl $1, 12(%rax)
+// CHECK-LP64: movl $2, 8(%rax)
+
struct B {
virtual void bar1();
virtual void bar2();
@@ -12,6 +17,12 @@ struct B {
void B::bar1() { }
void B::bar2() { }
+// CHECK-LP64: __ZTV1B:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1B
+// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
+// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
+
struct C {
virtual void bee1();
virtual void bee2();
@@ -41,6 +52,28 @@ public:
};
void F::foo() { }
+// CHECK-LP64: __ZTV1F:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 16
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1F
+// CHECK-LP64-NEXT: .quad __ZN1D3booEv
+// CHECK-LP64-NEXT: .quad __ZN1F3fooEv
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI1F
+// CHECK-LP64-NEXT: .quad __ZN2D13barEv
+// CHECK-LP64-NEXT: .quad __ZN2D14bar2Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar3Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev
+// CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev
+
+
int j;
void *vp;
void test2() {
@@ -79,9 +112,18 @@ int main() {
ap->b = 2;
}
-// CHECK-LP64: main:
-// CHECK-LP64: movl $1, 12(%rax)
-// CHECK-LP64: movl $2, 8(%rax)
+// CHECK-LP64: __ZTV1A:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI1A
+// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
+// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
+// CHECK-LP64-NEXT: .quad __ZN1A4foo1Ev
+// CHECK-LP64-NEXT: .quad __ZN1A4foo2Ev
+// CHECK-LP64-NEXT: .quad 18446744073709551600
+// CHECK-LP64-NEXT: .quad __ZTI1A
+// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev
+// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev
+
struct test12_A {
virtual void foo0() { }
@@ -675,12 +717,10 @@ virtual void foo_B2() { }
};
struct test16_D : test16_NV1, virtual test16_B2 {
- virtual void bar();
- virtual test16_D *foo1();
+ virtual void bar() { }
+ virtual test16_D *foo1() { return 0; }
};
-void test16_D::bar() { }
-
// CHECK-LP64: __ZTV8test16_D:
// CHECK-LP64-NEXT: .quad 32
// CHECK-LP64-NEXT: .quad 16
@@ -1040,45 +1080,6 @@ class test21_D : public test21_B, public test21_B1 {
-// CHECK-LP64: __ZTV1B:
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .quad __ZTI1B
-// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
-// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
-
-// CHECK-LP64: __ZTV1A:
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .quad __ZTI1A
-// CHECK-LP64-NEXT: .quad __ZN1B4bar1Ev
-// CHECK-LP64-NEXT: .quad __ZN1B4bar2Ev
-// CHECK-LP64-NEXT: .quad __ZN1A4foo1Ev
-// CHECK-LP64-NEXT: .quad __ZN1A4foo2Ev
-// CHECK-LP64-NEXT: .quad 18446744073709551600
-// CHECK-LP64-NEXT: .quad __ZTI1A
-// CHECK-LP64-NEXT: .quad __ZN1C4bee1Ev
-// CHECK-LP64-NEXT: .quad __ZN1C4bee2Ev
-
-// CHECK-LP64: __ZTV1F:
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .quad 16
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .quad __ZTI1F
-// CHECK-LP64-NEXT: .quad __ZN1D3booEv
-// CHECK-LP64-NEXT: .quad __ZN1F3fooEv
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .space 8
-// CHECK-LP64-NEXT: .quad 18446744073709551600
-// CHECK-LP64-NEXT: .quad __ZTI1F
-// CHECK-LP64-NEXT: .quad __ZN2D13barEv
-// CHECK-LP64-NEXT: .quad __ZN2D14bar2Ev
-// CHECK-LP64-NEXT: .quad __ZN2D14bar3Ev
-// CHECK-LP64-NEXT: .quad __ZN2D14bar4Ev
-// CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev
-
test21_D d21;
test20_D d20;
test19_D d19;
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
index a825120ad229..eae868f9b69c 100644
--- a/test/CodeGenCXX/virtual-base-cast.cpp
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -1,9 +1,33 @@
-// RUN: clang-cc -emit-llvm-only %s
+// RUN: clang-cc -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s
-struct A { virtual ~A(); };
-struct B : A { virtual ~B(); };
-struct C : virtual B { virtual ~C(); };
+struct A { int a; virtual int aa(); };
+struct B { int b; virtual int bb(); };
+struct C : virtual A, virtual B { int c; virtual int aa(); virtual int bb(); };
+struct AA { int a; virtual int aa(); };
+struct BB { int b; virtual int bb(); };
+struct CC : AA, BB { virtual int aa(); virtual int bb(); virtual int cc(); };
+struct D : virtual C, virtual CC { int e; };
-void f(C *c) {
- A* a = c;
-}
+D* x;
+
+A* a() { return x; }
+// CHECK: @_Z1av() nounwind
+// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -16
+// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32*
+// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
+// CHECK: }
+
+B* b() { return x; }
+// CHECK: @_Z1bv() nounwind
+// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20
+// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32*
+// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
+// CHECK: }
+
+BB* c() { return x; }
+// CHECK: @_Z1cv() nounwind
+// CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24
+// CHECK: [[CASTVBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRC]] to i32*
+// CHECK: [[VBASEOFFSETC:%[a-zA-Z0-9\.]+]] = load i32* [[CASTVBASEOFFSETPTRC]]
+// CHECK: add i32 [[VBASEOFFSETC]], 8
+// CHECK: }
diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp
new file mode 100644
index 000000000000..e791758aca9f
--- /dev/null
+++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+
+struct basic_ios{~basic_ios(); };
+
+template<typename _CharT> struct basic_istream : virtual public basic_ios {
+ virtual ~basic_istream(){}
+};
+
+template<typename _CharT> struct basic_iostream : public basic_istream<_CharT>
+{
+ virtual ~basic_iostream(){}
+};
+
+basic_iostream<char> res;
+
+int main() {
+}
+
+// CHECK: call void @_ZN9basic_iosD2Ev
diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
new file mode 100644
index 000000000000..4b069ead02b8
--- /dev/null
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s
+
+struct A {
+ A();
+};
+
+// CHECK: define void @_ZN1AC1Ev(%struct.A* %this)
+// CHECK: define void @_ZN1AC2Ev(%struct.A* %this)
+A::A() { }
+
+struct B : virtual A {
+ B();
+};
+
+// CHECK: define void @_ZN1BC1Ev(%struct.B* %this)
+// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt)
+B::B() { }
diff --git a/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
new file mode 100644
index 000000000000..1e1e96286e79
--- /dev/null
+++ b/test/CodeGenCXX/virtual-functions-incomplete-types.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+struct A;
+
+struct B {
+ virtual void f();
+ virtual A g();
+};
+
+void B::f() { }
+
+// CHECK: declare void @_ZN1B1gEv()
+
+struct C;
+
+struct D {
+ virtual void f();
+ virtual C g();
+};
+
+void D::f() { }
+
+struct C {
+ int a;
+};
+
+// CHECK: define i64 @_ZN1D1gEv(%struct.B* %this)
+C D::g() {
+ return C();
+}
diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp
index 6b5e7a7a1d2c..0e4c2abc1074 100644
--- a/test/CodeGenCXX/x86_64-arguments.cpp
+++ b/test/CodeGenCXX/x86_64-arguments.cpp
@@ -1,9 +1,24 @@
-// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s
-struct A { ~A(); };
+// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
-// RUN: grep 'define void @_Z2f11A(.struct.A\* .a)' %t
-void f1(A a) { }
+// CHECK: [[i64_i64_ty:%.*]] = type { i64, i64 }
+// CHECK: [[i64_double_ty:%.*]] = type { i64, double }
+
+// Basic base class test.
+struct f0_s0 { unsigned a; };
+struct f0_s1 : public f0_s0 { void *b; };
+// CHECK: define void @_Z2f05f0_s1([[i64_i64_ty]])
+void f0(f0_s1 a0) { }
+
+// Check with two eight-bytes in base class.
+struct f1_s0 { unsigned a; unsigned b; float c; };
+struct f1_s1 : public f1_s0 { float d;};
+// CHECK: define void @_Z2f15f1_s1([[i64_double_ty]])
+void f1(f1_s1 a0) { }
+
+// Check with two eight-bytes in base class and merge.
+struct f2_s0 { unsigned a; unsigned b; float c; };
+struct f2_s1 : public f2_s0 { char d;};
+// CHECK: define void @_Z2f25f2_s1([[i64_i64_ty]])
+void f2(f2_s1 a0) { }
-// RUN: grep 'define void @_Z2f2v(.struct.A\* noalias sret .agg.result)' %t
-A f2() { return A(); }
diff --git a/test/CodeGenObjC/class-obj-hidden-visibility.m b/test/CodeGenObjC/class-obj-hidden-visibility.m
deleted file mode 100644
index fc4ac12b1836..000000000000
--- a/test/CodeGenObjC/class-obj-hidden-visibility.m
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: clang-cc -fvisibility=hidden -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern _OBJC_" | count 2
-
-@interface INTF @end
-
-@implementation INTF @end
-
diff --git a/test/CodeGenObjC/constant-strings.m b/test/CodeGenObjC/constant-strings.m
index 8482376ff913..8204adc51886 100644
--- a/test/CodeGenObjC/constant-strings.m
+++ b/test/CodeGenObjC/constant-strings.m
@@ -1,6 +1,6 @@
// RUN: clang-cc -emit-llvm -o %t %s
// RUN: clang-cc -fgnu-runtime -emit-llvm -o %t %s && grep NXConstantString %t | count 1
-// RUN: clang-cc -fgnu-runtime -fconstant-string-class=NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1
+// RUN: clang-cc -fgnu-runtime -fconstant-string-class NSConstantString -emit-llvm -o %t %s && grep NSConstantString %t | count 1
id a = @"Hello World!";
diff --git a/test/CodeGenObjC/continuation-class.m b/test/CodeGenObjC/continuation-class.m
index 305d6c7ab39a..c22231063afa 100644
--- a/test/CodeGenObjC/continuation-class.m
+++ b/test/CodeGenObjC/continuation-class.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
@interface Object
- (id)new;
diff --git a/test/CodeGenObjC/dot-syntax-1.m b/test/CodeGenObjC/dot-syntax-1.m
index 6fab03935bea..18b972f04850 100644
--- a/test/CodeGenObjC/dot-syntax-1.m
+++ b/test/CodeGenObjC/dot-syntax-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
int printf(const char *, ...);
diff --git a/test/CodeGenObjC/dot-syntax.m b/test/CodeGenObjC/dot-syntax.m
index 348346b8fca2..01b71898a7a7 100644
--- a/test/CodeGenObjC/dot-syntax.m
+++ b/test/CodeGenObjC/dot-syntax.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
int printf(const char *, ...);
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index 6665cb9d584b..db8470b6bb2a 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -66,12 +66,15 @@ struct Innermost {
@interface Test
{
int ivar;
+ __attribute__((objc_gc(weak))) SEL selector;
}
-(void) test3: (Test* [3] [4])b ;
+- (SEL**) meth : (SEL) arg : (SEL*****) arg1 : (SEL*)arg2 : (SEL**) arg3;
@end
@implementation Test
-(void) test3: (Test* [3] [4])b {}
+- (SEL**) meth : (SEL) arg : (SEL*****) arg1 : (SEL*)arg2 : (SEL**) arg3 {}
@end
struct S { int iS; };
diff --git a/test/CodeGenObjC/hidden-synthesized-ivar.m b/test/CodeGenObjC/hidden-synthesized-ivar.m
deleted file mode 100644
index 50a87cb2f453..000000000000
--- a/test/CodeGenObjC/hidden-synthesized-ivar.m
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: clang-cc -fvisibility=hidden -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern _OBJC_IVAR_"
-@interface I
-{
- int P;
-}
-
-@property int P;
-@end
-
-@implementation I
-@synthesize P;
-@end
-
diff --git a/test/CodeGenObjC/hidden-visibility.m b/test/CodeGenObjC/hidden-visibility.m
index 082ee7a70a38..8596b41a79a7 100644
--- a/test/CodeGenObjC/hidden-visibility.m
+++ b/test/CodeGenObjC/hidden-visibility.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fvisibility=hidden -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
+// RUN: clang-cc -fvisibility hidden -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck %s
// CHECK: @"OBJC_IVAR_$_I.P" = hidden
// CHECK: @"OBJC_CLASS_$_I" = hidden
// CHECK: @"OBJC_METACLASS_$_I" = hidden
diff --git a/test/CodeGenObjC/hidden.m b/test/CodeGenObjC/hidden.m
index fd87d992aaf4..0c0dbb3aa50e 100644
--- a/test/CodeGenObjC/hidden.m
+++ b/test/CodeGenObjC/hidden.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
__attribute__((visibility("hidden")))
@interface Hidden
diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m
index 5cf4d2df2213..87f7cc6cc14a 100644
--- a/test/CodeGenObjC/messages-2.m
+++ b/test/CodeGenObjC/messages-2.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
int printf(const char *, ...);
diff --git a/test/CodeGenObjC/messages.m b/test/CodeGenObjC/messages.m
index ea8809ffcd18..ac3b81dead62 100644
--- a/test/CodeGenObjC/messages.m
+++ b/test/CodeGenObjC/messages.m
@@ -1,8 +1,8 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
// RUN: grep "objc_msgSend" %t | count 6
-// RUN: clang-cc -fgnu-runtime --emit-llvm -o %t %s
+// RUN: clang-cc -fgnu-runtime -emit-llvm -o %t %s
// RUN: grep "objc_msg_lookup" %t | count 6
-// RUN: clang-cc -fgnu-runtime -fobjc-nonfragile-abi --emit-llvm -o %t %s
+// RUN: clang-cc -fgnu-runtime -fobjc-nonfragile-abi -emit-llvm -o %t %s
// RUN: grep "objc_msg_lookup_sender" %t | count 6
typedef struct {
diff --git a/test/CodeGenObjC/metadata_symbols.m b/test/CodeGenObjC/metadata_symbols.m
index c608cd402240..9cc2296dd1ba 100644
--- a/test/CodeGenObjC/metadata_symbols.m
+++ b/test/CodeGenObjC/metadata_symbols.m
@@ -10,7 +10,7 @@
// RUN: grep -F 'define internal void @"\01-[A im0]"' %t
// RUN: grep -F 'define internal void @"\01-[A(Cat) im1]"' %t
-// RUN: clang-cc -fobjc-nonfragile-abi -fvisibility=hidden -emit-llvm -o %t %s
+// RUN: clang-cc -fobjc-nonfragile-abi -fvisibility hidden -emit-llvm -o %t %s
// RUN: grep '@"OBJC_METACLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t
// RUN: grep '@"OBJC_CLASS_$_A" = hidden global .*section "__DATA, __objc_data", align 8' %t
diff --git a/test/CodeGenObjC/newproperty-nested-synthesis-1.m b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
index 4d9319839d0b..898c81add5e9 100644
--- a/test/CodeGenObjC/newproperty-nested-synthesis-1.m
+++ b/test/CodeGenObjC/newproperty-nested-synthesis-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
@interface Object
- (id) new;
diff --git a/test/CodeGenObjC/property-getter-dot-syntax.m b/test/CodeGenObjC/property-getter-dot-syntax.m
index c1cc5e994774..8701b580af6e 100644
--- a/test/CodeGenObjC/property-getter-dot-syntax.m
+++ b/test/CodeGenObjC/property-getter-dot-syntax.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
@protocol NSObject
- (void *)description;
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index 59f096f5c590..2ab10541a7d0 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --emit-llvm -o %t %s
+// RUN: clang-cc -emit-llvm -o %t %s
int printf(const char *, ...);
diff --git a/test/CodeGenObjC/protocol-definition-hidden-visibility.m b/test/CodeGenObjC/protocol-definition-hidden-visibility.m
deleted file mode 100644
index 31a864b22d55..000000000000
--- a/test/CodeGenObjC/protocol-definition-hidden-visibility.m
+++ /dev/null
@@ -1,19 +0,0 @@
-// RUN: clang-cc -triple x86_64-apple-darwin10 -S -o - %s | grep -e "private_extern l_OBJC_PROTOCOL_" | count 2
-
-@interface FOO @end
-
-@interface NSObject @end
-
-@protocol SSHIPCProtocolHandler_BDC;
-
-typedef NSObject<SSHIPCProtocolHandler_BDC> _SSHIPCProtocolHandler_BDC;
-
-@interface SSHIPC_v2_RPFSProxy
-@property(nonatomic,readonly,retain) _SSHIPCProtocolHandler_BDC* protocolHandler_BDC;
-@end
-
-@implementation FOO
-- (_SSHIPCProtocolHandler_BDC*) protocolHandler_BDC {@protocol(SSHIPCProtocolHandler_BDC); }
-@end
-
-
diff --git a/test/CodeGenObjC/sel-as-builtin-type.m b/test/CodeGenObjC/sel-as-builtin-type.m
new file mode 100644
index 000000000000..c65a5b280542
--- /dev/null
+++ b/test/CodeGenObjC/sel-as-builtin-type.m
@@ -0,0 +1,23 @@
+// RUN: clang-cc -emit-llvm -o %t %s
+// pr5025
+// radar 7405040
+
+typedef const struct objc_selector {
+ void *sel_id;
+ const char *sel_types;
+} *SEL;
+
+@interface I2
++(id) dictionary;
+@end
+
+@implementation I3; // expected-warning {{cannot find interface declaration for 'I3'}}
++(void) initialize {
+ I2 *a0 = [I2 dictionary];
+}
+@end
+
+int func(SEL s1, SEL s2)
+{
+ return s1->sel_id == s2->sel_id;
+}
diff --git a/test/CodeGenObjC/undefined-protocol.m b/test/CodeGenObjC/undefined-protocol.m
new file mode 100644
index 000000000000..7fe0790032aa
--- /dev/null
+++ b/test/CodeGenObjC/undefined-protocol.m
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-llvm-only -fgnu-runtime %s
+
+@protocol MadeUpProtocol;
+
+@interface Object <MadeUpProtocol> @end
+@implementation Object @end
diff --git a/test/CodeGenObjC/variadic-sends.m b/test/CodeGenObjC/variadic-sends.m
index e2d13e3ae41d..ab0beef71453 100644
--- a/test/CodeGenObjC/variadic-sends.m
+++ b/test/CodeGenObjC/variadic-sends.m
@@ -8,33 +8,33 @@
@end
void f0(A *a) {
- // CHECK-X86-32: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*)*)
- // CHECK-X86-64: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*)*)
+ // CHECK-X86-32: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)
+ // CHECK-X86-64: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)
[a im0];
}
void f1(A *a) {
- // CHECK-X86-32: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32)*)
- // CHECK-X86-64: call void bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32)*)
+ // CHECK-X86-32: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)
+ // CHECK-X86-64: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)
[a im1: 1];
}
void f2(A *a) {
- // CHECK-X86-32: call void (i8*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32, i32, ...)*)
- // CHECK-X86-64: call void (i8*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (i8*, %struct.objc_selector*, ...)* @objc_msgSend to void (i8*, %struct.objc_selector*, i32, i32, ...)*)
+ // CHECK-X86-32: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
+ // CHECK-X86-64: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
[a im2: 1, 2];
}
@interface B : A @end
@implementation B : A
-(void) foo {
- // CHECK-X86-32: call void bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32)*)
- // CHECK-X86-64: call void bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32)*)
+ // CHECK-X86-32: call void bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32)*)
+ // CHECK-X86-64: call void bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32)*)
[super im1: 1];
}
-(void) bar {
- // CHECK-X86-32: call void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)*)
- // CHECK-X86-64: call void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, %struct.objc_selector*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, %struct.objc_selector*, i32, i32, ...)*)
+ // CHECK-X86-32: call void (%struct._objc_method_description*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32, i32, ...)*)
+ // CHECK-X86-64: call void (%struct._objc_method_description*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_method_description*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_method_description*, i8*, i32, i32, ...)*)
[super im2: 1, 2];
}
diff --git a/test/Coverage/ast-printing.c b/test/Coverage/ast-printing.c
index 2bed12e60bea..640dc29f394e 100644
--- a/test/Coverage/ast-printing.c
+++ b/test/Coverage/ast-printing.c
@@ -1,6 +1,6 @@
-// RUN: clang-cc --fsyntax-only %s
-// RUN: clang-cc --ast-print %s
-// RUN: clang-cc --ast-dump %s
-// RUN: clang-cc --ast-print-xml -o %t %s
+// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -ast-print %s
+// RUN: clang-cc -ast-dump %s
+// RUN: clang-cc -ast-print-xml -o %t %s
#include "c-language-features.inc"
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index 93c71912f64c..d627fca3522e 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -1,6 +1,6 @@
-// RUN: clang-cc --fsyntax-only %s
-// RUN: clang-cc --ast-print %s
-// RUN: clang-cc --ast-dump %s
-// FIXME: clang-cc --ast-print-xml -o %t %s
+// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -ast-print %s
+// RUN: clang-cc -ast-dump %s
+// FIXME: clang-cc -ast-print-xml -o %t %s
#include "cxx-language-features.inc"
diff --git a/test/Coverage/ast-printing.m b/test/Coverage/ast-printing.m
index e7589b80ed81..1b812288fed2 100644
--- a/test/Coverage/ast-printing.m
+++ b/test/Coverage/ast-printing.m
@@ -1,5 +1,5 @@
-// RUN: clang-cc --fsyntax-only %s
-// RUN: clang-cc --ast-print %s
-// RUN: clang-cc --ast-dump %s
+// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -ast-print %s
+// RUN: clang-cc -ast-dump %s
#include "objc-language-features.inc"
diff --git a/test/Coverage/parse-callbacks.c b/test/Coverage/parse-callbacks.c
index 537d63037441..e29b38bd0d26 100644
--- a/test/Coverage/parse-callbacks.c
+++ b/test/Coverage/parse-callbacks.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc --parse-noop %s
-// RUN: clang-cc --parse-print-callbacks %s
+// RUN: clang-cc -parse-noop %s
+// RUN: clang-cc -parse-print-callbacks %s
#include "c-language-features.inc"
diff --git a/test/Coverage/parse-callbacks.m b/test/Coverage/parse-callbacks.m
index fc240cfef721..310a1a6f6e28 100644
--- a/test/Coverage/parse-callbacks.m
+++ b/test/Coverage/parse-callbacks.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc --parse-noop %s
-// RUN: clang-cc --parse-print-callbacks %s
+// RUN: clang-cc -parse-noop %s
+// RUN: clang-cc -parse-print-callbacks %s
#include "objc-language-features.inc"
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index fe351843825f..f7f8b5ef5f80 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -1,14 +1,14 @@
-// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm 2> %t.log
+// RUN: clang -ccc-host-triple i386-unknown-unknown -### -S -O0 -Os %s -o %t.s -fverbose-asm -funwind-tables 2> %t.log
// RUN: grep '"-triple" "i386-unknown-unknown"' %t.log
// RUN: grep '"-S"' %t.log
// RUN: grep '"-disable-free"' %t.log
-// RUN: grep '"--relocation-model" "static"' %t.log
-// RUN: grep '"--disable-fp-elim"' %t.log
-// RUN: grep '"--unwind-tables=0"' %t.log
+// RUN: grep '"-mrelocation-model" "static"' %t.log
+// RUN: grep '"-mdisable-fp-elim"' %t.log
+// RUN: grep '"-munwind-tables"' %t.log
// RUN: grep '"-Os"' %t.log
// RUN: grep '"-o" .*clang-translation.*' %t.log
-// RUN: grep '"--asm-verbose"' %t.log
+// RUN: grep '"-masm-verbose"' %t.log
// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S %s -o %t.s 2> %t.log
-// RUN: grep '"--mcpu" "yonah"' %t.log
+// RUN: grep '"-mcpu" "yonah"' %t.log
// RUN: clang -ccc-host-triple x86_64-apple-darwin9 -### -S %s -o %t.s 2> %t.log
-// RUN: grep '"--mcpu" "core2"' %t.log
+// RUN: grep '"-mcpu" "core2"' %t.log
diff --git a/test/Driver/flags.c b/test/Driver/flags.c
index a3241007d8fb..bc50aae33870 100644
--- a/test/Driver/flags.c
+++ b/test/Driver/flags.c
@@ -1,9 +1,9 @@
// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float %s 2> %t.log
-// RUN: grep '"--no-implicit-float"' %t.log
+// RUN: grep '"-no-implicit-float"' %t.log
// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float -mno-soft-float %s 2> %t.log
-// RUN: grep '"--no-implicit-float"' %t.log | count 0
+// RUN: grep '"-no-implicit-float"' %t.log | count 0
// RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log
-// RUN: grep '"--no-implicit-float"' %t.log
+// RUN: grep '"-no-implicit-float"' %t.log
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
new file mode 100644
index 000000000000..2c783bc2e33a
--- /dev/null
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -0,0 +1,14 @@
+/* RUN: clang-cc -std=c++0x -fixit %s -o - | clang-cc -x c++ -std=c++0x -
+ */
+
+/* This is a test of the various code modification hints that only
+ apply in C++0x. */
+struct A {
+ explicit operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) { // expected-error{{explicit conversion to}}
+ }
+}
+
diff --git a/test/Frontend/mmacosx-version-min-test.c b/test/Frontend/mmacosx-version-min-test.c
deleted file mode 100644
index d117d1c776a8..000000000000
--- a/test/Frontend/mmacosx-version-min-test.c
+++ /dev/null
@@ -1 +0,0 @@
-// RUN: not clang-cc -fsyntax-only -mmacosx-version-min=10.4 -triple=x86_64-apple-darwin %s
diff --git a/test/Frontend/output-failures.c b/test/Frontend/output-failures.c
new file mode 100644
index 000000000000..a8687c754a01
--- /dev/null
+++ b/test/Frontend/output-failures.c
@@ -0,0 +1,4 @@
+// RUN: not clang-cc -emit-llvm -o %S/doesnotexist/somename %s 2> %t
+// RUN: FileCheck -check-prefix=OUTPUTFAIL -input-file=%t %s
+
+// OUTPUTFAIL: Error opening output file '{{.*}}doesnotexist{{.*}}'
diff --git a/test/Frontend/rewrite-macros.c b/test/Frontend/rewrite-macros.c
index 2d9fef40035b..1667925a2ba4 100644
--- a/test/Frontend/rewrite-macros.c
+++ b/test/Frontend/rewrite-macros.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -verify --rewrite-macros -o %t %s
+// RUN: clang-cc -verify -rewrite-macros -o %t %s
#define A(a,b) a ## b
diff --git a/test/Index/c-index-api-fn-scan.m b/test/Index/c-index-api-fn-scan.m
new file mode 100644
index 000000000000..3e2c9c272a20
--- /dev/null
+++ b/test/Index/c-index-api-fn-scan.m
@@ -0,0 +1,217 @@
+// RUN: clang-cc -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast
+// RUN: c-index-test -test-load-tu %t.ast scan-function | FileCheck %s
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@interface Foo
+{
+}
+
+- foo;
++ fooC;
+
+@end
+
+@interface Bar : Foo
+{
+}
+
+@end
+
+@interface Foo (FooCat)
+- (int) catMethodWithFloat:(float) fArg;
+- (float) floatMethod;
+@end
+
+@protocol Proto
+- pMethod;
+@end
+
+@protocol SubP <Proto>
+- spMethod;
+@end
+
+@interface Baz : Bar <SubP>
+{
+ int _anIVar;
+}
+
+- (Foo *) bazMethod;
+
+@end
+
+enum {
+ someEnum
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int main (int argc, const char * argv[]) {
+ Baz * bee;
+ id a = [bee foo];
+ id <SubP> c = [Foo fooC];
+ id <Proto> d;
+ d = c;
+ [d pMethod];
+ [bee catMethodWithFloat:[bee floatMethod]];
+ main(someEnum, (const char **)bee);
+}
+
+// CHECK: c-index-api-fn-scan.m:84:2: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-fn-scan.m:84:3: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-fn-scan.m:84:4: ObjCClassRef=Baz:84:8 [Context:Baz]
+// CHECK: c-index-api-fn-scan.m:84:6: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-fn-scan.m:84:8: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-fn-scan.m:84:9: VarDecl=bee:84:8 [Context:bee]
+// CHECK: c-index-api-fn-scan.m:84:10: VarDecl=bee:84:8 [Context:bee]
+// CHECK: <invalid loc>:85:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:85:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-fn-scan.m:85:5: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:6: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:7: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:8: VarDecl=a:85:5 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:9: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:10: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:11: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:12: VarRef=bee:84:8 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:13: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:14: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:15: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:16: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: c-index-api-fn-scan.m:85:17: ObjCSelectorRef=foo:24:1 [Context:a]
+// CHECK: <invalid loc>:86:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:86:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-fn-scan.m:86:5: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:6: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-fn-scan.m:86:7: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-fn-scan.m:86:8: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-fn-scan.m:86:9: ObjCProtocolRef=SubP:86:12 [Context:SubP]
+// CHECK: c-index-api-fn-scan.m:86:10: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:12: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:13: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:14: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:15: VarDecl=c:86:12 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:16: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:17: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:18: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:19: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:20: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:21: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:22: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:23: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:24: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: c-index-api-fn-scan.m:86:25: ObjCSelectorRef=fooC:25:1 [Context:c]
+// CHECK: <invalid loc>:87:2: TypedefDecl=id:0:0 [Context:id]
+// CHECK: <invalid loc>:87:3: TypedefDecl=id:0:0 [Context:id]
+// CHECK: c-index-api-fn-scan.m:87:5: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-fn-scan.m:87:6: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-fn-scan.m:87:7: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-fn-scan.m:87:8: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-fn-scan.m:87:9: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-fn-scan.m:87:10: ObjCProtocolRef=Proto:87:13 [Context:Proto]
+// CHECK: c-index-api-fn-scan.m:87:11: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-fn-scan.m:87:13: VarDecl=d:87:13 [Context:d]
+// CHECK: c-index-api-fn-scan.m:88:2: VarRef=d:87:13 [Context:main]
+// CHECK: c-index-api-fn-scan.m:88:6: VarRef=c:86:12 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:2: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:3: VarRef=d:87:13 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:4: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:5: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:6: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:7: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:8: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:9: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:10: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:11: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:89:12: ObjCSelectorRef=pMethod:41:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:2: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:3: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:4: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:5: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:6: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:7: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:8: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:9: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:10: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:11: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:12: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:13: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:14: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:15: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:16: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:17: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:18: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:19: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:20: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:21: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:22: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:23: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:24: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:25: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:26: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:27: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:28: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:29: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:30: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:31: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:32: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:33: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:34: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:35: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:36: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:37: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:38: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:39: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:40: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:41: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:42: ObjCSelectorRef=floatMethod:37:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:90:43: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:3: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:4: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:5: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:6: FunctionRef=main:83:5 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:8: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:9: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:10: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:11: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:12: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:13: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:14: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:15: EnumConstantRef=someEnum:58:3 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:33: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:34: VarRef=bee:84:8 [Context:main]
+// CHECK: c-index-api-fn-scan.m:91:35: VarRef=bee:84:8 [Context:main]
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 7ab143546df6..1d5a9a893156 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -98,127 +98,3 @@ int main (int argc, const char * argv[]) {
// CHECK: c-index-api-loadTU-test.m:85:5: VarDecl=a:85:5 [Context=main]
// CHECK: c-index-api-loadTU-test.m:86:12: VarDecl=c:86:12 [Context=main]
// CHECK: c-index-api-loadTU-test.m:87:13: VarDecl=d:87:13 [Context=main]
-// CHECK: c-index-api-loadTU-test.m:84:2: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-loadTU-test.m:84:3: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-loadTU-test.m:84:4: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-loadTU-test.m:84:6: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-loadTU-test.m:84:8: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-loadTU-test.m:84:9: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-loadTU-test.m:84:10: VarDecl=bee:84:8 [Context:bee]
-// CHECK: <invalid loc>:85:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:85:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-loadTU-test.m:85:5: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:6: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:7: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:8: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:9: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:10: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:11: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:12: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:13: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:14: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:15: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:16: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-loadTU-test.m:85:17: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: <invalid loc>:86:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:86:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-loadTU-test.m:86:5: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:6: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-loadTU-test.m:86:7: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-loadTU-test.m:86:8: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-loadTU-test.m:86:9: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-loadTU-test.m:86:10: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:12: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:13: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:14: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:15: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:16: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:17: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:18: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:19: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:20: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:21: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:22: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:23: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:24: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-loadTU-test.m:86:25: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: <invalid loc>:87:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:87:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-loadTU-test.m:87:5: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-loadTU-test.m:87:6: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-loadTU-test.m:87:7: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-loadTU-test.m:87:8: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-loadTU-test.m:87:9: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-loadTU-test.m:87:10: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-loadTU-test.m:87:11: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-loadTU-test.m:87:13: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-loadTU-test.m:88:2: VarRef=d:87:13 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:88:6: VarRef=c:86:12 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:2: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:3: VarRef=d:87:13 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:4: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:5: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:6: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:7: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:8: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:9: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:10: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:11: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:89:12: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:2: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:3: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:4: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:5: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:6: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:7: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:8: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:9: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:10: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:11: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:12: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:13: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:14: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:15: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:16: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:17: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:18: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:19: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:20: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:21: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:22: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:23: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:24: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:25: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:26: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:27: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:28: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:29: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:30: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:31: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:32: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:33: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:34: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:35: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:36: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:37: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:38: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:39: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:40: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:41: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:42: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:90:43: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:3: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:4: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:5: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:6: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:8: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:9: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:10: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:11: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:12: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:13: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:14: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:15: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:33: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:34: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-loadTU-test.m:91:35: VarRef=bee:84:8 [Context:main]
diff --git a/test/Index/c-index-api-test.m b/test/Index/c-index-api-test.m
deleted file mode 100644
index 55669e7579cd..000000000000
--- a/test/Index/c-index-api-test.m
+++ /dev/null
@@ -1,224 +0,0 @@
-// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-pch -x objective-c %s -o %t.ast
-// RUN: c-index-test %t.ast all | FileCheck %s
-
-// CHECK: <invalid loc>:0:0: TypedefDecl=__int128_t:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: TypedefDecl=__uint128_t:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: StructDecl=objc_selector:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: TypedefDecl=SEL:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: ObjCInterfaceDecl=Protocol:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: TypedefDecl=id:0:0 [Context=c-index-api-test.m]
-// CHECK: <invalid loc>:0:0: TypedefDecl=Class:0:0 [Context=c-index-api-test.m]
-// CHECK: <built-in>:79:16: StructDecl=__va_list_tag:79:16 [Context=c-index-api-test.m]
-// CHECK: <built-in>:79:42: FieldDecl=gp_offset:79:42 [Context=__va_list_tag]
-// CHECK: <built-in>:79:63: FieldDecl=fp_offset:79:63 [Context=__va_list_tag]
-// CHECK: <built-in>:79:81: FieldDecl=overflow_arg_area:79:81 [Context=__va_list_tag]
-// CHECK: <built-in>:79:107: FieldDecl=reg_save_area:79:107 [Context=__va_list_tag]
-// CHECK: <built-in>:79:123: TypedefDecl=__va_list_tag:79:123 [Context=c-index-api-test.m]
-// CHECK: <built-in>:79:159: TypedefDecl=__builtin_va_list:79:159 [Context=c-index-api-test.m]
-//
-
-@interface Foo
-{
-}
-
-- foo;
-+ fooC;
-
-@end
-
-@interface Bar : Foo
-{
-}
-
-@end
-
-@interface Foo (FooCat)
-- (int) catMethodWithFloat:(float) fArg;
-- (float) floatMethod;
-@end
-
-@protocol Proto
-- pMethod;
-@end
-
-@protocol SubP <Proto>
-- spMethod;
-@end
-
-@interface Baz : Bar <SubP>
-{
- int _anIVar;
-}
-
-- (Foo *) bazMethod;
-
-@end
-
-enum {
- someEnum
-};
-
-// CHECK: c-index-api-test.m:20:12: ObjCInterfaceDecl=Foo:20:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:24:1: ObjCInstanceMethodDecl=foo:24:1 [Context=Foo]
-// CHECK: c-index-api-test.m:25:1: ObjCClassMethodDecl=fooC:25:1 [Context=Foo]
-// CHECK: c-index-api-test.m:29:12: ObjCInterfaceDecl=Bar:29:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:29:18: ObjCSuperClassRef=Foo:29:1 [Context=Bar]
-// CHECK: c-index-api-test.m:35:1: ObjCCategoryDecl=FooCat:35:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:20:1: ObjCClassRef=Foo:35:1 [Context=FooCat]
-// CHECK: c-index-api-test.m:36:1: ObjCInstanceMethodDecl=catMethodWithFloat::36:1 [Context=FooCat]
-// CHECK: c-index-api-test.m:37:1: ObjCInstanceMethodDecl=floatMethod:37:1 [Context=FooCat]
-// CHECK: c-index-api-test.m:40:1: ObjCProtocolDecl=Proto:40:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:41:1: ObjCInstanceMethodDecl=pMethod:41:1 [Context=Proto]
-// CHECK: c-index-api-test.m:44:1: ObjCProtocolDecl=SubP:44:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:40:1: ObjCProtocolRef=Proto:40:1 [Context=SubP]
-// CHECK: c-index-api-test.m:45:1: ObjCInstanceMethodDecl=spMethod:45:1 [Context=SubP]
-// CHECK: c-index-api-test.m:48:12: ObjCInterfaceDecl=Baz:48:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:48:18: ObjCSuperClassRef=Bar:48:1 [Context=Baz]
-// CHECK: c-index-api-test.m:44:1: ObjCProtocolRef=SubP:44:1 [Context=Baz]
-// CHECK: c-index-api-test.m:50:9: ObjCIvarDecl=_anIVar:50:9 [Context=Baz]
-// CHECK: c-index-api-test.m:53:1: ObjCInstanceMethodDecl=bazMethod:53:1 [Context=Baz]
-// CHECK: c-index-api-test.m:57:1: EnumDecl=:57:1 [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:58:3: EnumConstantDecl=someEnum:58:3 [Context=]
-
-int main (int argc, const char * argv[]) {
- Baz * bee;
- id a = [bee foo];
- id <SubP> c = [Foo fooC];
- id <Proto> d;
- d = c;
- [d pMethod];
- [bee catMethodWithFloat:[bee floatMethod]];
- main(someEnum, (const char **)bee);
-}
-
-// CHECK: c-index-api-test.m:83:5: FunctionDefn=main [Context=c-index-api-test.m]
-// CHECK: c-index-api-test.m:83:15: ParmDecl=argc:83:15 [Context=main]
-// CHECK: c-index-api-test.m:83:34: ParmDecl=argv:83:34 [Context=main]
-// CHECK: c-index-api-test.m:84:8: VarDecl=bee:84:8 [Context=main]
-// CHECK: c-index-api-test.m:85:5: VarDecl=a:85:5 [Context=main]
-// CHECK: c-index-api-test.m:86:12: VarDecl=c:86:12 [Context=main]
-// CHECK: c-index-api-test.m:87:13: VarDecl=d:87:13 [Context=main]
-// CHECK: c-index-api-test.m:84:2: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-test.m:84:3: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-test.m:84:4: ObjCClassRef=Baz:84:8 [Context:Baz]
-// CHECK: c-index-api-test.m:84:6: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-test.m:84:8: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-test.m:84:9: VarDecl=bee:84:8 [Context:bee]
-// CHECK: c-index-api-test.m:84:10: VarDecl=bee:84:8 [Context:bee]
-// CHECK: <invalid loc>:85:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:85:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-test.m:85:5: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-test.m:85:6: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-test.m:85:7: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-test.m:85:8: VarDecl=a:85:5 [Context:a]
-// CHECK: c-index-api-test.m:85:9: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-test.m:85:10: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-test.m:85:11: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-test.m:85:12: VarRef=bee:84:8 [Context:a]
-// CHECK: c-index-api-test.m:85:13: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-test.m:85:14: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-test.m:85:15: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-test.m:85:16: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: c-index-api-test.m:85:17: ObjCSelectorRef=foo:24:1 [Context:a]
-// CHECK: <invalid loc>:86:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:86:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-test.m:86:5: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:6: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-test.m:86:7: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-test.m:86:8: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-test.m:86:9: ObjCProtocolRef=SubP:86:12 [Context:SubP]
-// CHECK: c-index-api-test.m:86:10: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:12: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:13: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:14: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:15: VarDecl=c:86:12 [Context:c]
-// CHECK: c-index-api-test.m:86:16: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:17: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:18: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:19: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:20: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:21: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:22: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:23: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:24: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: c-index-api-test.m:86:25: ObjCSelectorRef=fooC:25:1 [Context:c]
-// CHECK: <invalid loc>:87:2: TypedefDecl=id:0:0 [Context:id]
-// CHECK: <invalid loc>:87:3: TypedefDecl=id:0:0 [Context:id]
-// CHECK: c-index-api-test.m:87:5: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-test.m:87:6: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-test.m:87:7: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-test.m:87:8: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-test.m:87:9: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-test.m:87:10: ObjCProtocolRef=Proto:87:13 [Context:Proto]
-// CHECK: c-index-api-test.m:87:11: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-test.m:87:13: VarDecl=d:87:13 [Context:d]
-// CHECK: c-index-api-test.m:88:2: VarRef=d:87:13 [Context:main]
-// CHECK: c-index-api-test.m:88:6: VarRef=c:86:12 [Context:main]
-// CHECK: c-index-api-test.m:89:2: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:3: VarRef=d:87:13 [Context:main]
-// CHECK: c-index-api-test.m:89:4: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:5: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:6: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:7: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:8: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:9: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:10: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:11: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:89:12: ObjCSelectorRef=pMethod:41:1 [Context:main]
-// CHECK: c-index-api-test.m:90:2: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:3: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:4: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:5: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:6: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:7: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:8: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:9: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:10: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:11: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:12: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:13: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:14: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:15: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:16: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:17: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:18: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:19: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:20: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:21: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:22: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:23: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:24: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:25: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:90:26: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:27: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:28: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:29: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:90:30: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:31: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:32: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:33: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:34: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:35: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:36: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:37: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:38: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:39: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:40: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:41: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:42: ObjCSelectorRef=floatMethod:37:1 [Context:main]
-// CHECK: c-index-api-test.m:90:43: ObjCSelectorRef=catMethodWithFloat::36:1 [Context:main]
-// CHECK: c-index-api-test.m:91:3: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-test.m:91:4: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-test.m:91:5: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-test.m:91:6: FunctionRef=main:83:5 [Context:main]
-// CHECK: c-index-api-test.m:91:8: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:9: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:10: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:11: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:12: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:13: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:14: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:15: EnumConstantRef=someEnum:58:3 [Context:main]
-// CHECK: c-index-api-test.m:91:33: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:91:34: VarRef=bee:84:8 [Context:main]
-// CHECK: c-index-api-test.m:91:35: VarRef=bee:84:8 [Context:main]
diff --git a/test/Index/c-index-pch.h b/test/Index/c-index-pch.h
deleted file mode 100644
index 6dda18000c2f..000000000000
--- a/test/Index/c-index-pch.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef C_INDEX_PCH_H
-#define C_INDEX_PCH_H
-
-void foo(int i, float f);
-extern int bar;
-
-#endif // C_INDEX_PCH_H
diff --git a/test/Index/foo.h b/test/Index/foo.h
deleted file mode 100644
index 7670c00dfbfe..000000000000
--- a/test/Index/foo.h
+++ /dev/null
@@ -1,8 +0,0 @@
-extern int global_var;
-
-void foo_func(int param1);
-void bar_func(void);
-
-struct MyStruct {
- int field_var;
-};
diff --git a/test/Index/objc.h b/test/Index/objc.h
deleted file mode 100644
index c671addde59f..000000000000
--- a/test/Index/objc.h
+++ /dev/null
@@ -1,11 +0,0 @@
-@interface Base {
- int my_var;
-}
--(int) my_var;
--(void) my_method: (int)param;
-+(void) my_method: (int)param;
-@end
-
-@interface Sub : Base
--(void) my_method: (int)param;
-@end
diff --git a/test/Index/t1.c b/test/Index/t1.c
deleted file mode 100644
index 45e04881244d..000000000000
--- a/test/Index/t1.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "foo.h"
-
-void foo_func(int param1) {
- int local_var = global_var;
- for (int for_var = 100; for_var < 500; ++for_var) {
- local_var = param1 + for_var;
- }
- bar_func();
-}
-
-struct S1 {
- int x;
-};
-
-struct S2 {
- int x;
-};
-
-void field_test(void) {
- struct S1 s1;
- s1.x = 0;
- ((struct S2 *)0)->x = 0;
-
- struct MyStruct ms;
- ms.field_var = 10;
-}
-
-int (^CP)(int) = ^(int x) { return x * global_var; };
-
-// Suppress 'no run line' failure.
-// RUN: true
diff --git a/test/Index/t1.m b/test/Index/t1.m
deleted file mode 100644
index b2a7a3726d20..000000000000
--- a/test/Index/t1.m
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "objc.h"
-
-static void foo() {
- Base *base;
- int x = [base my_var];
- [base my_method:x];
- [Base my_method:x];
-}
-
-@implementation Base
--(int) my_var {
- return my_var;
-}
-
--(void) my_method: (int)param {
-}
-
-+(void) my_method: (int)param {
-}
-@end
-
-// Suppress 'no run line' failure.
-// RUN: true
diff --git a/test/Index/t2.c b/test/Index/t2.c
deleted file mode 100644
index bf52869ec8d9..000000000000
--- a/test/Index/t2.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "foo.h"
-
-int global_var = 10;
-
-void bar_func(void) {
- global_var += 100;
- foo_func(global_var);
-
- struct MyStruct *ms;
- ms->field_var = 10;
-}
-
-// Suppress 'no run line' failure.
-// RUN: true
diff --git a/test/Index/t2.m b/test/Index/t2.m
deleted file mode 100644
index 00d2f1d92b05..000000000000
--- a/test/Index/t2.m
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "objc.h"
-
-static void foo() {
- Sub *sub;
- int x = [sub my_var];
- [sub my_method:x];
- [Sub my_method:x];
-}
-
-@implementation Sub
--(void) my_method: (int)param {
-}
-@end
-
-// Suppress 'no run line' failure.
-// RUN: true
diff --git a/test/Lexer/constants-ms.c b/test/Lexer/constants-ms.c
new file mode 100644
index 000000000000..8176ec3249f9
--- /dev/null
+++ b/test/Lexer/constants-ms.c
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify -fms-extensions %s
+
+__int8 x1 = 3i8;
+__int16 x2 = 4i16;
+__int32 x3 = 5i32;
+__int64 x5 = 0x42i64;
+__int64 x4 = 70000000i128;
+
+__int64 y = 0x42i64u; // expected-error {{invalid suffix}}
+__int64 w = 0x43ui64; // expected-error {{invalid suffix}}
+__int64 z = 9Li64; // expected-error {{invalid suffix}}
+__int64 q = 10lli64; // expected-error {{invalid suffix}}
diff --git a/test/Misc/diag-checker.c b/test/Misc/diag-checker.c
deleted file mode 100644
index 4733ee1e03d7..000000000000
--- a/test/Misc/diag-checker.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: clang-cc -fsyntax-only -verify %s
-
-#include <stdio.h>
-
-void foo(FILE *FP) {}
diff --git a/test/PCH/method_pool.m b/test/PCH/method_pool.m
index 3fe45a66a47d..053438828e36 100644
--- a/test/PCH/method_pool.m
+++ b/test/PCH/method_pool.m
@@ -2,7 +2,7 @@
// RUN: clang-cc -include %S/method_pool.h -fsyntax-only -verify %s
// Test with pch.
-// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/method_pool.h
+// RUN: clang-cc -x objective-c -emit-pch -o %t %S/method_pool.h
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
int message_id(id x) {
diff --git a/test/PCH/objc_import.m b/test/PCH/objc_import.m
index 83f389c4ca90..12893861585a 100644
--- a/test/PCH/objc_import.m
+++ b/test/PCH/objc_import.m
@@ -2,7 +2,7 @@
// RUN: clang-cc -include %S/objc_import.h -fsyntax-only -verify %s
// Test with pch.
-// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_import.h
+// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_import.h
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
#import "objc_import.h"
diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m
index aff34d114f02..136e39706c82 100644
--- a/test/PCH/objc_methods.m
+++ b/test/PCH/objc_methods.m
@@ -2,7 +2,7 @@
// RUN: clang-cc -include %S/objc_methods.h -fsyntax-only -verify %s
// Test with pch.
-// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_methods.h
+// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_methods.h
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
void func() {
diff --git a/test/PCH/objc_property.m b/test/PCH/objc_property.m
index a1d3eb99ceb5..5992787fa422 100644
--- a/test/PCH/objc_property.m
+++ b/test/PCH/objc_property.m
@@ -2,7 +2,7 @@
// RUN: clang-cc -include %S/objc_property.h -fsyntax-only -verify %s
// Test with pch.
-// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_property.h
+// RUN: clang-cc -x objective-c -emit-pch -o %t %S/objc_property.h
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
void func() {
diff --git a/test/PCH/reloc.c b/test/PCH/reloc.c
index 36247d50296e..ba8e70db024a 100644
--- a/test/PCH/reloc.c
+++ b/test/PCH/reloc.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -emit-pch -o %t --relocatable-pch -isysroot %S/libroot %S/libroot/usr/include/reloc.h
+// RUN: clang-cc -emit-pch -o %t -relocatable-pch -isysroot %S/libroot %S/libroot/usr/include/reloc.h
// RUN: clang-cc -include-pch %t -isysroot %S/libroot %s -verify
// RUN: not clang-cc -include-pch %t %s
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 572ac44d1f40..9c804c354e5a 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify -fms-extensions -x=objective-c++ %s
+// RUN: clang-cc -fsyntax-only -verify -fms-extensions -x objective-c++ %s
__stdcall int func0();
int __stdcall func();
typedef int (__cdecl *tptr)();
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index dc2bb02670c6..cad39d382d18 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -51,3 +51,4 @@ int foo42(void) {
// rdar://6096491
void __attribute__((noreturn)) d0(void), __attribute__((noreturn)) d1(void);
+void d2(void) __attribute__((noreturn)), d3(void) __attribute__((noreturn));
diff --git a/test/Parser/cxx-attributes.cpp b/test/Parser/cxx-attributes.cpp
new file mode 100644
index 000000000000..743d9b9ec1f2
--- /dev/null
+++ b/test/Parser/cxx-attributes.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class c {
+ virtual void f1(const char* a, ...)
+ __attribute__ (( __format__(__printf__,2,3) )) = 0;
+ virtual void f2(const char* a, ...)
+ __attribute__ (( __format__(__printf__,2,3) )) {}
+};
+
diff --git a/test/Parser/cxx-parse-member-pointer-op.cpp b/test/Parser/cxx-parse-member-pointer-op.cpp
deleted file mode 100644
index cc2e8b142fcb..000000000000
--- a/test/Parser/cxx-parse-member-pointer-op.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: clang-cc -fsyntax-only -pedantic -verify %s
-
-struct C {};
-
-typedef void (C::*pmfc)();
-
-void g(pmfc) {
- C *c;
- c->*pmfc(); // expected-error {{invalid use of pointer to member type after '->*'}}
- C c1;
- c1.*pmfc(); // expected-error {{invalid use of pointer to member type after '.*'}}
-}
-
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 2b2d3de50497..644f0def79c9 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -1,11 +1,11 @@
-// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -verify %s
// Errors
export class foo { }; // expected-error {{expected template}}
template x; // expected-error {{C++ requires a type specifier for all declarations}} \
// expected-error {{does not refer}}
export template x; // expected-error {{expected '<' after 'template'}}
-export template<class T> class x0; // expected-note {{exported templates are unsupported}}
+export template<class T> class x0; // expected-warning {{exported templates are unsupported}}
template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
// expected-error{{extraneous}}
diff --git a/test/Parser/cxx-using-declaration.cpp b/test/Parser/cxx-using-declaration.cpp
index a2bc8c54edc7..461b9e597d25 100644
--- a/test/Parser/cxx-using-declaration.cpp
+++ b/test/Parser/cxx-using-declaration.cpp
@@ -1,4 +1,3 @@
-// FIXME: Disabled, appears to have undefined behavior, and needs to be updated to match new warnings.
// RUN: clang-cc -fsyntax-only -verify %s
// XFAIL: *
@@ -12,7 +11,7 @@ using A::VA;
using A::FA;
using typename A::SA;
-void main()
+int main()
{
VA = 1;
FA();
@@ -35,7 +34,7 @@ namespace E {
template <typename TYPE> int funcE(TYPE arg) { return(arg); }
}
-using E::funcE<int>; // expected-error{{use of template specialization in using directive not allowed}}
+using E::funcE<int>; // expected-error{{using declaration can not refer to a template specialization}}
namespace F {
struct X;
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
new file mode 100644
index 000000000000..a66e3e059766
--- /dev/null
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+// Declaration syntax checks
+[[]] int before_attr;
+int after_attr [[]];
+int * [[]] ptr_attr;
+int array_attr [1] [[]];
+[[align(8)]] int aligned_attr;
+[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
+ int garbage_attr;
+void fn_attr () [[]];
+class [[]] class_attr {};
+extern "C++" [[]] int extern_attr;
+template <typename T> [[]] void template_attr ();
+
+int comma_attr [[,]]; // expected-error {{expected identifier}}
+int scope_attr [[foo::]]; // expected-error {{expected identifier}}
+int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
+class foo {
+ void after_const_attr () const [[]]; // expected-error {{expected expression}}
+};
+extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
+[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
+[[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}}
+[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
+[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
+
+[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
+[[]] using namespace ns;
+
+// Argument tests
+[[final()]] int final_params; // expected-error {{C++0x attribute 'final' cannot have an argument list}}
+[[align]] int aligned_no_params; // expected-error {{C++0x attribute 'align' must have an argument list}}
+[[align(i)]] int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}}
+
+// Statement tests
+void foo () {
+ [[]] ;
+ [[]] { }
+ [[]] if (0) { }
+ [[]] for (;;);
+ [[]] do {
+ [[]] continue;
+ } while (0);
+ [[]] while (0);
+
+ [[]] switch (i) {
+ [[]] case 0:
+ [[]] default:
+ [[]] break;
+ }
+
+ [[]] goto there;
+ [[]] there:
+
+ [[]] try {
+ } [[]] catch (...) { // expected-error {{an attribute list cannot appear here}}
+ }
+
+ [[]] return;
+}
diff --git a/test/Parser/cxx0x-literal-operators.cpp b/test/Parser/cxx0x-literal-operators.cpp
new file mode 100644
index 000000000000..c5514601d116
--- /dev/null
+++ b/test/Parser/cxx0x-literal-operators.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+void operator "" (); // expected-error {{expected identifier}}
+void operator "k" foo(); // expected-error {{string literal after 'operator' must be '""'}}
+void operator "" tester (int);
diff --git a/test/Parser/if-scope-c90.c b/test/Parser/if-scope-c90.c
index 53987dccbc37..c372f0fc4f4d 100644
--- a/test/Parser/if-scope-c90.c
+++ b/test/Parser/if-scope-c90.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify --std=c90 %s
+// RUN: clang-cc -fsyntax-only -verify -std=c90 %s
int f (int z)
{
diff --git a/test/Parser/if-scope-c99.c b/test/Parser/if-scope-c99.c
index b4cb51ca8c4f..0cb2495efce2 100644
--- a/test/Parser/if-scope-c99.c
+++ b/test/Parser/if-scope-c99.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify --std=c99 %s
+// RUN: clang-cc -fsyntax-only -verify -std=c99 %s
int f (int z)
{
diff --git a/test/Preprocessor/assembler-with-cpp.c b/test/Preprocessor/assembler-with-cpp.c
index 693d5b81a17f..17880c8da7e3 100644
--- a/test/Preprocessor/assembler-with-cpp.c
+++ b/test/Preprocessor/assembler-with-cpp.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=0 -E %s -o - | FileCheck -strict-whitespace -check-prefix=CHECK-Identifiers-False %s
+// RUN: clang-cc -x assembler-with-cpp -E %s -o - | FileCheck -strict-whitespace -check-prefix=CHECK-Identifiers-False %s
#ifndef __ASSEMBLER__
#error "__ASSEMBLER__ not defined"
@@ -49,7 +49,7 @@
6: FOO(blarg)
// CHECK-Identifiers-False: 6: blarg $foo
-// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers=1 -E %s -o - | FileCheck -check-prefix=CHECK-Identifiers-True -strict-whitespace %s
+// RUN: clang-cc -x assembler-with-cpp -fdollars-in-identifiers -E %s -o - | FileCheck -check-prefix=CHECK-Identifiers-True -strict-whitespace %s
#define FOO(name) name ## $foo
7: FOO(blarg)
// CHECK-Identifiers-True: 7: blarg$foo
diff --git a/test/Preprocessor/cxx_true.cpp b/test/Preprocessor/cxx_true.cpp
index 80aa04e2b99e..bca70c5949e6 100644
--- a/test/Preprocessor/cxx_true.cpp
+++ b/test/Preprocessor/cxx_true.cpp
@@ -1,6 +1,6 @@
-/* RUN: clang-cc -E %s -x=c++ | grep block_1
- RUN: clang-cc -E %s -x=c++ | not grep block_2
- RUN: clang-cc -E %s -x=c | not grep block
+/* RUN: clang-cc -E %s -x c++ | grep block_1
+ RUN: clang-cc -E %s -x c++ | not grep block_2
+ RUN: clang-cc -E %s -x c | not grep block
*/
#if true
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index dbfde4b430b7..9ccff0e12025 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -1,5 +1,5 @@
-// RUN: clang-cc %s --triple=i686-apple-darwin9
-// RUN: clang-cc %s -E --triple=i686-apple-darwin9
+// RUN: clang-cc %s -triple=i686-apple-darwin9
+// RUN: clang-cc %s -E -triple=i686-apple-darwin9
#ifndef __has_feature
#error Should have __has_feature
#endif
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index aae218db46da..163734e185e3 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -E -dM -x=assembler-with-cpp < /dev/null | FileCheck -check-prefix ASM %s
+// RUN: clang-cc -E -dM -x assembler-with-cpp < /dev/null | FileCheck -check-prefix ASM %s
//
// ASM:#define __ASSEMBLER__ 1
//
@@ -9,7 +9,7 @@
// BLOCKS:#define __block __attribute__((__blocks__(byref)))
//
//
-// RUN: clang-cc -x=c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
+// RUN: clang-cc -x c++ -std=c++0x -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
//
// CXX0X:#define _GNU_SOURCE 1
// CXX0X:#define __DEPRECATED 1
@@ -20,7 +20,7 @@
// CXX0X:#define __private_extern__ extern
//
//
-// RUN: clang-cc -x=c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s
+// RUN: clang-cc -x c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s
//
// CXX98:#define _GNU_SOURCE 1
// CXX98:#define __DEPRECATED 1
@@ -36,7 +36,7 @@
// C99:#define __STRICT_ANSI__ 1
//
//
-// RUN: clang-cc -E -dM -fms-extensions=0 < /dev/null | FileCheck -check-prefix COMMON %s
+// RUN: clang-cc -E -dM < /dev/null | FileCheck -check-prefix COMMON %s
//
// COMMON:#define __CONSTANT_CFSTRINGS__ 1
// COMMON:#define __FINITE_MATH_ONLY__ 0
@@ -56,7 +56,7 @@
// RUN: clang-cc -ffreestanding -E -dM < /dev/null | FileCheck -check-prefix FREESTANDING %s
// FREESTANDING:#define __STDC_HOSTED__ 0
//
-// RUN: clang-cc -x=c++ -std=gnu++98 -E -dM < /dev/null | FileCheck -check-prefix GXX98 %s
+// RUN: clang-cc -x c++ -std=gnu++98 -E -dM < /dev/null | FileCheck -check-prefix GXX98 %s
//
// GXX98:#define _GNU_SOURCE 1
// GXX98:#define __DEPRECATED 1
@@ -80,19 +80,19 @@
// MSEXT:#define __int8 __INT8_TYPE__
//
//
-// RUN: clang-cc -x=objective-c -E -dM < /dev/null | FileCheck -check-prefix OBJC %s
+// RUN: clang-cc -x objective-c -E -dM < /dev/null | FileCheck -check-prefix OBJC %s
//
// OBJC:#define OBJC_NEW_PROPERTIES 1
// OBJC:#define __NEXT_RUNTIME__ 1
// OBJC:#define __OBJC__ 1
//
//
-// RUN: clang-cc -x=objective-c -fobjc-gc -E -dM < /dev/null | FileCheck -check-prefix OBJCGC %s
+// RUN: clang-cc -x objective-c -fobjc-gc -E -dM < /dev/null | FileCheck -check-prefix OBJCGC %s
//
// OBJCGC:#define __OBJC_GC__ 1
//
//
-// RUN: clang-cc -x=objective-c -fobjc-nonfragile-abi -E -dM < /dev/null | FileCheck -check-prefix NONFRAGILE %s
+// RUN: clang-cc -x objective-c -fobjc-nonfragile-abi -E -dM < /dev/null | FileCheck -check-prefix NONFRAGILE %s
//
// NONFRAGILE:#define OBJC_ZEROCOST_EXCEPTIONS 1
// NONFRAGILE:#define __OBJC2__ 1
@@ -108,7 +108,7 @@
// PASCAL:#define __PASCAL_STRINGS__ 1
//
//
-// RUN: clang-cc -fsigned-char -E -dM -fms-extensions=0 < /dev/null | FileCheck -check-prefix SCHAR %s
+// RUN: clang-cc -E -dM < /dev/null | FileCheck -check-prefix SCHAR %s
//
// SCHAR:#define __STDC__ 1
// SCHAR-NOT:#define __UNSIGNED_CHAR__
@@ -155,6 +155,7 @@
// ARM:#define __INT64_TYPE__ long long int
// ARM:#define __INT8_TYPE__ char
// ARM:#define __INTMAX_MAX__ 9223372036854775807LL
+// ARM:#define __INTMAX_TYPE__ long long int
// ARM:#define __INTMAX_WIDTH__ 64
// ARM:#define __INTPTR_TYPE__ long int
// ARM:#define __INTPTR_WIDTH__ 32
@@ -178,15 +179,21 @@
// ARM:#define __NO_INLINE__ 1
// ARM:#define __POINTER_WIDTH__ 32
// ARM:#define __PTRDIFF_TYPE__ int
+// ARM:#define __PTRDIFF_WIDTH__ 32
// ARM:#define __SCHAR_MAX__ 127
// ARM:#define __SHRT_MAX__ 32767
+// ARM:#define __SIG_ATOMIC_WIDTH__ 32
// ARM:#define __SIZE_TYPE__ unsigned int
+// ARM:#define __SIZE_WIDTH__ 32
// ARM:#define __THUMB_INTERWORK__ 1
+// ARM:#define __UINTMAX_TYPE__ long long unsigned int
// ARM:#define __USER_LABEL_PREFIX__ _
// ARM:#define __VFP_FP__ 1
// ARM:#define __WCHAR_MAX__ 2147483647
// ARM:#define __WCHAR_TYPE__ int
+// ARM:#define __WCHAR_WIDTH__ 32
// ARM:#define __WINT_TYPE__ int
+// ARM:#define __WINT_WIDTH__ 32
// ARM:#define __arm 1
// ARM:#define __arm__ 1
//
@@ -233,6 +240,7 @@
// BFIN:#define __INT64_TYPE__ long long int
// BFIN:#define __INT8_TYPE__ char
// BFIN:#define __INTMAX_MAX__ 9223372036854775807LL
+// BFIN:#define __INTMAX_TYPE__ long long int
// BFIN:#define __INTMAX_WIDTH__ 64
// BFIN:#define __INTPTR_TYPE__ long int
// BFIN:#define __INTPTR_WIDTH__ 32
@@ -255,13 +263,19 @@
// BFIN:#define __NO_INLINE__ 1
// BFIN:#define __POINTER_WIDTH__ 32
// BFIN:#define __PTRDIFF_TYPE__ long int
+// BFIN:#define __PTRDIFF_WIDTH__ 32
// BFIN:#define __SCHAR_MAX__ 127
// BFIN:#define __SHRT_MAX__ 32767
+// BFIN:#define __SIG_ATOMIC_WIDTH__ 32
// BFIN:#define __SIZE_TYPE__ long unsigned int
+// BFIN:#define __SIZE_WIDTH__ 32
+// BFIN:#define __UINTMAX_TYPE__ long long unsigned int
// BFIN:#define __USER_LABEL_PREFIX__ _
// BFIN:#define __WCHAR_MAX__ 2147483647
// BFIN:#define __WCHAR_TYPE__ int
+// BFIN:#define __WCHAR_WIDTH__ 32
// BFIN:#define __WINT_TYPE__ int
+// BFIN:#define __WINT_WIDTH__ 32
// BFIN:#define __bfin 1
// BFIN:#define __bfin__ 1
// BFIN:#define bfin 1
@@ -304,6 +318,7 @@
// I386:#define __INT64_TYPE__ long long int
// I386:#define __INT8_TYPE__ char
// I386:#define __INTMAX_MAX__ 9223372036854775807LL
+// I386:#define __INTMAX_TYPE__ long long int
// I386:#define __INTMAX_WIDTH__ 64
// I386:#define __INTPTR_TYPE__ int
// I386:#define __INTPTR_WIDTH__ 32
@@ -328,14 +343,20 @@
// I386:#define __NO_MATH_INLINES 1
// I386:#define __POINTER_WIDTH__ 32
// I386:#define __PTRDIFF_TYPE__ int
+// I386:#define __PTRDIFF_WIDTH__ 32
// I386:#define __REGISTER_PREFIX__
// I386:#define __SCHAR_MAX__ 127
// I386:#define __SHRT_MAX__ 32767
+// I386:#define __SIG_ATOMIC_WIDTH__ 32
// I386:#define __SIZE_TYPE__ unsigned int
+// I386:#define __SIZE_WIDTH__ 32
+// I386:#define __UINTMAX_TYPE__ long long unsigned int
// I386:#define __USER_LABEL_PREFIX__ _
// I386:#define __WCHAR_MAX__ 2147483647
// I386:#define __WCHAR_TYPE__ int
+// I386:#define __WCHAR_WIDTH__ 32
// I386:#define __WINT_TYPE__ int
+// I386:#define __WINT_WIDTH__ 32
// I386:#define __i386 1
// I386:#define __i386__ 1
// I386:#define __nocona 1
@@ -381,6 +402,7 @@
// MSP430:#define __INT32_TYPE__ long int
// MSP430:#define __INT8_TYPE__ char
// MSP430:#define __INTMAX_MAX__ 2147483647L
+// MSP430:#define __INTMAX_TYPE__ long int
// MSP430:#define __INTMAX_WIDTH__ 32
// MSP430:#define __INTPTR_TYPE__ short
// MSP430:#define __INTPTR_WIDTH__ 16
@@ -404,13 +426,19 @@
// MSP430:#define __NO_INLINE__ 1
// MSP430:#define __POINTER_WIDTH__ 16
// MSP430:#define __PTRDIFF_TYPE__ int
+// MSP430:#define __PTRDIFF_WIDTH__ 16
// MSP430:#define __SCHAR_MAX__ 127
// MSP430:#define __SHRT_MAX__ 32767
+// MSP430:#define __SIG_ATOMIC_WIDTH__ 32
// MSP430:#define __SIZE_TYPE__ unsigned int
+// MSP430:#define __SIZE_WIDTH__ 16
+// MSP430:#define __UINTMAX_TYPE__ long unsigned int
// MSP430:#define __USER_LABEL_PREFIX__ _
// MSP430:#define __WCHAR_MAX__ 32767
// MSP430:#define __WCHAR_TYPE__ int
+// MSP430:#define __WCHAR_WIDTH__ 16
// MSP430:#define __WINT_TYPE__ int
+// MSP430:#define __WINT_WIDTH__ 16
// MSP430:#define __clang__ 1
//
// RUN: clang-cc -E -dM -ffreestanding -triple=pic16-none-none < /dev/null | FileCheck -check-prefix PIC16 %s
@@ -451,6 +479,7 @@
// PIC16:#define __INT32_TYPE__ long int
// PIC16:#define __INT8_TYPE__ char
// PIC16:#define __INTMAX_MAX__ 2147483647L
+// PIC16:#define __INTMAX_TYPE__ long int
// PIC16:#define __INTMAX_WIDTH__ 32
// PIC16:#define __INTPTR_TYPE__ short
// PIC16:#define __INTPTR_WIDTH__ 16
@@ -473,13 +502,19 @@
// PIC16:#define __NO_INLINE__ 1
// PIC16:#define __POINTER_WIDTH__ 16
// PIC16:#define __PTRDIFF_TYPE__ int
+// PIC16:#define __PTRDIFF_WIDTH__ 16
// PIC16:#define __SCHAR_MAX__ 127
// PIC16:#define __SHRT_MAX__ 32767
+// PIC16:#define __SIG_ATOMIC_WIDTH__ 32
// PIC16:#define __SIZE_TYPE__ unsigned int
+// PIC16:#define __SIZE_WIDTH__ 16
+// PIC16:#define __UINTMAX_TYPE__ long unsigned int
// PIC16:#define __USER_LABEL_PREFIX__ _
// PIC16:#define __WCHAR_MAX__ 32767
// PIC16:#define __WCHAR_TYPE__ int
+// PIC16:#define __WCHAR_WIDTH__ 16
// PIC16:#define __WINT_TYPE__ int
+// PIC16:#define __WINT_WIDTH__ 16
// PIC16:#define __clang__ 1
// PIC16:#define __llvm__ 1
// PIC16:#define __pic16 1
@@ -489,7 +524,7 @@
// PIC16:#define ram __attribute__((address_space(0)))
// PIC16:#define rom __attribute__((address_space(1)))
//
-// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc64-none-none -fsigned-char=0 < /dev/null | FileCheck -check-prefix PPC64 %s
+// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc64-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix PPC64 %s
//
// PPC64:#define _ARCH_PPC 1
// PPC64:#define _ARCH_PPC64 1
@@ -533,6 +568,7 @@
// PPC64:#define __INT64_TYPE__ long int
// PPC64:#define __INT8_TYPE__ char
// PPC64:#define __INTMAX_MAX__ 9223372036854775807L
+// PPC64:#define __INTMAX_TYPE__ long int
// PPC64:#define __INTMAX_WIDTH__ 64
// PPC64:#define __INTPTR_TYPE__ long int
// PPC64:#define __INTPTR_WIDTH__ 64
@@ -559,18 +595,24 @@
// PPC64:#define __POINTER_WIDTH__ 64
// PPC64:#define __POWERPC__ 1
// PPC64:#define __PTRDIFF_TYPE__ long int
+// PPC64:#define __PTRDIFF_WIDTH__ 64
// PPC64:#define __REGISTER_PREFIX__
// PPC64:#define __SCHAR_MAX__ 127
// PPC64:#define __SHRT_MAX__ 32767
+// PPC64:#define __SIG_ATOMIC_WIDTH__ 32
// PPC64:#define __SIZE_TYPE__ long unsigned int
+// PPC64:#define __SIZE_WIDTH__ 64
+// PPC64:#define __UINTMAX_TYPE__ long unsigned int
// PPC64:#define __USER_LABEL_PREFIX__ _
// PPC64:#define __WCHAR_MAX__ 2147483647
// PPC64:#define __WCHAR_TYPE__ int
+// PPC64:#define __WCHAR_WIDTH__ 32
// PPC64:#define __WINT_TYPE__ int
+// PPC64:#define __WINT_WIDTH__ 32
// PPC64:#define __ppc64__ 1
// PPC64:#define __ppc__ 1
//
-// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc-none-none -fsigned-char=0 < /dev/null | FileCheck -check-prefix PPC %s
+// RUN: clang-cc -E -dM -ffreestanding -triple=powerpc-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix PPC %s
//
// PPC:#define _ARCH_PPC 1
// PPC:#define _BIG_ENDIAN 1
@@ -612,6 +654,7 @@
// PPC:#define __INT64_TYPE__ long long int
// PPC:#define __INT8_TYPE__ char
// PPC:#define __INTMAX_MAX__ 9223372036854775807LL
+// PPC:#define __INTMAX_TYPE__ long long int
// PPC:#define __INTMAX_WIDTH__ 64
// PPC:#define __INTPTR_TYPE__ long int
// PPC:#define __INTPTR_WIDTH__ 32
@@ -637,17 +680,23 @@
// PPC:#define __POINTER_WIDTH__ 32
// PPC:#define __POWERPC__ 1
// PPC:#define __PTRDIFF_TYPE__ long int
+// PPC:#define __PTRDIFF_WIDTH__ 32
// PPC:#define __REGISTER_PREFIX__
// PPC:#define __SCHAR_MAX__ 127
// PPC:#define __SHRT_MAX__ 32767
+// PPC:#define __SIG_ATOMIC_WIDTH__ 32
// PPC:#define __SIZE_TYPE__ long unsigned int
+// PPC:#define __SIZE_WIDTH__ 32
+// PPC:#define __UINTMAX_TYPE__ long long unsigned int
// PPC:#define __USER_LABEL_PREFIX__ _
// PPC:#define __WCHAR_MAX__ 2147483647
// PPC:#define __WCHAR_TYPE__ int
+// PPC:#define __WCHAR_WIDTH__ 32
// PPC:#define __WINT_TYPE__ int
+// PPC:#define __WINT_WIDTH__ 32
// PPC:#define __ppc__ 1
//
-// RUN: clang-cc -E -dM -ffreestanding -triple=s390x-none-none -fsigned-char=0 < /dev/null | FileCheck -check-prefix S390X %s
+// RUN: clang-cc -E -dM -ffreestanding -triple=s390x-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix S390X %s
//
// S390X:#define __CHAR_BIT__ 8
// S390X:#define __CHAR_UNSIGNED__ 1
@@ -686,6 +735,7 @@
// S390X:#define __INT64_TYPE__ long int
// S390X:#define __INT8_TYPE__ char
// S390X:#define __INTMAX_MAX__ 9223372036854775807LL
+// S390X:#define __INTMAX_TYPE__ long long int
// S390X:#define __INTMAX_WIDTH__ 64
// S390X:#define __INTPTR_TYPE__ long int
// S390X:#define __INTPTR_WIDTH__ 64
@@ -708,13 +758,19 @@
// S390X:#define __NO_INLINE__ 1
// S390X:#define __POINTER_WIDTH__ 64
// S390X:#define __PTRDIFF_TYPE__ long int
+// S390X:#define __PTRDIFF_WIDTH__ 64
// S390X:#define __SCHAR_MAX__ 127
// S390X:#define __SHRT_MAX__ 32767
+// S390X:#define __SIG_ATOMIC_WIDTH__ 32
// S390X:#define __SIZE_TYPE__ long unsigned int
+// S390X:#define __SIZE_WIDTH__ 64
+// S390X:#define __UINTMAX_TYPE__ long long unsigned int
// S390X:#define __USER_LABEL_PREFIX__ _
// S390X:#define __WCHAR_MAX__ 2147483647
// S390X:#define __WCHAR_TYPE__ int
+// S390X:#define __WCHAR_WIDTH__ 32
// S390X:#define __WINT_TYPE__ int
+// S390X:#define __WINT_WIDTH__ 32
// S390X:#define __s390__ 1
// S390X:#define __s390x__ 1
//
@@ -756,6 +812,7 @@
// SPARC:#define __INT64_TYPE__ long long int
// SPARC:#define __INT8_TYPE__ char
// SPARC:#define __INTMAX_MAX__ 9223372036854775807LL
+// SPARC:#define __INTMAX_TYPE__ long long int
// SPARC:#define __INTMAX_WIDTH__ 64
// SPARC:#define __INTPTR_TYPE__ long int
// SPARC:#define __INTPTR_WIDTH__ 32
@@ -778,15 +835,21 @@
// SPARC:#define __NO_INLINE__ 1
// SPARC:#define __POINTER_WIDTH__ 32
// SPARC:#define __PTRDIFF_TYPE__ long int
+// SPARC:#define __PTRDIFF_WIDTH__ 32
// SPARC:#define __REGISTER_PREFIX__
// SPARC:#define __SCHAR_MAX__ 127
// SPARC:#define __SHRT_MAX__ 32767
+// SPARC:#define __SIG_ATOMIC_WIDTH__ 32
// SPARC:#define __SIZE_TYPE__ long unsigned int
+// SPARC:#define __SIZE_WIDTH__ 32
+// SPARC:#define __UINTMAX_TYPE__ long long unsigned int
// SPARC:#define __USER_LABEL_PREFIX__ _
// SPARC:#define __VERSION__ "4.2.1 Compatible Clang Compiler"
// SPARC:#define __WCHAR_MAX__ 2147483647
// SPARC:#define __WCHAR_TYPE__ int
+// SPARC:#define __WCHAR_WIDTH__ 32
// SPARC:#define __WINT_TYPE__ int
+// SPARC:#define __WINT_WIDTH__ 32
// SPARC:#define __sparc 1
// SPARC:#define __sparc__ 1
// SPARC:#define __sparcv8 1
@@ -828,6 +891,7 @@
// TCE:#define __INT32_TYPE__ int
// TCE:#define __INT8_TYPE__ char
// TCE:#define __INTMAX_MAX__ 2147483647L
+// TCE:#define __INTMAX_TYPE__ long int
// TCE:#define __INTMAX_WIDTH__ 32
// TCE:#define __INTPTR_TYPE__ int
// TCE:#define __INTPTR_WIDTH__ 32
@@ -850,15 +914,21 @@
// TCE:#define __NO_INLINE__ 1
// TCE:#define __POINTER_WIDTH__ 32
// TCE:#define __PTRDIFF_TYPE__ int
+// TCE:#define __PTRDIFF_WIDTH__ 32
// TCE:#define __SCHAR_MAX__ 127
// TCE:#define __SHRT_MAX__ 32767
+// TCE:#define __SIG_ATOMIC_WIDTH__ 32
// TCE:#define __SIZE_TYPE__ unsigned int
+// TCE:#define __SIZE_WIDTH__ 32
// TCE:#define __TCE_V1__ 1
// TCE:#define __TCE__ 1
+// TCE:#define __UINTMAX_TYPE__ long unsigned int
// TCE:#define __USER_LABEL_PREFIX__ _
// TCE:#define __WCHAR_MAX__ 2147483647
// TCE:#define __WCHAR_TYPE__ int
+// TCE:#define __WCHAR_WIDTH__ 32
// TCE:#define __WINT_TYPE__ int
+// TCE:#define __WINT_WIDTH__ 32
// TCE:#define __tce 1
// TCE:#define __tce__ 1
// TCE:#define tce 1
@@ -902,6 +972,7 @@
// X86_64:#define __INT64_TYPE__ long int
// X86_64:#define __INT8_TYPE__ char
// X86_64:#define __INTMAX_MAX__ 9223372036854775807L
+// X86_64:#define __INTMAX_TYPE__ long int
// X86_64:#define __INTMAX_WIDTH__ 64
// X86_64:#define __INTPTR_TYPE__ long int
// X86_64:#define __INTPTR_WIDTH__ 64
@@ -928,18 +999,24 @@
// X86_64:#define __NO_MATH_INLINES 1
// X86_64:#define __POINTER_WIDTH__ 64
// X86_64:#define __PTRDIFF_TYPE__ long int
+// X86_64:#define __PTRDIFF_WIDTH__ 64
// X86_64:#define __REGISTER_PREFIX__
// X86_64:#define __SCHAR_MAX__ 127
// X86_64:#define __SHRT_MAX__ 32767
+// X86_64:#define __SIG_ATOMIC_WIDTH__ 32
// X86_64:#define __SIZE_TYPE__ long unsigned int
+// X86_64:#define __SIZE_WIDTH__ 64
// X86_64:#define __SSE2_MATH__ 1
// X86_64:#define __SSE2__ 1
// X86_64:#define __SSE_MATH__ 1
// X86_64:#define __SSE__ 1
+// X86_64:#define __UINTMAX_TYPE__ long unsigned int
// X86_64:#define __USER_LABEL_PREFIX__ _
// X86_64:#define __WCHAR_MAX__ 2147483647
// X86_64:#define __WCHAR_TYPE__ int
+// X86_64:#define __WCHAR_WIDTH__ 32
// X86_64:#define __WINT_TYPE__ int
+// X86_64:#define __WINT_WIDTH__ 32
// X86_64:#define __amd64 1
// X86_64:#define __amd64__ 1
// X86_64:#define __nocona 1
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
index b79b1d98ea02..33dd9bb3fe16 100644
--- a/test/Preprocessor/line-directive.c
+++ b/test/Preprocessor/line-directive.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify -pedantic -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
// RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:92:2: error: #error ABC'
// RUN: clang-cc -E %s 2>&1 | grep 'blonk.c:93:2: error: #error DEF'
diff --git a/test/Preprocessor/macro_paste_bcpl_comment.c b/test/Preprocessor/macro_paste_bcpl_comment.c
index 0637a8721739..8bbee5dc2dd9 100644
--- a/test/Preprocessor/macro_paste_bcpl_comment.c
+++ b/test/Preprocessor/macro_paste_bcpl_comment.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -Eonly -fms-extensions=0 2>&1 | grep error
+// RUN: clang-cc %s -Eonly 2>&1 | grep error
#define COMM1 / ## /
COMM1
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index 9c98e291664c..930474645f17 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -403,8 +403,8 @@
//
// MSP430:SIG_ATOMIC_MIN_ (-2147483647L -1)
// MSP430:SIG_ATOMIC_MAX_ 2147483647L
-// MSP430:WINT_MIN_ (-2147483647L -1)
-// MSP430:WINT_MAX_ 2147483647L
+// MSP430:WINT_MIN_ (-32767 -1)
+// MSP430:WINT_MAX_ 32767
//
// MSP430:WCHAR_MAX_ 32767
// MSP430:WCHAR_MIN_ (-32767 -1)
@@ -503,8 +503,8 @@
//
// PIC16:SIG_ATOMIC_MIN_ (-2147483647L -1)
// PIC16:SIG_ATOMIC_MAX_ 2147483647L
-// PIC16:WINT_MIN_ (-2147483647L -1)
-// PIC16:WINT_MAX_ 2147483647L
+// PIC16:WINT_MIN_ (-32767 -1)
+// PIC16:WINT_MAX_ 32767
//
// PIC16:WCHAR_MAX_ 32767
// PIC16:WCHAR_MIN_ (-32767 -1)
@@ -1158,6 +1158,35 @@
// X86_64:INTMAX_C_(0) 0L
// X86_64:UINTMAX_C_(0) 0UL
//
+//
+// stdint.h forms several macro definitions by pasting together identifiers
+// to form names (eg. int32_t is formed from int ## 32 ## _t). The following
+// case tests that these joining operations are performed correctly even if
+// the identifiers used in the operations (int, uint, _t, INT, UINT, _MIN,
+// _MAX, and _C(v)) are themselves macros.
+//
+// RUN: clang-cc -E -ffreestanding -Dint=a -Duint=b -D_t=c -DINT=d -DUINT=e -D_MIN=f -D_MAX=g '-D_C(v)=h' -triple=i386-none-none %s | FileCheck -check-prefix JOIN %s
+// JOIN:typedef int32_t intptr_t;
+// JOIN:typedef uint32_t uintptr_t;
+// JOIN:typedef int64_t intmax_t;
+// JOIN:typedef uint64_t uintmax_t;
+// JOIN:INTPTR_MIN_ (-2147483647 -1)
+// JOIN:INTPTR_MAX_ 2147483647
+// JOIN:UINTPTR_MAX_ 4294967295U
+// JOIN:PTRDIFF_MIN_ (-2147483647 -1)
+// JOIN:PTRDIFF_MAX_ 2147483647
+// JOIN:SIZE_MAX_ 4294967295U
+// JOIN:INTMAX_MIN_ (-9223372036854775807LL -1)
+// JOIN:INTMAX_MAX_ 9223372036854775807LL
+// JOIN:UINTMAX_MAX_ 18446744073709551615ULL
+// JOIN:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// JOIN:SIG_ATOMIC_MAX_ 2147483647
+// JOIN:WINT_MIN_ (-2147483647 -1)
+// JOIN:WINT_MAX_ 2147483647
+// JOIN:WCHAR_MAX_ 2147483647
+// JOIN:WCHAR_MIN_ (-2147483647 -1)
+// JOIN:INTMAX_C_(0) 0LL
+// JOIN:UINTMAX_C_(0) 0ULL
#include <stdint.h>
diff --git a/test/Rewriter/id-test-3.m b/test/Rewriter/id-test-3.m
index 7e4cc51d7357..aecabe6f30ab 100644
--- a/test/Rewriter/id-test-3.m
+++ b/test/Rewriter/id-test-3.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol P
- (id<P>) Meth: (id<P>) Arg;
diff --git a/test/Rewriter/ivar-encoding-1.m b/test/Rewriter/ivar-encoding-1.m
index 759146175d44..10665b838ff7 100644
--- a/test/Rewriter/ivar-encoding-1.m
+++ b/test/Rewriter/ivar-encoding-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface Intf
{
diff --git a/test/Rewriter/ivar-encoding-2.m b/test/Rewriter/ivar-encoding-2.m
index 86cc9b6a88f3..6cd0e2729874 100644
--- a/test/Rewriter/ivar-encoding-2.m
+++ b/test/Rewriter/ivar-encoding-2.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@implementation Intf
{
diff --git a/test/Rewriter/metadata-test-1.m b/test/Rewriter/metadata-test-1.m
index 40eded121ece..54413f2650f7 100644
--- a/test/Rewriter/metadata-test-1.m
+++ b/test/Rewriter/metadata-test-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface Intf
@end
diff --git a/test/Rewriter/metadata-test-2.m b/test/Rewriter/metadata-test-2.m
index ab838f18bb93..af26545fa69d 100644
--- a/test/Rewriter/metadata-test-2.m
+++ b/test/Rewriter/metadata-test-2.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
typedef struct _NSPoint {
float x;
diff --git a/test/Rewriter/method-encoding-1.m b/test/Rewriter/method-encoding-1.m
index 05df60291e02..4726061d1a61 100644
--- a/test/Rewriter/method-encoding-1.m
+++ b/test/Rewriter/method-encoding-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol P1
- (void) MyProtoMeth : (int **) arg1 : (void*) arg2;
diff --git a/test/Rewriter/objc-encoding-bug-1.m b/test/Rewriter/objc-encoding-bug-1.m
index 684a0d2ded09..d2099883b1de 100644
--- a/test/Rewriter/objc-encoding-bug-1.m
+++ b/test/Rewriter/objc-encoding-bug-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
typedef struct NSMethodFrameArgInfo {
struct NSMethodFrameArgInfo *subInfo;
diff --git a/test/Rewriter/objc-string-concat-1.m b/test/Rewriter/objc-string-concat-1.m
index e8f8a88f2056..b1f95e052cb8 100644
--- a/test/Rewriter/objc-string-concat-1.m
+++ b/test/Rewriter/objc-string-concat-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@class NSString;
diff --git a/test/Rewriter/objc-synchronized-1.m b/test/Rewriter/objc-synchronized-1.m
index e3c41165db22..df24518d65e4 100644
--- a/test/Rewriter/objc-synchronized-1.m
+++ b/test/Rewriter/objc-synchronized-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
id SYNCH_EXPR();
void SYNCH_BODY();
diff --git a/test/Rewriter/protocol-rewrite-1.m b/test/Rewriter/protocol-rewrite-1.m
index 263a97d85d28..3f2bb6f190cd 100644
--- a/test/Rewriter/protocol-rewrite-1.m
+++ b/test/Rewriter/protocol-rewrite-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
typedef struct MyWidget {
int a;
diff --git a/test/Rewriter/rewrite-api-bug.m b/test/Rewriter/rewrite-api-bug.m
index ba0511b64650..e2dfe38afe44 100644
--- a/test/Rewriter/rewrite-api-bug.m
+++ b/test/Rewriter/rewrite-api-bug.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface MyDerived
- (void) instanceMethod;
diff --git a/test/Rewriter/rewrite-foreach-1.m b/test/Rewriter/rewrite-foreach-1.m
index eef33f88c9ca..686d73fca5b4 100644
--- a/test/Rewriter/rewrite-foreach-1.m
+++ b/test/Rewriter/rewrite-foreach-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-2.m b/test/Rewriter/rewrite-foreach-2.m
index 12f0e834df42..4de64bc87ded 100644
--- a/test/Rewriter/rewrite-foreach-2.m
+++ b/test/Rewriter/rewrite-foreach-2.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-3.m b/test/Rewriter/rewrite-foreach-3.m
index 3aa0d95b44bb..0de31021d820 100644
--- a/test/Rewriter/rewrite-foreach-3.m
+++ b/test/Rewriter/rewrite-foreach-3.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol P @end
diff --git a/test/Rewriter/rewrite-foreach-4.m b/test/Rewriter/rewrite-foreach-4.m
index 5c831ea18b20..70f3eb874497 100644
--- a/test/Rewriter/rewrite-foreach-4.m
+++ b/test/Rewriter/rewrite-foreach-4.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface MyList
- (id) allKeys;
diff --git a/test/Rewriter/rewrite-foreach-5.m b/test/Rewriter/rewrite-foreach-5.m
index d03f6ce84df6..14d18d130d89 100644
--- a/test/Rewriter/rewrite-foreach-5.m
+++ b/test/Rewriter/rewrite-foreach-5.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface MyList
- (id) allKeys;
diff --git a/test/Rewriter/rewrite-foreach-6.m b/test/Rewriter/rewrite-foreach-6.m
index c6043bb98eb4..66d411001e13 100644
--- a/test/Rewriter/rewrite-foreach-6.m
+++ b/test/Rewriter/rewrite-foreach-6.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -rewrite-objc -o=-
+// RUN: clang-cc %s -rewrite-objc -o -
// rdar://5716356
// FIXME: Should be able to pipe into clang, but code is not
// yet correct for other reasons: rdar://5716940
diff --git a/test/Rewriter/rewrite-nest.m b/test/Rewriter/rewrite-nest.m
index 7a1690a3630b..e35baf6ce852 100644
--- a/test/Rewriter/rewrite-nest.m
+++ b/test/Rewriter/rewrite-nest.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface NSMapTable @end
@interface NSEnumerator @end
diff --git a/test/Rewriter/rewrite-protocol-type-1.m b/test/Rewriter/rewrite-protocol-type-1.m
index 48dc02971ca9..63b605d7ed61 100644
--- a/test/Rewriter/rewrite-protocol-type-1.m
+++ b/test/Rewriter/rewrite-protocol-type-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol MyProto1
@end
diff --git a/test/Rewriter/rewrite-try-catch.m b/test/Rewriter/rewrite-try-catch.m
index 8c6d08f2e01d..f69e8ef35496 100644
--- a/test/Rewriter/rewrite-try-catch.m
+++ b/test/Rewriter/rewrite-try-catch.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface Foo @end
@interface GARF @end
diff --git a/test/Rewriter/static-type-protocol-1.m b/test/Rewriter/static-type-protocol-1.m
index 0985a9d77554..986627d37a89 100644
--- a/test/Rewriter/static-type-protocol-1.m
+++ b/test/Rewriter/static-type-protocol-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@protocol Proto
- (void) ProtoDidget;
diff --git a/test/Rewriter/undecl-objc-h.m b/test/Rewriter/undecl-objc-h.m
index b09765163ec0..12f38112c9cd 100644
--- a/test/Rewriter/undecl-objc-h.m
+++ b/test/Rewriter/undecl-objc-h.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
typedef struct S {
int * pint;
diff --git a/test/Rewriter/undeclared-method-1.m b/test/Rewriter/undeclared-method-1.m
index 795fd61b4afa..499d9114e1a7 100644
--- a/test/Rewriter/undeclared-method-1.m
+++ b/test/Rewriter/undeclared-method-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface Derived @end
diff --git a/test/Rewriter/undef-field-reference-1.m b/test/Rewriter/undef-field-reference-1.m
index 43bc2ad8bfa5..17f448dcae20 100644
--- a/test/Rewriter/undef-field-reference-1.m
+++ b/test/Rewriter/undef-field-reference-1.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
@interface MyDerived
{
diff --git a/test/Rewriter/va-method.m b/test/Rewriter/va-method.m
index 3bee599435e7..b4fdac553ded 100644
--- a/test/Rewriter/va-method.m
+++ b/test/Rewriter/va-method.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -rewrite-objc %s -o=-
+// RUN: clang-cc -rewrite-objc %s -o -
#include <stdarg.h>
diff --git a/test/Sema/align-arm-apcs.c b/test/Sema/align-arm-apcs.c
index 924ba9034d8b..9689906488b1 100644
--- a/test/Sema/align-arm-apcs.c
+++ b/test/Sema/align-arm-apcs.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple arm-unknown-unknown -target-abi=apcs-gnu -fsyntax-only -verify %s
+// RUN: clang-cc -triple arm-unknown-unknown -target-abi apcs-gnu -fsyntax-only -verify %s
struct s0 { double f0; int f1; };
char chk0[__alignof__(struct s0) == 4 ? 1 : -1];
diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c
index 6185186903b0..2a33e1e56f55 100644
--- a/test/Sema/altivec-init.c
+++ b/test/Sema/altivec-init.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -faltivec -verify -pedantic -fsyntax-only -fblocks=0
+// RUN: clang-cc %s -faltivec -verify -pedantic -fsyntax-only
typedef int v4 __attribute((vector_size(16)));
typedef short v8 __attribute((vector_size(16)));
diff --git a/test/Sema/carbon.c b/test/Sema/carbon.c
index 5eda4385ac49..8292ba8a506b 100644
--- a/test/Sema/carbon.c
+++ b/test/Sema/carbon.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc -mcpu=pentium4 %s -print-stats
+// RUN: clang-cc -mcpu pentium4 %s -print-stats
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
diff --git a/test/Sema/cast.c b/test/Sema/cast.c
index ec19626d28e0..d2e3e0c7e3a1 100644
--- a/test/Sema/cast.c
+++ b/test/Sema/cast.c
@@ -12,3 +12,7 @@ void bar() {
a = (char*)b; // expected-error {{cannot be cast to a pointer type}}
}
+long bar1(long *next) {
+ return (long)(*next)++;
+}
+
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index 2bcc0f8a2ca0..299b0a267dc2 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -1,4 +1,4 @@
-// RUN: clang-cc %s -verify -pedantic -fsyntax-only -fblocks=0
+// RUN: clang-cc %s -verify -pedantic -fsyntax-only
// PR1966
_Complex double test1() {
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index 122947e7ce5c..3ee371202f91 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-
void f (int z) {
while (z) {
default: z--; // expected-error {{statement not in switch}}
@@ -75,3 +74,14 @@ void test6() {
break;
}
}
+
+// PR5606
+int f0(int var) {
+ switch (va) { // expected-error{{use of undeclared identifier 'va'}}
+ case 1:
+ break;
+ case 2:
+ return 1;
+ }
+ return 2;
+}
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
index e201c7e49144..ed6649a31d98 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -6,7 +6,9 @@ typedef __WCHAR_TYPE__ wchar_t;
#if defined(_WIN32) || defined(_M_IX86) || defined(__CYGWIN__) \
|| defined(_M_X64) || defined(SHORT_WCHAR)
#define WCHAR_T_TYPE unsigned short
-#else
+#elif defined(__sun) || defined(__AuroraUX__)
+ #define WCHAR_T_TYPE long
+#else /* Solaris or AuroraUX. */
#define WCHAR_T_TYPE int
#endif
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
new file mode 100644
index 000000000000..27d98ab6491e
--- /dev/null
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -0,0 +1,9 @@
+// RUN: clang-cc -std=c++0x -fsyntax-only -verify %s
+
+struct s0; // expected-note {{forward declaration}}
+char ar[sizeof(s0&)]; // expected-error {{invalid application of 'sizeof' to an incomplete type}}
+void test() {
+ char &r = ar[0];
+ static_assert(alignof(r) == 1, "bad alignment");
+ static_assert(sizeof(r) == 1, "bad size");
+}
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
new file mode 100644
index 000000000000..da52d338cfbc
--- /dev/null
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+int final_fail [[final]]; //expected-error {{'final' attribute only applies to virtual method or class types}}
+
+struct [[final]] final_base { }; // expected-note {{struct final_base declared here}}
+struct final_child : final_base { }; // expected-error {{derivation from 'final' struct final_base}}
+
+struct final_member { virtual void quux [[final]] (); }; // expected-note {{overridden virtual function is here}}
+struct final_override : final_member { virtual void quux (); }; // expected-error {{declaration of 'quux' overrides a 'final' function}}
+
+int align_illegal [[align(3)]]; //expected-error {{requested alignment is not a power of 2}}
+char align_big [[align(int)]];
+int align_small [[align(1)]];
+int align_multiple [[align(1), align(8), align(1)]];
+
+struct align_member {
+ int member [[align(8)]];
+};
+
+static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
+static_assert(alignof(align_small) == alignof(int), "j's alignment is wrong");
+static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
+static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
+static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
+
+int bc_fail [[base_check]]; // expected-error {{'base_check' attribute only applies to class types}}
+int hiding_fail [[hiding]]; // expected-error {{'hiding' attribute only applies to member types}}
+int override_fail [[override]]; // expected-error {{'override' attribute only applies to virtual method types}}
+
+struct base {
+ virtual void function();
+ virtual void other_function();
+};
+
+struct [[base_check, base_check]] bc : base { // expected-error {{'base_check' attribute cannot be repeated}}
+}; \ No newline at end of file
diff --git a/test/SemaCXX/attr-sentinel.cpp b/test/SemaCXX/attr-sentinel.cpp
new file mode 100644
index 000000000000..0293a5dce00c
--- /dev/null
+++ b/test/SemaCXX/attr-sentinel.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+void f(int, ...) __attribute__((sentinel));
+
+void g() {
+ f(1, 2, __null);
+}
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
index 56f41bfbdb93..b5971723a70d 100644
--- a/test/SemaCXX/class-layout.cpp
+++ b/test/SemaCXX/class-layout.cpp
@@ -47,3 +47,20 @@ struct G { G(); };
struct H : G { };
SA(6, sizeof(H) == 1);
+
+// PR5580
+namespace PR5580 {
+
+class A { bool iv0 : 1; };
+SA(7, sizeof(A) == 1);
+
+class B : A { bool iv0 : 1; };
+SA(8, sizeof(B) == 2);
+
+struct C { bool iv0 : 1; };
+SA(9, sizeof(C) == 1);
+
+struct D : C { bool iv0 : 1; };
+SA(10, sizeof(D) == 2);
+
+}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index d2a8114f7b06..2637f320207f 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -110,3 +110,11 @@ struct C4 {
void f(); // expected-note{{previous declaration is here}}
int f; // expected-error{{duplicate member 'f'}}
};
+
+// PR5415 - don't hang!
+struct S
+{
+ void f(); // expected-note 1 {{previous declaration}}
+ void S::f() {} // expected-error {{class member cannot be redeclared}} expected-note {{previous declaration}} expected-note {{previous definition}}
+ void f() {} // expected-error {{class member cannot be redeclared}} expected-error {{redefinition}}
+};
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index 7c9cee59da6f..b2645d4fe0fa 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -33,3 +33,11 @@ void test() {
for (; int x=0; ) { int x; } // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
switch (int x=0) { default: int x; } // expected-error {{redefinition of 'x'}} expected-note {{previous definition is here}}
}
+
+int* get_int_ptr();
+
+void test2() {
+ float *ip;
+ if (int *ip = ip) {
+ }
+}
diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp
index 59b793e3f28c..3f347b49022e 100644
--- a/test/SemaCXX/converting-constructor.cpp
+++ b/test/SemaCXX/converting-constructor.cpp
@@ -38,3 +38,10 @@ void explicit_constructor(short s) {
FromShortExplicitly fse1(s);
FromShortExplicitly fse2 = s; // expected-error{{error: cannot initialize 'fse2' with an lvalue of type 'short'}}
}
+
+// PR5519
+struct X1 { X1(const char&); };
+void x1(X1);
+void y1() {
+ x1(1);
+}
diff --git a/test/SemaCXX/implicit-int.cpp b/test/SemaCXX/implicit-int.cpp
index 723030516dee..6fa8dd3463d3 100644
--- a/test/SemaCXX/implicit-int.cpp
+++ b/test/SemaCXX/implicit-int.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -verify %s
x; // expected-error{{C++ requires a type specifier for all declarations}}
diff --git a/test/SemaCXX/member-pointers-2.cpp b/test/SemaCXX/member-pointers-2.cpp
new file mode 100644
index 000000000000..fea1d74b0255
--- /dev/null
+++ b/test/SemaCXX/member-pointers-2.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+// Tests that Sema properly creates member-access expressions for
+// these instead of bare FieldDecls.
+
+struct Foo {
+ int myvalue;
+
+ // We have to override these to get something with an lvalue result.
+ int &operator++(int);
+ int &operator--(int);
+};
+
+struct Test0 {
+ Foo memfoo;
+ int memint;
+ int memarr[10];
+ Test0 *memptr;
+ struct MemClass { int a; } memstruct;
+ int &memfun();
+
+ void test() {
+ int *p;
+ p = &Test0::memfoo++;
+ p = &Test0::memfoo--;
+ p = &Test0::memarr[1];
+ p = &Test0::memptr->memint;
+ p = &Test0::memstruct.a;
+ p = &Test0::memfun();
+ }
+};
+
+void test0() {
+ Test0 mytest;
+ mytest.test();
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 721758f4cae0..83c72417d590 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -std=c++98 -verify -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s
namespace A {
struct C {
static int cx;
@@ -87,7 +87,6 @@ void f3() {
N::x = 0; // expected-error {{expected a class or namespace}}
{ int A; A::ax = 0; }
{ typedef int A; A::ax = 0; } // expected-error{{expected a class or namespace}}
- { int A(); A::ax = 0; }
{ typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}}
{ typedef A::C A; A::cx = 0; }
}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index ededfc0900de..f2fe0a78e388 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -190,3 +190,15 @@ class X9 {
void f(X9 *x9) {
delete x9; // expected-error {{no suitable member 'operator delete' in 'X9'}}
}
+
+struct X10 {
+ virtual ~X10();
+};
+
+struct X11 : X10 { // expected-error {{no suitable member 'operator delete' in 'X11'}}
+ void operator delete(void*, int); // expected-note {{'operator delete' declared here}}
+};
+
+void f() {
+ X11 x11; // expected-note {{implicit default destructor for 'struct X11' first required here}}
+}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index 0850c44a36f9..8f69def9fd4f 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -38,3 +38,12 @@ typedef int Integer;
void destroy_without_call(int *ip) {
ip->~Integer; // expected-error{{called immediately}}
}
+
+// PR5530
+namespace N1 {
+ class X0 { };
+}
+
+void test_X0(N1::X0 &x0) {
+ x0.~X0();
+}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index ecb6aa9b3592..02e69996c772 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -48,7 +48,7 @@ namespace C
a.A::sub::x();
a.A::B::base::x();
- a.bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}}
+ a.bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''A::sub''}}
a->foo();
a->member::foo();
@@ -69,7 +69,7 @@ namespace C
a->A::sub::x();
a->A::B::base::x();
- a->bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}}
+ a->bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''A::sub''}}
(*a)->foo();
(*a)->member::foo();
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index be960a3af8b5..bfe8887bd3d3 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -1,5 +1,7 @@
// RUN: clang-cc -fsyntax-only -verify %s
+#include <stdint.h>
+
enum test { testval = 1 };
struct structure { int m; };
typedef void (*fnptr)();
@@ -20,11 +22,11 @@ void self_conversion()
void integral_conversion()
{
void *vp = reinterpret_cast<void*>(testval);
- long l = reinterpret_cast<long>(vp);
- (void)reinterpret_cast<float*>(l);
- fnptr fnp = reinterpret_cast<fnptr>(l);
+ intptr_t i = reinterpret_cast<intptr_t>(vp);
+ (void)reinterpret_cast<float*>(i);
+ fnptr fnp = reinterpret_cast<fnptr>(i);
(void)reinterpret_cast<char>(fnp); // expected-error {{cast from pointer to smaller type 'char' loses information}}
- (void)reinterpret_cast<long>(fnp);
+ (void)reinterpret_cast<intptr_t>(fnp);
}
void pointer_conversion()
diff --git a/test/SemaCXX/switch-0x.cpp b/test/SemaCXX/switch-0x.cpp
new file mode 100644
index 000000000000..c1f6bd9d19a8
--- /dev/null
+++ b/test/SemaCXX/switch-0x.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+// PR5518
+struct A {
+ explicit operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) { // expected-error{{explicit conversion to}}
+ }
+}
diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp
index b22adb749576..003d5b8b9c08 100644
--- a/test/SemaCXX/switch.cpp
+++ b/test/SemaCXX/switch.cpp
@@ -13,3 +13,30 @@ void test() {
break;
}
}
+
+// PR5518
+struct A {
+ operator int(); // expected-note{{conversion to integral type}}
+};
+
+void x() {
+ switch(A()) {
+ }
+}
+
+enum E { e1, e2 };
+struct B : A {
+ operator E() const; // expected-note{{conversion to enumeration type}}
+};
+
+void x2() {
+ switch (B()) { // expected-error{{multiple conversions}}
+ }
+}
+
+struct C; // expected-note{{forward declaration}}
+
+void x3(C &c) {
+ switch (c) { // expected-error{{incomplete class type}}
+ }
+}
diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp
index 85944a661d41..e38f47436d1c 100644
--- a/test/SemaCXX/typedef-redecl.cpp
+++ b/test/SemaCXX/typedef-redecl.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -verify %s
typedef int INT;
typedef INT REALLY_INT; // expected-note {{previous definition is here}}
typedef REALLY_INT REALLY_REALLY_INT;
diff --git a/test/SemaCXX/using-directive.cpp b/test/SemaCXX/using-directive.cpp
index 3b67c7a5b61f..51f347dc7a73 100644
--- a/test/SemaCXX/using-directive.cpp
+++ b/test/SemaCXX/using-directive.cpp
@@ -102,3 +102,13 @@ namespace FuncHidesTagAmbiguity {
(void)X(); // expected-error{{reference to 'X' is ambiguous}}
}
}
+
+// PR5479
+namespace Aliased {
+ void inAliased();
+}
+namespace Alias = Aliased;
+using namespace Alias;
+void testAlias() {
+ inAliased();
+}
diff --git a/test/SemaObjC/cocoa.m b/test/SemaObjC/cocoa.m
index b73b3c4ccd33..7dab9f55e734 100644
--- a/test/SemaObjC/cocoa.m
+++ b/test/SemaObjC/cocoa.m
@@ -1,4 +1,4 @@
-// RUN: clang-cc -mcpu=pentium4 %s -print-stats
+// RUN: clang-cc -mcpu pentium4 %s -print-stats
#ifdef __APPLE__
#include <Cocoa/Cocoa.h>
#endif
diff --git a/test/SemaObjC/foreach.m b/test/SemaObjC/foreach.m
index f136adfa363b..2b62b1744ce2 100644
--- a/test/SemaObjC/foreach.m
+++ b/test/SemaObjC/foreach.m
@@ -1,4 +1,4 @@
-/* RUN: clang-cc -fsyntax-only -verify -std=c89 -pedantic %s
+/* RUN: clang-cc -Wall -fsyntax-only -verify -std=c89 -pedantic %s
*/
@class NSArray;
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
index 85ede5786d5b..707e1893bf8e 100644
--- a/test/SemaObjC/ivar-ref-misuse.m
+++ b/test/SemaObjC/ivar-ref-misuse.m
@@ -15,7 +15,7 @@ int UseGlobalBar;
@implementation Sprite
+ (void)setFoo:(int)foo {
- sprite = foo; // expected-error {{use of undeclared identifier 'sprite'}}
+ sprite = foo; // expected-error {{instance variable 'sprite' accessed in class method}}
spree = foo;
Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}}
UseGlobalBar = 10;
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
index a1d9fcb5372b..fe2c558a3d21 100644
--- a/test/SemaTemplate/current-instantiation.cpp
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -142,3 +142,12 @@ struct X0<T*, U*> {
void g8(typename ::X0<typename X0<T_type*, U*>::X2::my_T_type*, U_type*>::X2::my_T_type&); // expected-error{{redecl}}
};
};
+
+template<typename T>
+struct X1 {
+ static int *a;
+ void f(float *b) {
+ X1<T>::a = b; // expected-error{{incompatible}}
+ X1<T*>::a = b;
+ }
+};
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
new file mode 100644
index 000000000000..8d8833c6702e
--- /dev/null
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
+
+// Test default template arguments for function templates.
+template<typename T = int>
+void f0();
+
+template<typename T>
+void f0();
+
+void g0() {
+ f0(); // okay!
+}
+
+template<typename T, int N = T::value>
+int &f1(T);
+
+float &f1(...);
+
+struct HasValue {
+ static const int value = 17;
+};
+
+void g1() {
+ float &fr = f1(15);
+ int &ir = f1(HasValue());
+}
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index 95ee2d2b9d1f..aef43cb29db4 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -14,3 +14,73 @@ int a0[sizeof(X<int>::a) == sizeof(double) ? 1 : -1];
// PR4365.
template<class T> class Q;
template<class T> class R : Q<T> {T current;};
+
+
+namespace test0 {
+ template <class T> class Base {
+ void instance_foo();
+ static void static_foo();
+ class Inner {
+ void instance_foo();
+ static void static_foo();
+ };
+ };
+
+ template <class T> class Derived1 : Base<T> {
+ void test0() {
+ Base<T>::static_foo();
+ Base<T>::instance_foo();
+ }
+
+ void test1() {
+ Base<T>::Inner::static_foo();
+ Base<T>::Inner::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+
+ static void test2() {
+ Base<T>::static_foo();
+ Base<T>::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+
+ static void test3() {
+ Base<T>::Inner::static_foo();
+ Base<T>::Inner::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+ };
+
+ template <class T> class Derived2 : Base<T>::Inner {
+ void test0() {
+ Base<T>::static_foo();
+ Base<T>::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+
+ void test1() {
+ Base<T>::Inner::static_foo();
+ Base<T>::Inner::instance_foo();
+ }
+
+ static void test2() {
+ Base<T>::static_foo();
+ Base<T>::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+
+ static void test3() {
+ Base<T>::Inner::static_foo();
+ Base<T>::Inner::instance_foo(); // expected-error {{call to non-static member function without an object argument}}
+ }
+ };
+
+ void test0() {
+ Derived1<int> d1;
+ d1.test0();
+ d1.test1(); // expected-note {{in instantiation of member function}}
+ d1.test2(); // expected-note {{in instantiation of member function}}
+ d1.test3(); // expected-note {{in instantiation of member function}}
+
+ Derived2<int> d2;
+ d2.test0(); // expected-note {{in instantiation of member function}}
+ d2.test1();
+ d2.test2(); // expected-note {{in instantiation of member function}}
+ d2.test3(); // expected-note {{in instantiation of member function}}
+ }
+}
diff --git a/test/SemaTemplate/dependent-sized_array.cpp b/test/SemaTemplate/dependent-sized_array.cpp
new file mode 100644
index 000000000000..d221a4d276d2
--- /dev/null
+++ b/test/SemaTemplate/dependent-sized_array.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -pedantic -verify %s
+
+template<int N>
+void f() {
+ int a[] = { 1, 2, 3, N };
+ unsigned numAs = sizeof(a) / sizeof(int);
+}
+
+template void f<17>();
+
+
+template<int N>
+void f1() {
+ int a0[] = {}; // expected-warning{{zero}}
+ int a1[] = { 1, 2, 3, N };
+ int a3[sizeof(a1)/sizeof(int) != 4? 1 : -1]; // expected-error{{negative}}
+}
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index a7c8d247f021..afe2cfc30019 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -9,4 +9,11 @@ template<typename A> class s0 {
};
+struct Incomplete;
+template<typename T>
+void destroy_me(T me) {
+ me.~T();
+}
+
+template void destroy_me(Incomplete*);
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 2749ec24401b..a6c269febea1 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -106,9 +106,6 @@ template<typename T> struct Do0 {
void f(T t) {
do {
} while (t); // expected-error{{not contextually}}
-
- do {
- } while (T t2 = T());
}
};
diff --git a/test/SemaTemplate/instantiate-member-template.cpp b/test/SemaTemplate/instantiate-member-template.cpp
index 95556bcc221b..04ced926341a 100644
--- a/test/SemaTemplate/instantiate-member-template.cpp
+++ b/test/SemaTemplate/instantiate-member-template.cpp
@@ -116,3 +116,18 @@ struct X2 {
X2<int&> x2a; // expected-note{{instantiation}}
X2<float> x2b; // expected-note{{instantiation}}
+
+namespace N0 {
+ template<typename T>
+ struct X0 { };
+
+ struct X1 {
+ template<typename T> void f(X0<T>& vals) { g(vals); }
+ template<typename T> void g(X0<T>& vals) { }
+ };
+
+ void test(X1 x1, X0<int> x0i, X0<long> x0l) {
+ x1.f(x0i);
+ x1.f(x0l);
+ }
+}
diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp
index df1e1d964eb6..2351d882f9c2 100644
--- a/test/SemaTemplate/instantiate-method.cpp
+++ b/test/SemaTemplate/instantiate-method.cpp
@@ -84,6 +84,8 @@ int *a(A0<int> &x0, A1<int> &x1) {
struct X0Base {
int &f();
+ int& g(int);
+ static double &g(double);
};
template<typename T>
@@ -92,9 +94,28 @@ struct X0 : X0Base {
template<typename U>
struct X1 : X0<U> {
- int &f2() { return X0Base::f(); }
+ int &f2() {
+ // FIXME: We should be able to do this lookup and diagnose the error
+ // *despite* the fact that we can't decide the relationship yet.
+ return X0Base::f(); // expected-FIXME-error{{call to non-static member function without an object argument}}
+ }
};
void test_X1(X1<int> x1i) {
int &ir = x1i.f2();
}
+
+template<typename U>
+struct X2 : X0Base, U {
+ int &f2() { return X0Base::f(); }
+};
+
+template<typename T>
+struct X3 {
+ void test(T x) {
+ double& d1 = X0Base::g(x);
+ }
+};
+
+
+template struct X3<double>;
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index 96fa34cc2aff..452fccf2244d 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-
template<typename T, T Divisor>
class X {
public:
@@ -38,3 +37,38 @@ void test() {
DefCon &DC = Z<DefCon>::value;
NoDefCon &NDC = Z<NoDefCon>::value; // expected-note{{instantiation}}
}
+
+// PR5609
+struct X1 {
+ ~X1(); // The errors won't be triggered without this dtor.
+};
+
+template <typename T>
+struct Y1 {
+ static char Helper(T);
+ static const int value = sizeof(Helper(T()));
+};
+
+struct X2 {
+ virtual ~X2();
+};
+
+namespace std {
+ class type_info { };
+}
+
+template <typename T>
+struct Y2 {
+ static T &Helper();
+ static const int value = sizeof(typeid(Helper()));
+};
+
+template <int>
+struct Z1 {};
+
+void Test() {
+ Z1<Y1<X1>::value> x;
+ int y[Y1<X1>::value];
+ Z1<Y2<X2>::value> x2;
+ int y2[Y2<X2>::value];
+}
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
index 522c4e1cbb5c..31abb40dd5b1 100644
--- a/test/SemaTemplate/instantiation-depth.cpp
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -ftemplate-depth=5 -verify %s
+// RUN: clang-cc -fsyntax-only -ftemplate-depth 5 -verify %s
template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
// expected-note{{use -ftemplate-depth-N to increase recursive template instantiation depth}} \
diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp
index e936640f5e3e..436732a828d7 100644
--- a/test/SemaTemplate/nested-name-spec-template.cpp
+++ b/test/SemaTemplate/nested-name-spec-template.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only -verify -fms-extensions=0 %s
+// RUN: clang-cc -fsyntax-only -verify %s
namespace N {
namespace M {
diff --git a/test/SemaTemplate/overload-uneval.cpp b/test/SemaTemplate/overload-uneval.cpp
new file mode 100644
index 000000000000..2e3bfede700a
--- /dev/null
+++ b/test/SemaTemplate/overload-uneval.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Tests that overload resolution is treated as an unevaluated context.
+// PR5541
+struct Foo
+{
+ Foo *next;
+};
+
+template <typename>
+struct Bar
+{
+};
+
+
+template <typename T>
+class Wibble
+{
+ typedef Bar<T> B;
+
+ static inline B *concrete(Foo *node) {
+ int a[sizeof(T) ? -1 : -1];
+ return reinterpret_cast<B *>(node);
+ }
+
+public:
+ class It
+ {
+ Foo *i;
+
+ public:
+ inline operator B *() const { return concrete(i); }
+ inline bool operator!=(const It &o) const { return i !=
+o.i; }
+ };
+};
+
+void f() {
+ Wibble<void*>::It a, b;
+
+ a != b;
+}
diff --git a/test/SemaTemplate/qualified-id.cpp b/test/SemaTemplate/qualified-id.cpp
index 85efab2b5cc9..a07f05ca78ee 100644
--- a/test/SemaTemplate/qualified-id.cpp
+++ b/test/SemaTemplate/qualified-id.cpp
@@ -7,3 +7,14 @@ namespace a {
namespace b {
template<typename T> void f0(a::C<T> &a0) { }
}
+
+
+namespace test1 {
+ int a = 0;
+ template <class T> class Base { };
+ template <class T> class Derived : public Base<T> {
+ int foo() {
+ return test1::a;
+ }
+ };
+}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index bde92be93dfb..0c44651ccfee 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -151,3 +151,12 @@ namespace ns {
Baz<static_cast<ns::E>(0)> b2; // This neither.
}
+// PR5597
+template<int (*)(float)> struct X0 { };
+
+struct X1 {
+ static int pfunc(float);
+};
+void test_X0_X1() {
+ X0<X1::pfunc> x01;
+}
diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp
index 9c824d6f4145..ae409aff662b 100644
--- a/test/SemaTemplate/temp_explicit.cpp
+++ b/test/SemaTemplate/temp_explicit.cpp
@@ -108,3 +108,20 @@ struct X6 {
};
template struct X6::Inner; // expected-error{{non-templated}}
+
+// PR5559
+template <typename T>
+struct Foo;
+
+template <>
+struct Foo<int> // expected-note{{header not required for explicitly-specialized}}
+{
+ template <typename U>
+ struct Bar
+ {};
+};
+
+template <> // expected-warning{{extraneous template parameter list}}
+template <>
+struct Foo<int>::Bar<void>
+{};
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 46732de785bb..4681b939cea2 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -4,7 +4,7 @@
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
-//
+//
//===----------------------------------------------------------------------===//
//
// This file implements the Clang-C Source Indexing library.
@@ -24,7 +24,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -47,7 +46,7 @@ using namespace clang;
using namespace idx;
namespace {
-static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
{
NamedDecl *D = DRE->getDecl();
if (isa<VarDecl>(D))
@@ -56,7 +55,7 @@ static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
return CXCursor_FunctionRef;
else if (isa<EnumConstantDecl>(D))
return CXCursor_EnumConstantRef;
- else
+ else
return CXCursor_NotImplemented;
}
@@ -66,16 +65,16 @@ class CRefVisitor : public StmtVisitor<CRefVisitor> {
CXDecl CDecl;
CXDeclIterator Callback;
CXClientData CData;
-
+
void Call(enum CXCursorKind CK, Stmt *SRef) {
CXCursor C = { CK, CDecl, SRef };
Callback(CDecl, C, CData);
}
public:
- CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
+ CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
CDecl(C), Callback(cback), CData(D) {}
-
+
void VisitStmt(Stmt *S) {
for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
C != CEnd; ++C)
@@ -95,13 +94,13 @@ public:
}
};
#endif
-
+
/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
/// warnings and errors.
class VISIBILITY_HIDDEN IgnoreDiagnosticsClient : public DiagnosticClient {
public:
virtual ~IgnoreDiagnosticsClient() {}
- virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
+ virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
};
// Translation Unit Visitor.
@@ -109,30 +108,30 @@ class TUVisitor : public DeclVisitor<TUVisitor> {
CXTranslationUnit TUnit;
CXTranslationUnitIterator Callback;
CXClientData CData;
-
+
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
// to the visitor. Declarations with a PCH level greater than this value will
// be suppressed.
unsigned MaxPCHLevel;
-
+
void Call(enum CXCursorKind CK, NamedDecl *ND) {
// Filter any declarations that have a PCH level greater than what we allow.
if (ND->getPCHLevel() > MaxPCHLevel)
return;
-
+
// Filter any implicit declarations (since the source info will be bogus).
if (ND->isImplicit())
return;
-
+
CXCursor C = { CK, ND, 0 };
Callback(TUnit, C, CData);
}
public:
- TUVisitor(CXTranslationUnit CTU,
+ TUVisitor(CXTranslationUnit CTU,
CXTranslationUnitIterator cback, CXClientData D,
- unsigned MaxPCHLevel) :
+ unsigned MaxPCHLevel) :
TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
-
+
void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
VisitDeclContext(dyn_cast<DeclContext>(D));
}
@@ -157,63 +156,63 @@ public:
}
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
Call(CXCursor_ObjCInterfaceDecl, ND);
- }
+ }
void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
Call(CXCursor_ObjCProtocolDecl, ND);
}
void VisitTagDecl(TagDecl *ND) {
switch (ND->getTagKind()) {
- case TagDecl::TK_struct:
- Call(CXCursor_StructDecl, ND);
- break;
- case TagDecl::TK_class:
- Call(CXCursor_ClassDecl, ND);
- break;
- case TagDecl::TK_union:
- Call(CXCursor_UnionDecl, ND);
- break;
- case TagDecl::TK_enum:
- Call(CXCursor_EnumDecl, ND);
- break;
+ case TagDecl::TK_struct:
+ Call(CXCursor_StructDecl, ND);
+ break;
+ case TagDecl::TK_class:
+ Call(CXCursor_ClassDecl, ND);
+ break;
+ case TagDecl::TK_union:
+ Call(CXCursor_UnionDecl, ND);
+ break;
+ case TagDecl::TK_enum:
+ Call(CXCursor_EnumDecl, ND);
+ break;
}
}
- void VisitTypedefDecl(TypedefDecl *ND) {
- Call(CXCursor_TypedefDecl, ND);
- }
+ void VisitTypedefDecl(TypedefDecl *ND) {
+ Call(CXCursor_TypedefDecl, ND);
+ }
void VisitVarDecl(VarDecl *ND) {
Call(CXCursor_VarDecl, ND);
- }
+ }
};
-
+
// Declaration visitor.
class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
CXDecl CDecl;
CXDeclIterator Callback;
CXClientData CData;
-
+
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
// to the visitor. Declarations with a PCH level greater than this value will
// be suppressed.
unsigned MaxPCHLevel;
-
+
void Call(enum CXCursorKind CK, NamedDecl *ND) {
// Disable the callback when the context is equal to the visiting decl.
if (CDecl == ND && !clang_isReference(CK))
return;
-
+
// Filter any declarations that have a PCH level greater than what we allow.
if (ND->getPCHLevel() > MaxPCHLevel)
return;
-
+
CXCursor C = { CK, ND, 0 };
Callback(CDecl, C, CData);
}
public:
- CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
- unsigned MaxPCHLevel) :
+ CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
+ unsigned MaxPCHLevel) :
CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
-
+
void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
// Issue callbacks for the containing class.
Call(CXCursor_ObjCClassRef, ND);
@@ -225,16 +224,16 @@ public:
if (D->getSuperClass())
Call(CXCursor_ObjCSuperClassRef, D);
- for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end(); I != E; ++I)
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I)
Call(CXCursor_ObjCProtocolRef, *I);
VisitDeclContext(dyn_cast<DeclContext>(D));
}
void VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
- for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
- E = PID->protocol_end(); I != E; ++I)
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
Call(CXCursor_ObjCProtocolRef, *I);
-
+
VisitDeclContext(dyn_cast<DeclContext>(PID));
}
void VisitTagDecl(TagDecl *D) {
@@ -292,9 +291,9 @@ public:
};
class CIndexer : public Indexer {
-public:
- explicit CIndexer(Program *prog) : Indexer(*prog),
- OnlyLocalDecls(false),
+public:
+ explicit CIndexer(Program *prog) : Indexer(*prog),
+ OnlyLocalDecls(false),
DisplayDiagnostics(false) {}
virtual ~CIndexer() { delete &getProgram(); }
@@ -305,17 +304,17 @@ public:
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
- void setDisplayDiagnostics(bool Display = true) {
+ void setDisplayDiagnostics(bool Display = true) {
DisplayDiagnostics = Display;
}
bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
-
+
/// \brief Get the path of the clang binary.
const llvm::sys::Path& getClangPath();
private:
bool OnlyLocalDecls;
bool DisplayDiagnostics;
-
+
llvm::sys::Path ClangPath;
};
@@ -360,63 +359,63 @@ const llvm::sys::Path& CIndexer::getClangPath() {
}
-static SourceLocation getLocationFromCursor(CXCursor C,
+static SourceLocation getLocationFromCursor(CXCursor C,
SourceManager &SourceMgr,
NamedDecl *ND) {
if (clang_isReference(C.kind)) {
switch (C.kind) {
- case CXCursor_ObjCClassRef: {
- if (isa<ObjCInterfaceDecl>(ND)) {
- // FIXME: This is a hack (storing the parent decl in the stmt slot).
- NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt);
- return parentDecl->getLocation();
- }
- ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing category decl");
- return OID->getClassInterface()->getLocation();
- }
- case CXCursor_ObjCSuperClassRef: {
- ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing interface decl");
- return OID->getSuperClassLoc();
- }
- case CXCursor_ObjCProtocolRef: {
- ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing protocol decl");
- return OID->getLocation();
- }
- case CXCursor_ObjCSelectorRef: {
- ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
- static_cast<Stmt *>(C.stmt));
- assert(OME && "clang_getCursorLine(): Missing message expr");
- return OME->getLeftLoc(); /* FIXME: should be a range */
+ case CXCursor_ObjCClassRef: {
+ if (isa<ObjCInterfaceDecl>(ND)) {
+ // FIXME: This is a hack (storing the parent decl in the stmt slot).
+ NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt);
+ return parentDecl->getLocation();
}
- case CXCursor_VarRef:
- case CXCursor_FunctionRef:
- case CXCursor_EnumConstantRef: {
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
- static_cast<Stmt *>(C.stmt));
- assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
- return DRE->getLocation();
- }
- default:
- return SourceLocation();
+ ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing category decl");
+ return OID->getClassInterface()->getLocation();
+ }
+ case CXCursor_ObjCSuperClassRef: {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return OID->getSuperClassLoc();
+ }
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return OID->getLocation();
+ }
+ case CXCursor_ObjCSelectorRef: {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return OME->getLeftLoc(); /* FIXME: should be a range */
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef: {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return DRE->getLocation();
+ }
+ default:
+ return SourceLocation();
}
} else { // We have a declaration or a definition.
SourceLocation SLoc;
switch (ND->getKind()) {
- case Decl::ObjCInterface: {
- SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc();
- break;
- }
- case Decl::ObjCProtocol: {
- SLoc = ND->getLocation(); /* FIXME: need to get the name location. */
- break;
- }
- default: {
- SLoc = ND->getLocation();
- break;
- }
+ case Decl::ObjCInterface: {
+ SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc();
+ break;
+ }
+ case Decl::ObjCProtocol: {
+ SLoc = ND->getLocation(); /* FIXME: need to get the name location. */
+ break;
+ }
+ default: {
+ SLoc = ND->getLocation();
+ break;
+ }
}
if (SLoc.isInvalid())
return SourceLocation();
@@ -439,8 +438,7 @@ static CXString createCXString(const char *String, bool DupString = false) {
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
- int displayDiagnostics)
-{
+ int displayDiagnostics) {
CIndexer *CIdxr = new CIndexer(new Program());
if (excludeDeclarationsFromPCH)
CIdxr->setOnlyLocalDecls();
@@ -449,56 +447,55 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
return CIdxr;
}
-void clang_disposeIndex(CXIndex CIdx)
-{
+void clang_disposeIndex(CXIndex CIdx) {
assert(CIdx && "Passed null CXIndex");
delete static_cast<CIndexer *>(CIdx);
}
// FIXME: need to pass back error info.
-CXTranslationUnit clang_createTranslationUnit(
- CXIndex CIdx, const char *ast_filename)
-{
+CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
+ const char *ast_filename) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
std::string astName(ast_filename);
std::string ErrMsg;
-
+
CXTranslationUnit TU =
- ASTUnit::LoadFromPCHFile(astName, &ErrMsg,
- CXXIdx->getDisplayDiagnostics() ?
- NULL : new IgnoreDiagnosticsClient(),
- CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true);
-
+ ASTUnit::LoadFromPCHFile(astName, &ErrMsg,
+ CXXIdx->getDisplayDiagnostics() ?
+ NULL : new IgnoreDiagnosticsClient(),
+ CXXIdx->getOnlyLocalDecls(),
+ /* UseBumpAllocator = */ true);
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty())
llvm::errs() << "clang_createTranslationUnit: " << ErrMsg << '\n';
-
+
return TU;
}
-CXTranslationUnit clang_createTranslationUnitFromSourceFile(
- CXIndex CIdx,
- const char *source_filename,
- int num_command_line_args, const char **command_line_args) {
+CXTranslationUnit
+clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
+ const char *source_filename,
+ int num_command_line_args,
+ const char **command_line_args) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
// Build up the arguments for invoking 'clang'.
std::vector<const char *> argv;
-
+
// First add the complete path to the 'clang' executable.
llvm::sys::Path ClangPath = static_cast<CIndexer *>(CIdx)->getClangPath();
argv.push_back(ClangPath.c_str());
-
+
// Add the '-emit-ast' option as our execution mode for 'clang'.
argv.push_back("-emit-ast");
-
+
// The 'source_filename' argument is optional. If the caller does not
// specify it then it is assumed that the source file is specified
// in the actual argument list.
- if (source_filename)
- argv.push_back(source_filename);
+ if (source_filename)
+ argv.push_back(source_filename);
// Generate a temporary name for the AST file.
argv.push_back("-o");
@@ -521,7 +518,7 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
// Keep the argument.
argv.push_back(arg);
}
-
+
// Add the null terminator.
argv.push_back(NULL);
@@ -533,10 +530,10 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ !CXXIdx->getDisplayDiagnostics() ? &Redirects[0] : NULL,
/* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
-
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
- << '\n' << "Arguments: \n";
+ llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
+ << '\n' << "Arguments: \n";
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
I!=E; ++I) {
if (*I)
@@ -547,45 +544,40 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
// Finally, we create the translation unit from the ast file.
ASTUnit *ATU = static_cast<ASTUnit *>(
- clang_createTranslationUnit(CIdx, astTmpFile));
+ clang_createTranslationUnit(CIdx, astTmpFile));
if (ATU)
ATU->unlinkTemporaryFile();
return ATU;
}
-void clang_disposeTranslationUnit(
- CXTranslationUnit CTUnit)
-{
+void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
assert(CTUnit && "Passed null CXTranslationUnit");
delete static_cast<ASTUnit *>(CTUnit);
}
-
-CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
-{
+
+CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
assert(CTUnit && "Passed null CXTranslationUnit");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
return createCXString(CXXUnit->getOriginalSourceFileName().c_str(), true);
}
-void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
+void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
CXTranslationUnitIterator callback,
- CXClientData CData)
-{
+ CXClientData CData) {
assert(CTUnit && "Passed null CXTranslationUnit");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
ASTContext &Ctx = CXXUnit->getASTContext();
-
- TUVisitor DVisit(CTUnit, callback, CData,
+
+ TUVisitor DVisit(CTUnit, callback, CData,
CXXUnit->getOnlyLocalDecls()? 1 : Decl::MaxPCHLevel);
DVisit.Visit(Ctx.getTranslationUnitDecl());
}
-void clang_loadDeclaration(CXDecl Dcl,
- CXDeclIterator callback,
- CXClientData CData)
-{
+void clang_loadDeclaration(CXDecl Dcl,
+ CXDeclIterator callback,
+ CXClientData CData) {
assert(Dcl && "Passed null CXDecl");
-
+
CDeclVisitor DVisit(Dcl, callback, CData,
static_cast<Decl *>(Dcl)->getPCHLevel());
DVisit.Visit(static_cast<Decl *>(Dcl));
@@ -593,14 +585,14 @@ void clang_loadDeclaration(CXDecl Dcl,
// Some notes on CXEntity:
//
-// - Since the 'ordinary' namespace includes functions, data, typedefs,
-// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
+// - Since the 'ordinary' namespace includes functions, data, typedefs,
+// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
// entity for 2 different types). For example:
//
// module1.m: @interface Foo @end Foo *x;
// module2.m: void Foo(int);
//
-// - Since the unique name spans translation units, static data/functions
+// - Since the unique name spans translation units, static data/functions
// within a CXTranslationUnit are *not* currently represented by entities.
// As a result, there will be no entity for the following:
//
@@ -608,29 +600,27 @@ void clang_loadDeclaration(CXDecl Dcl,
//
-const char *clang_getDeclarationName(CXEntity)
-{
+const char *clang_getDeclarationName(CXEntity) {
return "";
}
-const char *clang_getURI(CXEntity)
-{
+
+const char *clang_getURI(CXEntity) {
return "";
}
-CXEntity clang_getEntity(const char *URI)
-{
+CXEntity clang_getEntity(const char *URI) {
return 0;
}
//
// CXDecl Operations.
//
-CXEntity clang_getEntityFromDecl(CXDecl)
-{
+
+CXEntity clang_getEntityFromDecl(CXDecl) {
return 0;
}
-CXString clang_getDeclSpelling(CXDecl AnonDecl)
-{
+
+CXString clang_getDeclSpelling(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
@@ -649,24 +639,21 @@ CXString clang_getDeclSpelling(CXDecl AnonDecl)
return createCXString("");
}
-unsigned clang_getDeclLine(CXDecl AnonDecl)
-{
+unsigned clang_getDeclLine(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
return SourceMgr.getSpellingLineNumber(ND->getLocation());
}
-unsigned clang_getDeclColumn(CXDecl AnonDecl)
-{
+unsigned clang_getDeclColumn(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
return SourceMgr.getSpellingColumnNumber(ND->getLocation());
}
-const char *clang_getDeclSource(CXDecl AnonDecl)
-{
+const char *clang_getDeclSource(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
FileEntry *FEnt = static_cast<FileEntry *>(clang_getDeclSourceFile(AnonDecl));
assert (FEnt && "Cannot find FileEntry for Decl");
@@ -674,8 +661,7 @@ const char *clang_getDeclSource(CXDecl AnonDecl)
}
static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
- SourceLocation SLoc)
-{
+ SourceLocation SLoc) {
FileID FID;
if (SLoc.isFileID())
FID = SMgr.getFileID(SLoc);
@@ -684,8 +670,7 @@ static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
return SMgr.getFileEntryForID(FID);
}
-CXFile clang_getDeclSourceFile(CXDecl AnonDecl)
-{
+CXFile clang_getDeclSourceFile(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
@@ -704,145 +689,143 @@ time_t clang_getFileTime(CXFile SFile) {
return FEnt->getModificationTime();
}
-CXString clang_getCursorSpelling(CXCursor C)
-{
+CXString clang_getCursorSpelling(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
if (clang_isReference(C.kind)) {
switch (C.kind) {
- case CXCursor_ObjCSuperClassRef: {
- ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing interface decl");
- return createCXString(OID->getSuperClass()->getIdentifier()
- ->getNameStart());
- }
- case CXCursor_ObjCClassRef: {
- if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND))
- return createCXString(OID->getIdentifier()->getNameStart());
-
- ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
- assert(OCD && "clang_getCursorLine(): Missing category decl");
- return createCXString(OCD->getClassInterface()->getIdentifier()
- ->getNameStart());
- }
- case CXCursor_ObjCProtocolRef: {
- ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ case CXCursor_ObjCSuperClassRef: {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return createCXString(OID->getSuperClass()->getIdentifier()
+ ->getNameStart());
+ }
+ case CXCursor_ObjCClassRef: {
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND))
return createCXString(OID->getIdentifier()->getNameStart());
- }
- case CXCursor_ObjCSelectorRef: {
- ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
- static_cast<Stmt *>(C.stmt));
- assert(OME && "clang_getCursorLine(): Missing message expr");
- return createCXString(OME->getSelector().getAsString().c_str(), true);
- }
- case CXCursor_VarRef:
- case CXCursor_FunctionRef:
- case CXCursor_EnumConstantRef: {
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
- static_cast<Stmt *>(C.stmt));
- assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
- return createCXString(DRE->getDecl()->getIdentifier()->getNameStart());
- }
- default:
- return createCXString("<not implemented>");
+
+ ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OCD && "clang_getCursorLine(): Missing category decl");
+ return createCXString(OCD->getClassInterface()->getIdentifier()
+ ->getNameStart());
+ }
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return createCXString(OID->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCSelectorRef: {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return createCXString(OME->getSelector().getAsString().c_str(), true);
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef: {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return createCXString(DRE->getDecl()->getIdentifier()->getNameStart());
+ }
+ default:
+ return createCXString("<not implemented>");
}
}
return clang_getDeclSpelling(C.decl);
}
-const char *clang_getCursorKindSpelling(enum CXCursorKind Kind)
-{
+const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) {
switch (Kind) {
- case CXCursor_FunctionDecl: return "FunctionDecl";
- case CXCursor_TypedefDecl: return "TypedefDecl";
- case CXCursor_EnumDecl: return "EnumDecl";
- case CXCursor_EnumConstantDecl: return "EnumConstantDecl";
- case CXCursor_StructDecl: return "StructDecl";
- case CXCursor_UnionDecl: return "UnionDecl";
- case CXCursor_ClassDecl: return "ClassDecl";
- case CXCursor_FieldDecl: return "FieldDecl";
- case CXCursor_VarDecl: return "VarDecl";
- case CXCursor_ParmDecl: return "ParmDecl";
- case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl";
- case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl";
- case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl";
- case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl";
- case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl";
- case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl";
- case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl";
- case CXCursor_FunctionDefn: return "FunctionDefn";
- case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn";
- case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn";
- case CXCursor_ObjCClassDefn: return "ObjCClassDefn";
- case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn";
- case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef";
- case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef";
- case CXCursor_ObjCClassRef: return "ObjCClassRef";
- case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef";
-
- case CXCursor_VarRef: return "VarRef";
- case CXCursor_FunctionRef: return "FunctionRef";
- case CXCursor_EnumConstantRef: return "EnumConstantRef";
- case CXCursor_MemberRef: return "MemberRef";
-
- case CXCursor_InvalidFile: return "InvalidFile";
- case CXCursor_NoDeclFound: return "NoDeclFound";
- case CXCursor_NotImplemented: return "NotImplemented";
- default: return "<not implemented>";
+ case CXCursor_FunctionDecl: return "FunctionDecl";
+ case CXCursor_TypedefDecl: return "TypedefDecl";
+ case CXCursor_EnumDecl: return "EnumDecl";
+ case CXCursor_EnumConstantDecl: return "EnumConstantDecl";
+ case CXCursor_StructDecl: return "StructDecl";
+ case CXCursor_UnionDecl: return "UnionDecl";
+ case CXCursor_ClassDecl: return "ClassDecl";
+ case CXCursor_FieldDecl: return "FieldDecl";
+ case CXCursor_VarDecl: return "VarDecl";
+ case CXCursor_ParmDecl: return "ParmDecl";
+ case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl";
+ case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl";
+ case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl";
+ case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl";
+ case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl";
+ case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl";
+ case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl";
+ case CXCursor_FunctionDefn: return "FunctionDefn";
+ case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn";
+ case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn";
+ case CXCursor_ObjCClassDefn: return "ObjCClassDefn";
+ case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn";
+ case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef";
+ case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef";
+ case CXCursor_ObjCClassRef: return "ObjCClassRef";
+ case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef";
+
+ case CXCursor_VarRef: return "VarRef";
+ case CXCursor_FunctionRef: return "FunctionRef";
+ case CXCursor_EnumConstantRef: return "EnumConstantRef";
+ case CXCursor_MemberRef: return "MemberRef";
+
+ case CXCursor_InvalidFile: return "InvalidFile";
+ case CXCursor_NoDeclFound: return "NoDeclFound";
+ case CXCursor_NotImplemented: return "NotImplemented";
+ default: return "<not implemented>";
}
}
static enum CXCursorKind TranslateKind(Decl *D) {
switch (D->getKind()) {
- case Decl::Function: return CXCursor_FunctionDecl;
- case Decl::Typedef: return CXCursor_TypedefDecl;
- case Decl::Enum: return CXCursor_EnumDecl;
- case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
- case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class
- case Decl::Field: return CXCursor_FieldDecl;
- case Decl::Var: return CXCursor_VarDecl;
- case Decl::ParmVar: return CXCursor_ParmDecl;
- case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
- case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
- case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
- case Decl::ObjCMethod: {
- ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
- if (MD->isInstanceMethod())
- return CXCursor_ObjCInstanceMethodDecl;
- return CXCursor_ObjCClassMethodDecl;
- }
- default: break;
+ case Decl::Function: return CXCursor_FunctionDecl;
+ case Decl::Typedef: return CXCursor_TypedefDecl;
+ case Decl::Enum: return CXCursor_EnumDecl;
+ case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
+ case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class
+ case Decl::Field: return CXCursor_FieldDecl;
+ case Decl::Var: return CXCursor_VarDecl;
+ case Decl::ParmVar: return CXCursor_ParmDecl;
+ case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
+ case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
+ case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
+ if (MD->isInstanceMethod())
+ return CXCursor_ObjCInstanceMethodDecl;
+ return CXCursor_ObjCClassMethodDecl;
+ }
+ default: break;
}
return CXCursor_NotImplemented;
}
//
// CXCursor Operations.
//
-CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
- unsigned line, unsigned column)
-{
+
+CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
+ unsigned line, unsigned column) {
assert(CTUnit && "Passed null CXTranslationUnit");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
-
+
FileManager &FMgr = CXXUnit->getFileManager();
- const FileEntry *File = FMgr.getFile(source_name,
- source_name+strlen(source_name));
+ const FileEntry *File = FMgr.getFile(source_name,
+ source_name+strlen(source_name));
if (!File) {
CXCursor C = { CXCursor_InvalidFile, 0, 0 };
return C;
}
- SourceLocation SLoc =
+ SourceLocation SLoc =
CXXUnit->getSourceManager().getLocation(File, line, column);
-
+
ASTLocation LastLoc = CXXUnit->getLastASTLocation();
- ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
+ ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
&LastLoc);
if (ALoc.isValid())
CXXUnit->setLastASTLocation(ALoc);
-
+
Decl *Dcl = ALoc.getParentDecl();
if (ALoc.isNamedRef())
Dcl = ALoc.AsNamedRef().ND;
@@ -855,7 +838,7 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
} else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) {
CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp };
return C;
- }
+ }
// Fall through...treat as a decl, not a ref.
}
if (ALoc.isNamedRef()) {
@@ -868,7 +851,7 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
return C;
}
}
- CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
+ CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
return C;
}
CXCursor C = { CXCursor_NoDeclFound, 0, 0 };
@@ -886,38 +869,32 @@ CXCursor clang_getNullCursor(void) {
unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt;
}
-
-CXCursor clang_getCursorFromDecl(CXDecl AnonDecl)
-{
+
+CXCursor clang_getCursorFromDecl(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
-
+
CXCursor C = { TranslateKind(ND), ND, 0 };
return C;
}
-unsigned clang_isInvalid(enum CXCursorKind K)
-{
+unsigned clang_isInvalid(enum CXCursorKind K) {
return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
}
-unsigned clang_isDeclaration(enum CXCursorKind K)
-{
+unsigned clang_isDeclaration(enum CXCursorKind K) {
return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
}
-unsigned clang_isReference(enum CXCursorKind K)
-{
+unsigned clang_isReference(enum CXCursorKind K) {
return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
}
-unsigned clang_isDefinition(enum CXCursorKind K)
-{
+unsigned clang_isDefinition(enum CXCursorKind K) {
return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn;
}
-CXCursorKind clang_getCursorKind(CXCursor C)
-{
+CXCursorKind clang_getCursorKind(CXCursor C) {
return C.kind;
}
@@ -939,14 +916,13 @@ static Decl *getDeclFromExpr(Stmt *E) {
return 0;
}
-CXDecl clang_getCursorDecl(CXCursor C)
-{
+CXDecl clang_getCursorDecl(CXCursor C) {
if (clang_isDeclaration(C.kind))
return C.decl;
-
+
if (clang_isReference(C.kind)) {
if (C.stmt) {
- if (C.kind == CXCursor_ObjCClassRef ||
+ if (C.kind == CXCursor_ObjCClassRef ||
C.kind == CXCursor_ObjCProtocolRef)
return static_cast<Stmt *>(C.stmt);
else
@@ -957,44 +933,40 @@ CXDecl clang_getCursorDecl(CXCursor C)
return 0;
}
-unsigned clang_getCursorLine(CXCursor C)
-{
+unsigned clang_getCursorLine(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
-
+
SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
return SourceMgr.getSpellingLineNumber(SLoc);
}
-// Access string.
const char *clang_getCString(CXString string) {
return string.Spelling;
}
-
-// Free CXString.
+
void clang_disposeString(CXString string) {
if (string.MustFreeString)
free((void*)string.Spelling);
}
-unsigned clang_getCursorColumn(CXCursor C)
-{
+unsigned clang_getCursorColumn(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
-
+
SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
return SourceMgr.getSpellingColumnNumber(SLoc);
}
-const char *clang_getCursorSource(CXCursor C)
-{
+
+const char *clang_getCursorSource(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
-
+
SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
-
+
if (SLoc.isFileID()) {
const char *bufferName = SourceMgr.getBufferName(SLoc);
return bufferName[0] == '<' ? NULL : bufferName;
@@ -1003,7 +975,7 @@ const char *clang_getCursorSource(CXCursor C)
// Retrieve the file in which the macro was instantiated, then provide that
// buffer name.
// FIXME: Do we want to give specific macro-instantiation information?
- const llvm::MemoryBuffer *Buffer
+ const llvm::MemoryBuffer *Buffer
= SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first);
if (!Buffer)
return 0;
@@ -1011,29 +983,27 @@ const char *clang_getCursorSource(CXCursor C)
return Buffer->getBufferIdentifier();
}
-CXFile clang_getCursorSourceFile(CXCursor C)
-{
+CXFile clang_getCursorSourceFile(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
-
+
return (void *)getFileEntryFromSourceLocation(SourceMgr,
- getLocationFromCursor(C,SourceMgr, ND));
+ getLocationFromCursor(C,SourceMgr, ND));
}
-void clang_getDefinitionSpellingAndExtent(CXCursor C,
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
const char **startBuf,
const char **endBuf,
unsigned *startLine,
unsigned *startColumn,
unsigned *endLine,
- unsigned *endColumn)
-{
+ unsigned *endColumn) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
-
+
SourceManager &SM = FD->getASTContext().getSourceManager();
*startBuf = SM.getCharacterData(Body->getLBracLoc());
*endBuf = SM.getCharacterData(Body->getRBracLoc());
@@ -1043,20 +1013,20 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
*endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
}
-enum CXCompletionChunkKind
+enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return CXCompletionChunk_Text;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
return CXCompletionChunk_TypedText;
case CodeCompletionString::CK_Text:
return CXCompletionChunk_Text;
case CodeCompletionString::CK_Optional:
- return CXCompletionChunk_Optional;
+ return CXCompletionChunk_Optional;
case CodeCompletionString::CK_Placeholder:
return CXCompletionChunk_Placeholder;
case CodeCompletionString::CK_Informative:
@@ -1082,17 +1052,17 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
case CodeCompletionString::CK_Comma:
return CXCompletionChunk_Comma;
}
-
+
// Should be unreachable, but let's be careful.
return CXCompletionChunk_Text;
}
-
+
const char *clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
case CodeCompletionString::CK_Text:
@@ -1109,23 +1079,23 @@ const char *clang_getCompletionChunkText(CXCompletionString completion_string,
case CodeCompletionString::CK_RightAngle:
case CodeCompletionString::CK_Comma:
return (*CCStr)[chunk_number].Text;
-
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return 0;
}
-
+
// Should be unreachable, but let's be careful.
return 0;
}
-
+
CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
case CodeCompletionString::CK_Text:
@@ -1142,51 +1112,34 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
case CodeCompletionString::CK_RightAngle:
case CodeCompletionString::CK_Comma:
return 0;
-
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return (*CCStr)[chunk_number].Optional;
}
-
+
// Should be unreachable, but let's be careful.
return 0;
}
-
+
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
return CCStr? CCStr->size() : 0;
}
-static CXCursorKind parseResultKind(llvm::StringRef Str) {
- return llvm::StringSwitch<CXCursorKind>(Str)
- .Case("Typedef", CXCursor_TypedefDecl)
- .Case("Struct", CXCursor_StructDecl)
- .Case("Union", CXCursor_UnionDecl)
- .Case("Class", CXCursor_ClassDecl)
- .Case("Enum", CXCursor_EnumDecl)
- .Case("Field", CXCursor_FieldDecl)
- .Case("EnumConstant", CXCursor_EnumConstantDecl)
- .Case("Function", CXCursor_FunctionDecl)
- // FIXME: Hacks here to make C++ member functions look like C functions
- .Case("CXXMethod", CXCursor_FunctionDecl)
- .Case("CXXConstructor", CXCursor_FunctionDecl)
- .Case("CXXDestructor", CXCursor_FunctionDecl)
- .Case("CXXConversion", CXCursor_FunctionDecl)
- .Case("Var", CXCursor_VarDecl)
- .Case("ParmVar", CXCursor_ParmDecl)
- .Case("ObjCInterface", CXCursor_ObjCInterfaceDecl)
- .Case("ObjCCategory", CXCursor_ObjCCategoryDecl)
- .Case("ObjCProtocol", CXCursor_ObjCProtocolDecl)
- .Case("ObjCProperty", CXCursor_ObjCPropertyDecl)
- .Case("ObjCIvar", CXCursor_ObjCIvarDecl)
- .Case("ObjCInstanceMethod", CXCursor_ObjCInstanceMethodDecl)
- .Case("ObjCClassMethod", CXCursor_ObjCClassMethodDecl)
- .Default(CXCursor_NotImplemented);
+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 clang_codeComplete(CXIndex CIdx,
+
+void clang_codeComplete(CXIndex CIdx,
const char *source_filename,
- int num_command_line_args,
+ int num_command_line_args,
const char **command_line_args,
const char *complete_filename,
unsigned complete_line,
@@ -1195,15 +1148,15 @@ void clang_codeComplete(CXIndex CIdx,
CXClientData client_data) {
// The indexer, which is mainly used to determine where diagnostics go.
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
-
+
// Build up the arguments for invoking 'clang'.
std::vector<const char *> argv;
-
+
// First add the complete path to the 'clang' executable.
llvm::sys::Path ClangPath = CXXIdx->getClangPath();
argv.push_back(ClangPath.c_str());
-
- // Add the '-fsyntax-only' argument so that we only perform a basic
+
+ // Add the '-fsyntax-only' argument so that we only perform a basic
// syntax check of the code.
argv.push_back("-fsyntax-only");
@@ -1220,12 +1173,12 @@ void clang_codeComplete(CXIndex CIdx,
argv.push_back(code_complete_at.c_str());
argv.push_back("-Xclang");
argv.push_back("-no-code-completion-debug-printer");
-
+
// Add the source file name (FIXME: later, we'll want to build temporary
// file from the buffer, or just feed the source text via standard input).
if (source_filename)
- argv.push_back(source_filename);
-
+ argv.push_back(source_filename);
+
// Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
for (int i = 0; i < num_command_line_args; ++i)
if (const char *arg = command_line_args[i]) {
@@ -1238,19 +1191,19 @@ void clang_codeComplete(CXIndex CIdx,
strcmp(arg, "-fsyntax-only") == 0) {
continue;
}
-
+
// Keep the argument.
argv.push_back(arg);
}
-
+
// Add the null terminator.
argv.push_back(NULL);
-
+
// Generate a temporary name for the AST file.
char tmpFile[L_tmpnam];
char *tmpFileName = tmpnam(tmpFile);
llvm::sys::Path ResultsFile(tmpFileName);
-
+
// Invoke 'clang'.
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
@@ -1258,12 +1211,12 @@ void clang_codeComplete(CXIndex CIdx,
const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
- /* secondsToWait */ 0,
+ /* secondsToWait */ 0,
/* memoryLimits */ 0, &ErrMsg);
-
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_codeComplete: " << ErrMsg
- << '\n' << "Arguments: \n";
+ llvm::errs() << "clang_codeComplete: " << ErrMsg
+ << '\n' << "Arguments: \n";
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
I!=E; ++I) {
if (*I)
@@ -1277,84 +1230,32 @@ void clang_codeComplete(CXIndex CIdx,
using llvm::StringRef;
if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
StringRef Buffer = F->getBuffer();
- do {
- StringRef::size_type CompletionIdx = Buffer.find("COMPLETION:");
- StringRef::size_type OverloadIdx = Buffer.find("OVERLOAD:");
- if (CompletionIdx == StringRef::npos && OverloadIdx == StringRef::npos)
+ for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+ Str < StrEnd;) {
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
break;
-
- if (OverloadIdx < CompletionIdx) {
- // Parse an overload result.
- Buffer = Buffer.substr(OverloadIdx);
-
- // Skip past the OVERLOAD:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
-
+
+ CodeCompletionString *CCStr
+ = CodeCompletionString::Deserialize(Str, StrEnd);
+ if (!CCStr)
+ continue;
+
+ if (!CCStr->empty()) {
// Vend the code-completion result to the caller.
CXCompletionResult Result;
- Result.CursorKind = CXCursor_NotImplemented;
+ Result.CursorKind = (CXCursorKind)KindValue;
Result.CompletionString = CCStr;
if (completion_iterator)
completion_iterator(&Result, client_data);
- delete CCStr;
-
- continue;
}
-
- // Parse a completion result.
- Buffer = Buffer.substr(CompletionIdx);
-
- // Skip past the COMPLETION:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Get the rank
- unsigned Rank = 0;
- StringRef::size_type AfterRank = Buffer.find(':');
- Buffer.substr(0, AfterRank).getAsInteger(10, Rank);
- Buffer = Buffer.substr(AfterRank + 1);
-
- // Get the kind of result.
- StringRef::size_type AfterKind = Buffer.find(':');
- StringRef Kind = Buffer.substr(0, AfterKind);
- Buffer = Buffer.substr(AfterKind + 1);
-
- // Skip over any whitespace.
- Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
-
- // Vend the code-completion result to the caller.
- CXCompletionResult Result;
- Result.CursorKind = parseResultKind(Kind);
- Result.CompletionString = CCStr;
- if (completion_iterator)
- completion_iterator(&Result, client_data);
+
delete CCStr;
- } while (true);
+ };
delete F;
- }
-
+ }
+
ResultsFile.eraseFromDisk();
}
-
+
} // end extern "C"
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 8cded43151c8..8c666dd71a0c 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,5 +1,5 @@
+add_subdirectory(CIndex)
+add_subdirectory(c-index-test)
add_subdirectory(clang-cc)
add_subdirectory(driver)
add_subdirectory(index-test)
-add_subdirectory(CIndex)
-add_subdirectory(c-index-test)
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 4c724659f6f6..4678461de1f4 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -4,8 +4,11 @@ set( LLVM_USED_LIBS
CIndex
clangIndex
clangFrontend
+ clangDriver
+ clangAnalysis
clangSema
clangAST
+ clangParse
clangLex
clangBasic
)
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 81fee40b66e2..ae49bf4d7af9 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -19,6 +19,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := bitreader mc
-USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a \
+ clangSema.a clangAST.a clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 289dee962987..5364d7948c5d 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -38,7 +38,6 @@ static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
return 1;
}
-
/******************************************************************************/
/* Pretty-printing. */
/******************************************************************************/
@@ -71,8 +70,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
/* Logic for testing clang_loadTranslationUnit(). */
/******************************************************************************/
-static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
-{
+static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) {
if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
CXString string;
printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
@@ -84,9 +82,9 @@ static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
clang_disposeString(string);
}
}
+
static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
- CXClientData Filter)
-{
+ CXClientData Filter) {
if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
CXString string;
printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
@@ -99,58 +97,56 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
clang_disposeString(string);
clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
+ }
+}
- if (Cursor.kind == CXCursor_FunctionDefn) {
- const char *startBuf, *endBuf;
- unsigned startLine, startColumn, endLine, endColumn;
- clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
- &startLine, &startColumn,
- &endLine, &endColumn);
- {
- /* Probe the entire body, looking for both decls and refs. */
- unsigned curLine = startLine, curColumn = startColumn;
- CXCursor Ref;
-
- while (startBuf < endBuf) {
- if (*startBuf == '\n') {
- startBuf++;
- curLine++;
- curColumn = 1;
- } else if (*startBuf != '\t')
- curColumn++;
+static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
+ CXClientData Filter) {
+ const char *startBuf, *endBuf;
+ unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
+ CXCursor Ref;
+
+ if (Cursor.kind != CXCursor_FunctionDefn)
+ return;
+
+ clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
+ &startLine, &startColumn,
+ &endLine, &endColumn);
+ /* Probe the entire body, looking for both decls and refs. */
+ curLine = startLine;
+ curColumn = startColumn;
+
+ while (startBuf < endBuf) {
+ if (*startBuf == '\n') {
+ startBuf++;
+ curLine++;
+ curColumn = 1;
+ } else if (*startBuf != '\t')
+ curColumn++;
- Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
- curLine, curColumn);
- if (Ref.kind == CXCursor_NoDeclFound) {
- /* Nothing found here; that's fine. */
- } else if (Ref.kind != CXCursor_FunctionDecl) {
- CXString string;
- printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
- curLine, curColumn);
- PrintCursor(Ref);
- string = clang_getDeclSpelling(Ref.decl);
- printf(" [Context:%s]\n", clang_getCString(string));
- clang_disposeString(string);
- }
- startBuf++;
- }
- }
+ Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
+ curLine, curColumn);
+ if (Ref.kind == CXCursor_NoDeclFound) {
+ /* Nothing found here; that's fine. */
+ } else if (Ref.kind != CXCursor_FunctionDecl) {
+ CXString string;
+ printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
+ curLine, curColumn);
+ PrintCursor(Ref);
+ string = clang_getDeclSpelling(Ref.decl);
+ printf(" [Context:%s]\n", clang_getCString(string));
+ clang_disposeString(string);
}
+ startBuf++;
}
}
-int perform_test_load_tu(const char *file, const char *filter) {
- CXIndex Idx;
- CXTranslationUnit TU;
+static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
+ const char *filter) {
enum CXCursorKind K = CXCursor_NotImplemented;
+ CXTranslationUnitIterator Visitor = TranslationUnitVisitor;
enum CXCursorKind *ck = &K;
- Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
-
- if (!CreateTranslationUnit(Idx, file, &TU))
- return 1;
-
+
/* Perform some simple filtering. */
if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
@@ -158,16 +154,46 @@ int perform_test_load_tu(const char *file, const char *filter) {
else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
+ else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
else {
fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
return 1;
}
- clang_loadTranslationUnit(TU, TranslationUnitVisitor, ck);
+ clang_loadTranslationUnit(TU, Visitor, ck);
clang_disposeTranslationUnit(TU);
return 0;
}
+int perform_test_load_tu(const char *file, const char *filter) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */
+ !strcmp(filter, "local") ? 1 : 0,
+ /* displayDiagnostics */ 1);
+
+ if (!CreateTranslationUnit(Idx, file, &TU))
+ return 1;
+
+ return perform_test_load(Idx, TU, filter);
+}
+
+int perform_test_load_source(int argc, const char **argv, const char *filter) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */
+ !strcmp(filter, "local") ? 1 : 0,
+ /* displayDiagnostics */ 1);
+
+ TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv);
+ if (!TU) {
+ fprintf(stderr, "Unable to load translation unit!\n");
+ return 1;
+ }
+
+ return perform_test_load(Idx, TU, filter);
+}
+
/******************************************************************************/
/* Logic for testing clang_getCursor(). */
/******************************************************************************/
@@ -394,14 +420,16 @@ static void print_usage(void) {
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n"
" c-index-test -test-load-tu <AST file> <symbol filter>\n\n"
- " <symbol filter> options for -test-load-tu:\n%s",
+ " c-index-test -test-load-source <symbol filter> {<args>}*\n\n"
+ " <symbol filter> options for -test-load-tu and -test-load-source:\n%s",
" all - load all symbols, including those from PCH\n"
" local - load all symbols except those in PCH\n"
" category - only load ObjC categories (non-PCH)\n"
" interface - only load ObjC interfaces (non-PCH)\n"
" protocol - only load ObjC protocols (non-PCH)\n"
" function - only load functions (non-PCH)\n"
- " typedef - only load typdefs (non-PCH)\n\n");
+ " typedef - only load typdefs (non-PCH)\n"
+ " scan-function - scan function bodies (non-PCH)\n\n");
}
int main(int argc, const char **argv) {
@@ -409,6 +437,8 @@ int main(int argc, const char **argv) {
return perform_code_completion(argc, argv);
if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0)
return perform_test_load_tu(argv[2], argv[3]);
+ if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0)
+ return perform_test_load_source(argc - 3, argv + 3, argv[2]);
if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
argc >= 5 ? argv[4] : 0);
diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt
index e7da908fdd06..c96e8b1d068b 100644
--- a/tools/clang-cc/CMakeLists.txt
+++ b/tools/clang-cc/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
+ clangDriver
clangFrontend
clangCodeGen
clangAnalysis
diff --git a/tools/clang-cc/Makefile b/tools/clang-cc/Makefile
index 874a42fc1913..ebcc1d5fa0ba 100644
--- a/tools/clang-cc/Makefile
+++ b/tools/clang-cc/Makefile
@@ -21,7 +21,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
-USEDLIBS = clangFrontend.a clangCodeGen.a clangAnalysis.a \
+USEDLIBS = clangDriver.a clangFrontend.a clangCodeGen.a clangAnalysis.a \
clangRewrite.a clangSema.a clangAST.a clangParse.a \
clangLex.a clangBasic.a
diff --git a/tools/clang-cc/Options.cpp b/tools/clang-cc/Options.cpp
index 584f95709519..a18598ef7c21 100644
--- a/tools/clang-cc/Options.cpp
+++ b/tools/clang-cc/Options.cpp
@@ -21,6 +21,7 @@
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -81,7 +82,7 @@ static llvm::cl::opt<bool>
AnalyzeAll("analyzer-opt-analyze-headers",
llvm::cl::desc("Force the static analyzer to analyze "
"functions defined in header files"));
-
+
static llvm::cl::opt<bool>
AnalyzerDisplayProgress("analyzer-display-progress",
llvm::cl::desc("Emit verbose output about the analyzer's progress"));
@@ -93,7 +94,7 @@ AnalyzerExperimentalChecks("analyzer-experimental-checks",
static llvm::cl::opt<bool>
AnalyzerExperimentalInternalChecks("analyzer-experimental-internal-checks",
llvm::cl::desc("Use new default path-sensitive checks currently in testing"));
-
+
static llvm::cl::opt<std::string>
AnalyzeSpecificFunction("analyze-function",
llvm::cl::desc("Run analysis on specific function"));
@@ -141,6 +142,46 @@ GenerateDebugInfo("g",
llvm::cl::desc("Generate source level debug information"));
static llvm::cl::opt<bool>
+MAsmVerbose("masm-verbose", llvm::cl::desc("Generate verbose assembly output"));
+
+static llvm::cl::opt<std::string>
+MCodeModel("mcode-model", llvm::cl::desc("The code model to use"));
+
+static llvm::cl::opt<std::string>
+MDebugPass("mdebu-pass", llvm::cl::desc("Output additional debug information"));
+
+static llvm::cl::opt<bool>
+MDisableFPElim("mdisable-fp-elim",
+ llvm::cl::desc("Disable frame pointer elimination optimization"));
+
+static llvm::cl::opt<std::string>
+MFloatABI("mfloat-abi", llvm::cl::desc("The float ABI to use"));
+
+static llvm::cl::opt<std::string>
+MLimitFloatPrecision("mlimit-float-precision",
+ llvm::cl::desc("Limit float precision to the given value"));
+
+static llvm::cl::opt<bool>
+MNoZeroInitializedInBSS("mno-zero-initialized-in-bss",
+ llvm::cl::desc("Do not put zero initialized data in the BSS"));
+
+static llvm::cl::opt<bool>
+MSoftFloat("msoft-float", llvm::cl::desc("Use software floating point"));
+
+static llvm::cl::opt<std::string>
+MRelocationModel("mrelocation-model",
+ llvm::cl::desc("The relocation model to use"),
+ llvm::cl::init("pic"));
+
+static llvm::cl::opt<bool>
+MUnwindTables("munwind-tables",
+ llvm::cl::desc("Generate unwinding tables for all functions"));
+
+static llvm::cl::opt<std::string>
+MainFileName("main-file-name",
+ llvm::cl::desc("Main file name to use for debug info"));
+
+static llvm::cl::opt<bool>
NoCommon("fno-common",
llvm::cl::desc("Compile common globals like normal definitions"),
llvm::cl::ValueDisallowed);
@@ -436,6 +477,8 @@ TimeReport("ftime-report",
namespace langoptions {
+using namespace clang::frontend;
+
static llvm::cl::opt<bool>
NoBuiltin("fno-builtin",
llvm::cl::desc("Disable implicit builtin knowledge of functions"));
@@ -448,8 +491,8 @@ AccessControl("faccess-control",
llvm::cl::desc("Enable C++ access control"));
static llvm::cl::opt<bool>
-CharIsSigned("fsigned-char",
- llvm::cl::desc("Force char to be a signed/unsigned type"));
+NoSignedChar("fno-signed-char",
+ llvm::cl::desc("Char is unsigned"));
static llvm::cl::opt<bool>
DollarsInIdents("fdollars-in-identifiers",
@@ -481,42 +524,12 @@ GNURuntime("fgnu-runtime",
llvm::cl::desc("Generate output compatible with the standard GNU "
"Objective-C runtime"));
-/// LangStds - Language standards we support.
-enum LangStds {
- lang_unspecified,
- lang_c89, lang_c94, lang_c99,
- lang_gnu89, lang_gnu99,
- lang_cxx98, lang_gnucxx98,
- lang_cxx0x, lang_gnucxx0x
-};
-static llvm::cl::opt<LangStds>
+static llvm::cl::opt<LangStandard::Kind>
LangStd("std", llvm::cl::desc("Language standard to compile for"),
- llvm::cl::init(lang_unspecified),
- llvm::cl::values(clEnumValN(lang_c89, "c89", "ISO C 1990"),
- clEnumValN(lang_c89, "c90", "ISO C 1990"),
- clEnumValN(lang_c89, "iso9899:1990", "ISO C 1990"),
- clEnumValN(lang_c94, "iso9899:199409",
- "ISO C 1990 with amendment 1"),
- clEnumValN(lang_c99, "c99", "ISO C 1999"),
- clEnumValN(lang_c99, "c9x", "ISO C 1999"),
- clEnumValN(lang_c99, "iso9899:1999", "ISO C 1999"),
- clEnumValN(lang_c99, "iso9899:199x", "ISO C 1999"),
- clEnumValN(lang_gnu89, "gnu89",
- "ISO C 1990 with GNU extensions"),
- clEnumValN(lang_gnu99, "gnu99",
- "ISO C 1999 with GNU extensions (default for C)"),
- clEnumValN(lang_gnu99, "gnu9x",
- "ISO C 1999 with GNU extensions"),
- clEnumValN(lang_cxx98, "c++98",
- "ISO C++ 1998 with amendments"),
- clEnumValN(lang_gnucxx98, "gnu++98",
- "ISO C++ 1998 with amendments and GNU "
- "extensions (default for C++)"),
- clEnumValN(lang_cxx0x, "c++0x",
- "Upcoming ISO C++ 200x with amendments"),
- clEnumValN(lang_gnucxx0x, "gnu++0x",
- "Upcoming ISO C++ 200x with amendments and GNU "
- "extensions"),
+ llvm::cl::init(LangStandard::lang_unspecified), llvm::cl::values(
+#define LANGSTANDARD(id, name, desc, features) \
+ clEnumValN(LangStandard::lang_##id, name, desc),
+#include "clang/Frontend/LangStandards.def"
clEnumValEnd));
static llvm::cl::opt<bool>
@@ -524,10 +537,6 @@ MSExtensions("fms-extensions",
llvm::cl::desc("Accept some non-standard constructs used in "
"Microsoft header files "));
-static llvm::cl::opt<std::string>
-MainFileName("main-file-name",
- llvm::cl::desc("Main file name to use for debug info"));
-
static llvm::cl::opt<bool>
NoMathErrno("fno-math-errno",
llvm::cl::desc("Don't require math functions to respect errno"));
@@ -745,6 +754,7 @@ DumpDefines("dD", llvm::cl::desc("Print macro definitions in -E mode in "
"addition to normal output"));
}
+
//===----------------------------------------------------------------------===//
// Target Options
//===----------------------------------------------------------------------===//
@@ -757,7 +767,7 @@ TargetABI("target-abi",
static llvm::cl::opt<std::string>
TargetCPU("mcpu",
- llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)"));
+ llvm::cl::desc("Target a specific cpu type ('-mcpu help' for details)"));
static llvm::cl::list<std::string>
TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes"));
@@ -791,8 +801,7 @@ void clang::InitializeAnalyzerOptions(AnalyzerOptions &Opts) {
}
void clang::InitializeCodeGenOptions(CodeGenOptions &Opts,
- const LangOptions &Lang,
- bool TimePasses) {
+ const LangOptions &Lang) {
using namespace codegenoptions;
// -Os implies -O2
@@ -810,19 +819,27 @@ void clang::InitializeCodeGenOptions(CodeGenOptions &Opts,
Opts.NoCommon = NoCommon;
Opts.NoImplicitFloat = NoImplicitFloat;
Opts.OptimizeSize = OptSize;
- Opts.SimplifyLibCalls = 1;
Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize);
- // FIXME: Eliminate this dependency?
- if (Lang.NoBuiltin)
- Opts.SimplifyLibCalls = 0;
- if (Lang.CPlusPlus)
- Opts.NoCommon = 1;
- Opts.TimePasses = TimePasses;
+ // LLVM Code Generator options.
+
+ Opts.AsmVerbose = MAsmVerbose;
+ Opts.CodeModel = MCodeModel;
+ Opts.DebugPass = MDebugPass;
+ Opts.DisableFPElim = MDisableFPElim;
+ Opts.FloatABI = MFloatABI;
+ Opts.LimitFloatPrecision = MLimitFloatPrecision;
+ Opts.NoZeroInitializedInBSS = MNoZeroInitializedInBSS;
+ Opts.SoftFloat = MSoftFloat;
+ Opts.RelocationModel = MRelocationModel;
+ Opts.UnwindTables = MUnwindTables;
#ifdef NDEBUG
Opts.VerifyModule = 0;
#endif
+
+ if (MainFileName.getPosition())
+ Opts.MainFileName = MainFileName;
}
void clang::InitializeDependencyOutputOptions(DependencyOutputOptions &Opts) {
@@ -857,13 +874,8 @@ void clang::InitializeDiagnosticOptions(DiagnosticOptions &Opts) {
void clang::InitializeFrontendOptions(FrontendOptions &Opts) {
using namespace frontendoptions;
- // Select program action.
Opts.ProgramAction = ProgAction;
- if (PluginActionName.getPosition()) {
- Opts.ProgramAction = frontend::PluginAction;
- Opts.ActionName = PluginActionName;
- }
-
+ Opts.ActionName = PluginActionName;
Opts.CodeCompletionAt = CodeCompletionAt;
Opts.DebugCodeCompletionPrinter = !NoCodeCompletionDebugPrinter;
Opts.DisableFree = DisableFree;
@@ -876,6 +888,14 @@ void clang::InitializeFrontendOptions(FrontendOptions &Opts) {
Opts.ShowTimers = TimeReport;
Opts.ViewClassInheritance = InheritanceViewCls;
+ // Enforce certain program action implications.
+ if (!Opts.ActionName.empty())
+ Opts.ProgramAction = frontend::PluginAction;
+ if (!Opts.ViewClassInheritance.empty())
+ Opts.ProgramAction = frontend::InheritanceView;
+ if (!Opts.FixItLocations.empty())
+ Opts.ProgramAction = frontend::FixIt;
+
// '-' is the default input if none is given.
if (InputFilenames.empty()) {
FrontendOptions::InputKind IK = InputType;
@@ -1054,145 +1074,87 @@ void clang::InitializePreprocessorOptions(PreprocessorOptions &Opts) {
}
void clang::InitializeLangOptions(LangOptions &Options,
- FrontendOptions::InputKind IK,
- TargetInfo &Target) {
+ FrontendOptions::InputKind IK) {
using namespace langoptions;
-
- switch (IK) {
- case FrontendOptions::IK_None:
- case FrontendOptions::IK_AST:
- assert(0 && "Invalid input kind!");
- case FrontendOptions::IK_Asm:
+ // 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) {
Options.AsmPreprocessor = 1;
- // FALLTHROUGH
- case FrontendOptions::IK_PreprocessedC:
- // FALLTHROUGH
- case FrontendOptions::IK_C:
- // Do nothing.
- break;
- case FrontendOptions::IK_PreprocessedCXX:
- // FALLTHROUGH
- case FrontendOptions::IK_CXX:
- Options.CPlusPlus = 1;
- break;
- case FrontendOptions::IK_PreprocessedObjC:
- // FALLTHROUGH
- case FrontendOptions::IK_ObjC:
+ } else if (IK == FrontendOptions::IK_ObjC ||
+ IK == FrontendOptions::IK_ObjCXX ||
+ IK == FrontendOptions::IK_PreprocessedObjC ||
+ IK == FrontendOptions::IK_PreprocessedObjCXX) {
Options.ObjC1 = Options.ObjC2 = 1;
- break;
- case FrontendOptions::IK_PreprocessedObjCXX:
- // FALLTHROUGH
- case FrontendOptions::IK_ObjCXX:
- Options.ObjC1 = Options.ObjC2 = 1;
- Options.CPlusPlus = 1;
- break;
- case FrontendOptions::IK_OpenCL:
- Options.OpenCL = 1;
- Options.AltiVec = 1;
- Options.CXXOperatorNames = 1;
- Options.LaxVectorConversions = 1;
- break;
}
- if (ObjCExclusiveGC)
- Options.setGCMode(LangOptions::GCOnly);
- else if (ObjCEnableGC)
- Options.setGCMode(LangOptions::HybridGC);
-
- if (ObjCEnableGCBitmapPrint)
- Options.ObjCGCBitmapPrint = 1;
-
- if (AltiVec)
- Options.AltiVec = 1;
-
- if (PThread)
- Options.POSIXThreads = 1;
-
- Options.setVisibilityMode(SymbolVisibility);
- Options.OverflowChecking = OverflowChecking;
-
- if (LangStd == lang_unspecified) {
+ 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 = lang_c99;
+ 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 = lang_gnu99;
+ LangStd = LangStandard::lang_gnu99;
break;
case FrontendOptions::IK_CXX:
case FrontendOptions::IK_PreprocessedCXX:
case FrontendOptions::IK_ObjCXX:
case FrontendOptions::IK_PreprocessedObjCXX:
- LangStd = lang_gnucxx98;
+ LangStd = LangStandard::lang_gnucxx98;
break;
}
}
- switch (LangStd) {
- default: assert(0 && "Unknown language standard!");
-
- // Fall through from newer standards to older ones. This isn't really right.
- // FIXME: Enable specifically the right features based on the language stds.
- case lang_gnucxx0x:
- case lang_cxx0x:
- Options.CPlusPlus0x = 1;
- // FALL THROUGH
- case lang_gnucxx98:
- case lang_cxx98:
- Options.CPlusPlus = 1;
- Options.CXXOperatorNames = !NoOperatorNames;
- // FALL THROUGH.
- case lang_gnu99:
- case lang_c99:
- Options.C99 = 1;
- Options.HexFloats = 1;
- // FALL THROUGH.
- case lang_gnu89:
- Options.BCPLComment = 1; // Only for C99/C++.
- // FALL THROUGH.
- case lang_c94:
- Options.Digraphs = 1; // C94, C99, C++.
- // FALL THROUGH.
- case lang_c89:
- break;
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Options.BCPLComment = Std.hasBCPLComments();
+ Options.C99 = Std.isC99();
+ Options.CPlusPlus = Std.isCPlusPlus();
+ Options.CPlusPlus0x = Std.isCPlusPlus0x();
+ Options.Digraphs = Std.hasDigraphs();
+ Options.GNUInline = !Std.isC99();
+ Options.GNUMode = Std.isGNUMode();
+ Options.HexFloats = Std.hasHexFloats();
+ Options.ImplicitInt = Std.hasImplicitInt();
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl) {
+ Options.OpenCL = 1;
+ Options.AltiVec = 1;
+ Options.CXXOperatorNames = 1;
+ Options.LaxVectorConversions = 1;
}
- // GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
- switch (LangStd) {
- default: assert(0 && "Unknown language standard!");
- case lang_gnucxx0x:
- case lang_gnucxx98:
- case lang_gnu99:
- case lang_gnu89:
- Options.GNUMode = 1;
- break;
- case lang_cxx0x:
- case lang_cxx98:
- case lang_c99:
- case lang_c94:
- case lang_c89:
- Options.GNUMode = 0;
- break;
- }
+ // OpenCL and C++ both have bool, true, false keywords.
+ Options.Bool = Options.OpenCL || Options.CPlusPlus;
- if (Options.CPlusPlus) {
- Options.C99 = 0;
- Options.HexFloats = 0;
- }
+ if (Options.CPlusPlus)
+ Options.CXXOperatorNames = !NoOperatorNames;
- if (LangStd == lang_c89 || LangStd == lang_c94 || LangStd == lang_gnu89)
- Options.ImplicitInt = 1;
- else
- Options.ImplicitInt = 0;
+ if (ObjCExclusiveGC)
+ Options.setGCMode(LangOptions::GCOnly);
+ else if (ObjCEnableGC)
+ Options.setGCMode(LangOptions::HybridGC);
+
+ if (ObjCEnableGCBitmapPrint)
+ Options.ObjCGCBitmapPrint = 1;
+
+ if (AltiVec)
+ Options.AltiVec = 1;
+
+ if (PThread)
+ Options.POSIXThreads = 1;
+
+ Options.setVisibilityMode(SymbolVisibility);
+ Options.OverflowChecking = OverflowChecking;
// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
// is specified, or -std is set to a conforming mode.
@@ -1200,17 +1162,8 @@ void clang::InitializeLangOptions(LangOptions &Options,
if (Trigraphs.getPosition())
Options.Trigraphs = Trigraphs; // Command line option wins if specified.
- // If in a conformant language mode (e.g. -std=c99) Blocks defaults to off
- // even if they are normally on for the target. In GNU modes (e.g.
- // -std=gnu99) the default for blocks depends on the target settings.
- // However, blocks are not turned off when compiling Obj-C or Obj-C++ code.
- if (!Options.ObjC1 && !Options.GNUMode)
- Options.Blocks = 0;
-
- // Default to not accepting '$' in identifiers when preprocessing assembler,
- // but do accept when preprocessing C. FIXME: these defaults are right for
- // darwin, are they right everywhere?
- Options.DollarIdents = IK != FrontendOptions::IK_Asm;
+ // Default to not accepting '$' in identifiers when preprocessing assembler.
+ Options.DollarIdents = !Options.AsmPreprocessor;
if (DollarsInIdents.getPosition()) // Explicit setting overrides default.
Options.DollarIdents = DollarsInIdents;
@@ -1223,10 +1176,8 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.LaxVectorConversions = 0;
Options.Exceptions = Exceptions;
Options.Rtti = !NoRtti;
- if (EnableBlocks.getPosition())
- Options.Blocks = EnableBlocks;
- if (CharIsSigned.getPosition())
- Options.CharIsSigned = CharIsSigned;
+ Options.Blocks = EnableBlocks;
+ Options.CharIsSigned = !NoSignedChar;
if (ShortWChar.getPosition())
Options.ShortWChar = ShortWChar;
@@ -1242,9 +1193,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.ElideConstructors = !NoElideConstructors;
- // OpenCL and C++ both have bool, true, false keywords.
- Options.Bool = Options.OpenCL | Options.CPlusPlus;
-
Options.MathErrno = !NoMathErrno;
if (TemplateDepth.getPosition())
@@ -1255,7 +1203,7 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.NeXTRuntime = 0;
if (!ObjCConstantStringClass.empty())
- Options.ObjCConstantStringClass = ObjCConstantStringClass.c_str();
+ Options.ObjCConstantStringClass = ObjCConstantStringClass;
if (ObjCNonFragileABI)
Options.ObjCNonFragileABI = 1;
@@ -1272,8 +1220,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
assert(PICLevel <= 2 && "Invalid value for -pic-level");
Options.PICLevel = PICLevel;
- Options.GNUInline = !Options.C99;
-
// 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.
@@ -1292,11 +1238,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
case 2: Options.setStackProtectorMode(LangOptions::SSPReq); break;
}
}
-
- if (MainFileName.getPosition())
- Options.setMainFileName(MainFileName.c_str());
-
- Target.setForcedLangOptions(Options);
}
void
diff --git a/tools/clang-cc/Options.h b/tools/clang-cc/Options.h
index 9a2fd9d59a16..91e37f261103 100644
--- a/tools/clang-cc/Options.h
+++ b/tools/clang-cc/Options.h
@@ -30,8 +30,7 @@ class TargetOptions;
void InitializeAnalyzerOptions(AnalyzerOptions &Opts);
void InitializeCodeGenOptions(CodeGenOptions &Opts,
- const LangOptions &Lang,
- bool TimePasses);
+ const LangOptions &Lang);
void InitializeDependencyOutputOptions(DependencyOutputOptions &Opts);
@@ -42,9 +41,7 @@ void InitializeFrontendOptions(FrontendOptions &Opts);
void InitializeHeaderSearchOptions(HeaderSearchOptions &Opts,
llvm::StringRef BuiltinIncludePath);
-void InitializeLangOptions(LangOptions &Options,
- FrontendOptions::InputKind LK,
- TargetInfo &Target);
+void InitializeLangOptions(LangOptions &Options, FrontendOptions::InputKind LK);
void InitializePreprocessorOptions(PreprocessorOptions &Opts);
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
index bae8697e14bd..2899684284a9 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -21,11 +21,18 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.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/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/VerifyDiagnosticsClient.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/OwningPtr.h"
@@ -39,6 +46,7 @@
#include "llvm/System/Path.h"
#include "llvm/System/Signals.h"
#include "llvm/Target/TargetSelect.h"
+#include <cstdio>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -73,11 +81,6 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-/// ClangFrontendTimer - The front-end activities should charge time to it with
-/// TimeRegion. The -ftime-report option controls whether this will do
-/// anything.
-llvm::Timer *ClangFrontendTimer = 0;
-
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
using namespace clang::frontend;
@@ -139,18 +142,11 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
}
}
-static TargetInfo *
-ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
- const char *Argv0, bool &IsAST) {
+static bool ConstructCompilerInvocation(CompilerInvocation &Opts,
+ Diagnostic &Diags, const char *Argv0) {
// Initialize target options.
InitializeTargetOptions(Opts.getTargetOpts());
- // Get information about the target being compiled for.
- llvm::OwningPtr<TargetInfo> Target(
- TargetInfo::CreateTargetInfo(Diags, Opts.getTargetOpts()));
- if (!Target)
- return 0;
-
// Initialize frontend options.
InitializeFrontendOptions(Opts.getFrontendOpts());
@@ -160,7 +156,7 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
if (Opts.getFrontendOpts().Inputs[i].first != IK) {
llvm::errs() << "error: cannot have multiple input files of distinct "
<< "language kinds without -x\n";
- return 0;
+ return false;
}
}
@@ -168,9 +164,8 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
//
// FIXME: These aren't used during operations on ASTs. Split onto a separate
// code path to make this obvious.
- IsAST = (IK == FrontendOptions::IK_AST);
- if (!IsAST)
- InitializeLangOptions(Opts.getLangOpts(), IK, *Target);
+ if (IK != FrontendOptions::IK_AST)
+ InitializeLangOptions(Opts.getLangOpts(), IK);
// Initialize the static analyzer options.
InitializeAnalyzerOptions(Opts.getAnalyzerOpts());
@@ -188,12 +183,78 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
// Initialize the preprocessed output options.
InitializePreprocessorOutputOptions(Opts.getPreprocessorOutputOpts());
- // Initialize backend options, which may also be used to key some language
- // options.
- InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts(),
- Opts.getFrontendOpts().ShowTimers);
+ // Initialize backend options.
+ InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts());
+
+ return true;
+}
+
+static int cc1_main(Diagnostic &Diags,
+ const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
+ using namespace clang::driver;
+
+ llvm::errs() << "cc1 argv:";
+ for (const char **i = ArgBegin; i != ArgEnd; ++i)
+ llvm::errs() << " \"" << *i << '"';
+ llvm::errs() << "\n";
+
+ // Parse the arguments.
+ OptTable *Opts = createCC1OptTable();
+ unsigned MissingArgIndex, MissingArgCount;
+ InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
+ MissingArgIndex, MissingArgCount);
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(clang::diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Dump the parsed arguments.
+ llvm::errs() << "cc1 parsed options:\n";
+ for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
+ it != ie; ++it)
+ (*it)->dump();
+
+ // Create a compiler invocation.
+ llvm::errs() << "cc1 creating invocation.\n";
+ CompilerInvocation Invocation;
+ CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd,
+ Argv0, MainAddr, Diags);
+
+ // Convert the invocation back to argument strings.
+ std::vector<std::string> InvocationArgs;
+ Invocation.toArgs(InvocationArgs);
+
+ // Dump the converted arguments.
+ llvm::SmallVector<const char*, 32> Invocation2Args;
+ llvm::errs() << "invocation argv :";
+ for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
+ Invocation2Args.push_back(InvocationArgs[i].c_str());
+ llvm::errs() << " \"" << InvocationArgs[i] << '"';
+ }
+ llvm::errs() << "\n";
+
+ // Convert those arguments to another invocation, and check that we got the
+ // same thing.
+ CompilerInvocation Invocation2;
+ CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
+ Invocation2Args.end(), Argv0, MainAddr,
+ Diags);
+
+ // FIXME: Implement CompilerInvocation comparison.
+ if (true) {
+ //llvm::errs() << "warning: Invocations differ!\n";
+
+ std::vector<std::string> Invocation2Args;
+ Invocation2.toArgs(Invocation2Args);
+ llvm::errs() << "invocation2 argv:";
+ for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
+ llvm::errs() << " \"" << Invocation2Args[i] << '"';
+ llvm::errs() << "\n";
+ }
- return Target.take();
+ return 0;
}
int main(int argc, char **argv) {
@@ -201,10 +262,19 @@ int main(int argc, char **argv) {
llvm::PrettyStackTraceProgram X(argc, argv);
CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ // Run clang -cc1 test.
+ if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1") {
+ TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
+ Diagnostic Diags(&DiagClient);
+ return cc1_main(Diags, (const char**) argv + 2, (const char**) argv + argc,
+ argv[0], (void*) (intptr_t) GetBuiltinIncludePath);
+ }
+
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
+#if 1
llvm::cl::ParseCommandLineOptions(argc, argv,
"LLVM 'Clang' Compiler: http://clang.llvm.org\n");
@@ -225,13 +295,49 @@ int main(int argc, char **argv) {
//
// FIXME: We should move .ast inputs to taking a separate path, they are
// really quite different.
- bool IsAST = false;
- Clang.setTarget(
- ConstructCompilerInvocation(Clang.getInvocation(), Clang.getDiagnostics(),
- argv[0], IsAST));
+ if (!ConstructCompilerInvocation(Clang.getInvocation(),
+ Clang.getDiagnostics(), argv[0]))
+ return 1;
+#else
+ // Buffer diagnostics from argument parsing.
+ TextDiagnosticBuffer DiagsBuffer;
+ Diagnostic Diags(&DiagsBuffer);
+
+ CompilerInvocation::CreateFromArgs(Clang.getInvocation(),
+ (const char**) argv + 1,
+ (const char**) argv + argc, argv[0],
+ (void*)(intptr_t) GetBuiltinIncludePath,
+ Diags);
+
+ // Create the actual diagnostics engine.
+ Clang.createDiagnostics(argc, argv);
+ if (!Clang.hasDiagnostics())
+ return 1;
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ llvm::llvm_install_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Clang.getDiagnostics()));
+
+ DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics());
+
+ // If there were any errors in processing arguments, exit now.
+ if (Clang.getDiagnostics().getNumErrors())
+ return 1;
+#endif
+
+ // Create the target instance.
+ Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+ Clang.getTargetOpts()));
if (!Clang.hasTarget())
return 1;
+ // 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());
+
// Validate/process some options
if (Clang.getHeaderSearchOpts().Verbose)
llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
@@ -239,19 +345,15 @@ int main(int argc, char **argv) {
<< " hosted on " << llvm::sys::getHostTriple() << "\n";
if (Clang.getFrontendOpts().ShowTimers)
- ClangFrontendTimer = new llvm::Timer("Clang front-end time");
-
- // Enforce certain implications.
- if (!Clang.getFrontendOpts().ViewClassInheritance.empty())
- Clang.getFrontendOpts().ProgramAction = frontend::InheritanceView;
- if (!Clang.getFrontendOpts().FixItLocations.empty())
- Clang.getFrontendOpts().ProgramAction = frontend::FixIt;
+ Clang.createFrontendTimer();
for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) {
const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second;
// If we aren't using an AST file, setup the file and source managers and
// the preprocessor.
+ bool IsAST =
+ Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST;
if (!IsAST) {
if (!i) {
// Create a file manager object to provide access to and cache the
@@ -273,7 +375,6 @@ int main(int argc, char **argv) {
if (!Act)
break;
- Act->setCurrentTimer(ClangFrontendTimer);
if (Act->BeginSourceFile(Clang, InFile, IsAST)) {
Act->Execute();
Act->EndSourceFile();
@@ -290,8 +391,6 @@ int main(int argc, char **argv) {
fprintf(stderr, "\n");
}
- delete ClangFrontendTimer;
-
// Return the appropriate status when verifying diagnostics.
//
// FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 1a9538013e1b..790021181839 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -3,7 +3,6 @@ set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
clangDriver
clangBasic
- clangFrontend
)
set(LLVM_LINK_COMPONENTS system support bitreader bitwriter)
@@ -15,9 +14,15 @@ add_clang_executable(clang
add_dependencies(clang clang-cc)
+if(UNIX)
+ set(CLANGXX_LINK_OR_COPY create_symlink)
+else()
+ set(CLANGXX_LINK_OR_COPY copy)
+endif()
+
# Create the clang++ symlink in the build directory.
add_custom_target(clang++ ALL
- ${CMAKE_COMMAND} -E create_symlink
+ ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY}
"${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}"
"${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}"
DEPENDS clang)
@@ -26,4 +31,4 @@ install(TARGETS clang
RUNTIME DESTINATION bin)
# Create the clang++ symlink at installation time.
-install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
+install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 19f93a29fa1c..f250651ed7e2 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -19,7 +19,7 @@ TOOL_NO_EXPORTS = 1
# FIXME: It is unfortunate we need to pull in the bitcode reader and
# writer just to get the serializer stuff used by clangBasic.
LINK_COMPONENTS := system support bitreader bitwriter
-USEDLIBS = clangDriver.a clangBasic.a clangFrontend.a
+USEDLIBS = clangDriver.a clangBasic.a
include $(LEVEL)/Makefile.common
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index c5163592b42a..a9d27efb1c3b 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -11,78 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#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 "llvm/Support/raw_ostream.h"
-#include <cstdlib>
-#include <vector>
-using namespace clang;
-using namespace clang::driver;
-
-int cc1_main(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) {
+int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
llvm::errs() << "cc1 argv:";
for (const char **i = ArgBegin; i != ArgEnd; ++i)
llvm::errs() << " \"" << *i << '"';
llvm::errs() << "\n";
- // Parse the arguments.
- OptTable *Opts = createCC1OptTable();
- unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
- MissingArgIndex, MissingArgCount);
-
- // Check for missing argument error.
- if (MissingArgCount)
- Diags.Report(clang::diag::err_drv_missing_argument)
- << Args->getArgString(MissingArgIndex) << MissingArgCount;
-
- // Dump the parsed arguments.
- llvm::errs() << "cc1 parsed options:\n";
- for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
- it != ie; ++it)
- (*it)->dump();
-
- // Create a compiler invocation.
- llvm::errs() << "cc1 creating invocation.\n";
- CompilerInvocation Invocation;
- CompilerInvocation::CreateFromArgs(Invocation,
- llvm::SmallVector<llvm::StringRef, 32>(ArgBegin, ArgEnd));
-
- // Convert the invocation back to argument strings.
- std::vector<std::string> InvocationArgs;
- Invocation.toArgs(InvocationArgs);
-
- // Dump the converted arguments.
- llvm::SmallVector<llvm::StringRef, 32> Invocation2Args;
- llvm::errs() << "invocation argv:";
- for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
- Invocation2Args.push_back(InvocationArgs[i]);
- llvm::errs() << " \"" << InvocationArgs[i] << '"';
- }
- llvm::errs() << "\n";
-
- // Convert those arguments to another invocation, and check that we got the
- // same thing.
- CompilerInvocation Invocation2;
- CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args);
-
- // FIXME: Implement CompilerInvocation comparison.
- if (memcmp(&Invocation, &Invocation2, sizeof(Invocation)) != 0) {
- llvm::errs() << "warning: Invocations differ!\n";
-
- std::vector<std::string> Invocation2Args;
- Invocation2.toArgs(Invocation2Args);
- llvm::errs() << "invocation argv:";
- for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
- llvm::errs() << " \"" << Invocation2Args[i] << '"';
- llvm::errs() << "\n";
- }
-
return 0;
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index dbfc29365561..c61ee726449f 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -178,22 +178,23 @@ void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
}
}
-extern int cc1_main(Diagnostic &Diags,
- const char **ArgBegin, const char **ArgEnd);
+extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr);
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
+ // Dispatch to cc1_main if appropriate.
+ if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1")
+ return cc1_main(argv+2, argv+argc, argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+
llvm::sys::Path Path = GetExecutablePath(argv[0]);
DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs());
Diagnostic Diags(&DiagClient);
- // Dispatch to cc1_main if appropriate.
- if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1")
- return cc1_main(Diags, argv+2, argv+argc);
-
#ifdef CLANG_IS_PRODUCTION
bool IsProduction = true;
#else
@@ -208,7 +209,9 @@ int main(int argc, const char **argv) {
//
// Note that we intentionally want to use argv[0] here, to support "clang++"
// being a symlink.
- std::string ProgName(llvm::sys::Path(argv[0]).getBasename());
+ //
+ // We use *argv instead of argv[0] to work around a bogus g++ warning.
+ std::string ProgName(llvm::sys::Path(*argv).getBasename());
if (llvm::StringRef(ProgName).endswith("++") ||
llvm::StringRef(ProgName).rsplit('-').first.endswith("++"))
TheDriver.CCCIsCXX = true;
diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt
index 9c9656a1130e..163afc4ac9f5 100644
--- a/tools/index-test/CMakeLists.txt
+++ b/tools/index-test/CMakeLists.txt
@@ -3,8 +3,10 @@ set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
clangIndex
clangFrontend
+ clangAnalysis
clangSema
clangAST
+ clangParse
clangLex
clangBasic
)
diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile
index 76602e1d278d..8e7bfe554009 100644
--- a/tools/index-test/Makefile
+++ b/tools/index-test/Makefile
@@ -19,6 +19,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := bitreader mc
-USEDLIBS = clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a clangSema.a \
+ clangAST.a clangParse.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp
index fce48edf26e0..dd7cbb21642c 100644
--- a/tools/index-test/index-test.cpp
+++ b/tools/index-test/index-test.cpp
@@ -43,6 +43,10 @@
#include "clang/Index/Analyzer.h"
#include "clang/Index/Utils.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
@@ -202,9 +206,24 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
}
}
+static llvm::cl::opt<bool>
+ASTFromSource("ast-from-source",
+ llvm::cl::desc("Treat the inputs as source files to parse."));
+
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
+void CreateCompilerInvocation(const std::string &Filename,
+ CompilerInvocation &CI, Diagnostic &Diags,
+ const char *argv0) {
+ llvm::SmallVector<const char *, 16> Args;
+ Args.push_back(Filename.c_str());
+
+ void *MainAddr = (void*) (intptr_t) CreateCompilerInvocation;
+ CompilerInvocation::CreateFromArgs(CI, Args.data(), Args.data() + Args.size(),
+ argv0, MainAddr, Diags);
+}
+
int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
@@ -215,6 +234,10 @@ int main(int argc, char **argv) {
Indexer Idxer(Prog);
llvm::SmallVector<TUnit*, 4> TUnits;
+ TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions(), false);
+ llvm::OwningPtr<Diagnostic> Diags(
+ CompilerInstance::createDiagnostics(DiagnosticOptions(), argc, argv));
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
@@ -225,7 +248,15 @@ int main(int argc, char **argv) {
std::string ErrMsg;
llvm::OwningPtr<ASTUnit> AST;
- AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));
+ if (ASTFromSource) {
+ CompilerInvocation CI;
+ CreateCompilerInvocation(InFile, CI, *Diags, argv[0]);
+ AST.reset(ASTUnit::LoadFromCompilerInvocation(CI, *Diags));
+ if (!AST)
+ ErrMsg = "unable to create AST";
+ } else
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));
+
if (!AST) {
llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
return 1;
diff --git a/utils/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 25b980057408..25b980057408 100755
--- a/utils/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
diff --git a/utils/scan-build b/tools/scan-build/scan-build
index ca95676ca338..8d99f070eae9 100755
--- a/utils/scan-build
+++ b/tools/scan-build/scan-build
@@ -131,7 +131,7 @@ while(<PIPE>) {
if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
next if ($1 =~ /-dump/ or $1 =~ /-view/
- or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
+ or $1 =~ /-warn-uninit/);
$AvailableAnalyses{$1} = $2;
next;
diff --git a/utils/scanview.css b/tools/scan-build/scanview.css
index a0406f37a038..a0406f37a038 100644
--- a/utils/scanview.css
+++ b/tools/scan-build/scanview.css
diff --git a/utils/sorttable.js b/tools/scan-build/sorttable.js
index 4352d3be0a5f..4352d3be0a5f 100644
--- a/utils/sorttable.js
+++ b/tools/scan-build/sorttable.js
diff --git a/tools/wpa/CMakeLists.txt b/tools/wpa/CMakeLists.txt
deleted file mode 100644
index 5553474b4bcd..000000000000
--- a/tools/wpa/CMakeLists.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-set(LLVM_NO_RTTI 1)
-
-set( LLVM_USED_LIBS
- clangFrontend
- clangAnalysis
- clangSema
- clangAST
- clangLex
- clangBasic
- clangIndex
- )
-
-set( LLVM_LINK_COMPONENTS
- mc
- )
-
-add_clang_executable(clang-wpa
- clang-wpa.cpp
- )
-add_dependencies(clang-wpa clang-headers)
diff --git a/tools/wpa/Makefile b/tools/wpa/Makefile
deleted file mode 100644
index 01dbd11b8df5..000000000000
--- a/tools/wpa/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-LEVEL = ../../../..
-
-TOOLNAME = clang-wpa
-CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-CXXFLAGS = -fno-rtti
-NO_INSTALL = 1
-
-# No plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.config
-
-LINK_COMPONENTS := bitreader mc
-USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a clangAnalysis.a clangIndex.a
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/wpa/clang-wpa.cpp b/tools/wpa/clang-wpa.cpp
deleted file mode 100644
index 346634b6f617..000000000000
--- a/tools/wpa/clang-wpa.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This tool reads a sequence of precompiled AST files, and do various
-// cross translation unit analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/CallGraph.h"
-#include "clang/Frontend/ASTUnit.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/TextDiagnosticBuffer.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-using namespace idx;
-
-static llvm::cl::list<std::string>
-InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
-
-int main(int argc, char **argv) {
- llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
- FileManager FileMgr;
- std::vector<ASTUnit*> ASTUnits;
-
- if (InputFilenames.empty())
- return 0;
-
- TextDiagnosticBuffer DiagClient;
- Diagnostic Diags(&DiagClient);
-
- for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
- const std::string &InFile = InputFilenames[i];
-
- std::string ErrMsg;
- llvm::OwningPtr<ASTUnit> AST;
-
- AST.reset(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr, &ErrMsg));
-
- if (!AST) {
- llvm::errs() << "[" << InFile << "] error: " << ErrMsg << '\n';
- return 1;
- }
-
- ASTUnits.push_back(AST.take());
- }
-
- llvm::OwningPtr<CallGraph> CG;
- CG.reset(new CallGraph());
-
- for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
- CG->addTU(ASTUnits[i]->getASTContext());
-
- CG->ViewCallGraph();
-}
diff --git a/utils/C++Tests/Clang-Code-Compile/lit.local.cfg b/utils/C++Tests/Clang-Code-Compile/lit.local.cfg
index d9e39e5d3f8d..59d346665cbe 100644
--- a/utils/C++Tests/Clang-Code-Compile/lit.local.cfg
+++ b/utils/C++Tests/Clang-Code-Compile/lit.local.cfg
@@ -18,7 +18,7 @@ cxxflags = ['-D__STDC_LIMIT_MACROS',
'-I%s/tools/clang/include' % root.llvm_src_root,
'-I%s/tools/clang/include' % root.llvm_obj_root]
config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[root.clang, '-c',
+ lit.formats.OneCommandPerFileTest(command=[root.clang, '-emit-llvm', '-c',
'-o', '/dev/null'] + cxxflags,
dir='%s/tools/clang/lib' % root.llvm_src_root,
recursive=True,
diff --git a/utils/C++Tests/Clang-Syntax/lit.local.cfg b/utils/C++Tests/Clang-Syntax/lit.local.cfg
index 280d1c18a263..89fdd8e15997 100644
--- a/utils/C++Tests/Clang-Syntax/lit.local.cfg
+++ b/utils/C++Tests/Clang-Syntax/lit.local.cfg
@@ -17,6 +17,7 @@ config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
extra_cxx_args=['-D__STDC_LIMIT_MACROS',
'-D__STDC_CONSTANT_MACROS',
'-Wno-sign-compare',
+ '-Werror',
'-I%s/include' % root.llvm_src_root,
'-I%s/include' % root.llvm_obj_root,
'-I%s/tools/clang/include' % root.llvm_src_root,
diff --git a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
new file mode 100644
index 000000000000..fc493e480fda
--- /dev/null
+++ b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
@@ -0,0 +1,24 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+cxxflags = ['-D__STDC_LIMIT_MACROS',
+ '-D__STDC_CONSTANT_MACROS',
+ '-Wno-sign-compare',
+ '-I%s/include' % root.llvm_src_root,
+ '-I%s/include' % root.llvm_obj_root]
+config.test_format = \
+ lit.formats.OneCommandPerFileTest(command=[root.clang, '-emit-llvm', '-c',
+ '-o', '/dev/null'] + cxxflags,
+ dir='%s/lib' % root.llvm_src_root,
+ recursive=True,
+ pattern='^(.*\\.cpp)$')
+
diff --git a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
new file mode 100644
index 000000000000..67bc5aede63d
--- /dev/null
+++ b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
@@ -0,0 +1,23 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# testFormat: The test format to use to interpret tests.
+cxxflags = ['-D__STDC_LIMIT_MACROS',
+ '-D__STDC_CONSTANT_MACROS',
+ '-Wno-sign-compare',
+ '-I%s/include' % root.llvm_src_root,
+ '-I%s/include' % root.llvm_obj_root]
+config.test_format = \
+ lit.formats.OneCommandPerFileTest(command=[root.clang,
+ '-fsyntax-only'] + cxxflags,
+ dir='%s/lib' % root.llvm_src_root,
+ recursive=True,
+ pattern='^(.*\\.cpp)$')
diff --git a/utils/C++Tests/LLVM-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
index 25728bc39f47..b67bb907e26b 100644
--- a/utils/C++Tests/LLVM-Syntax/lit.local.cfg
+++ b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
@@ -17,8 +17,9 @@ config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
extra_cxx_args=['-D__STDC_LIMIT_MACROS',
'-D__STDC_CONSTANT_MACROS',
'-Wno-sign-compare',
+ '-Werror',
'-I%s/include' % root.llvm_src_root,
'-I%s/include' % root.llvm_obj_root])
config.excludes = ['AbstractTypeUser.h', 'DAGISelHeader.h',
- 'AIXDataTypesFix.h', 'Solaris.h']
+ 'AIXDataTypesFix.h', 'LinkAllPasses.h', 'Solaris.h']
diff --git a/utils/C++Tests/lit.cfg b/utils/C++Tests/lit.cfg
index aa3b09d50a4c..e61502b62edd 100644
--- a/utils/C++Tests/lit.cfg
+++ b/utils/C++Tests/lit.cfg
@@ -17,14 +17,10 @@ config.suffixes = []
# Reset these from the Clang config.
config.test_source_root = config.test_exec_root = None
-# Don't run Clang checks by default.
+# Don't run Clang and LLVM code checks by default.
config.excludes = []
-if (not lit.params.get('run_clang_syntax') and
- not lit.params.get('run_clang_all')):
- config.excludes.append('Clang-Syntax')
-if (not lit.params.get('run_clang_code_syntax') and
- not lit.params.get('run_clang_all')):
+if not lit.params.get('run_clang_all'):
config.excludes.append('Clang-Code-Syntax')
-if (not lit.params.get('run_clang_compile') and
- not lit.params.get('run_clang_all')):
config.excludes.append('Clang-Code-Compile')
+ config.excludes.append('LLVM-Code-Syntax')
+ config.excludes.append('LLVM-Code-Compile')
diff --git a/utils/ubiviz b/utils/analyzer/ubiviz
index 1582797c63f9..1582797c63f9 100755
--- a/utils/ubiviz
+++ b/utils/analyzer/ubiviz
diff --git a/www/analyzer/installation.html b/www/analyzer/installation.html
index 891353562136..81f45514fc01 100644
--- a/www/analyzer/installation.html
+++ b/www/analyzer/installation.html
@@ -100,7 +100,7 @@ the installation directory of your choice (specified when you run
programs.
<p>Currently these are not installed using <tt>make install</tt>, and
-are located in <tt>$(SRCDIR)/tools/clang/util</tt> and
+are located in <tt>$(SRCDIR)/tools/clang/tools/scan-build</tt> and
<tt>$(SRCDIR)/tools/clang/tools/scan-view</tt> respectively (where
<tt>$(SRCDIR)</tt> is the root LLVM source directory). These locations
are subject to change.</p></li>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index c45eebd430ff..c2238e4aab96 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://checker.minormatter.com/checker-227.tar.bz2">checker-227.tar.bz2</a></b> (built November 4, 2009)
+<b><a href="http://checker.minormatter.com/checker-228.tar.bz2">checker-228.tar.bz2</a></b> (built November 28, 2009)
diff --git a/www/cxx_status.html b/www/cxx_status.html
index e1df3befc5b7..0858db7567e9 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -24,7 +24,7 @@
<!--*************************************************************************-->
<h1>C++ Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2009-10-30 15:54:38 +0100 (Fri, 30 Oct 2009) $</p>
+<p>Last updated: $Date: 2009-11-20 23:00:06 +0100 (Fri, 20 Nov 2009) $</p>
<p>
This page tracks the status of C++ support in Clang.<br>
@@ -546,8 +546,7 @@ welcome!</p>
<td class="advanced" align="center"></td>
<td class="advanced" align="center"></td>
<td></td>
- <td>cannot parse operator-function-ids that have explicit template argument
- lists</td>
+ <td></td>
</tr>
<tr><td>&nbsp;&nbsp;5.2 [expr.post]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
@@ -1093,9 +1092,9 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.1 [namespace.unnamed]</td>
<td class="complete" align="center"></td>
<td class="complete" align="center"></td>
- <td class="broken"></td>
+ <td class="complete"></td>
+ <td></td>
<td></td>
- <td>Unnamed namespace members cannot be looked up.</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.3.1.2 [namespace.memdef]</td>
@@ -1809,7 +1808,7 @@ welcome!</p>
<td class="complete" align="center">&#x2713;</td>
<td class="medium" align="center"></td>
<td class="na" align="center">N/A</td>
- <td>Template template parameters cannot actually be used in templates</td>
+ <td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;14.2 [temp.names]</td>