aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-01-15 15:39:40 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-01-15 15:39:40 +0000
commitee791dde723a2089c681d2ab6a9d4f96379d5f49 (patch)
treea6082d4d1d1e9ddaea09a6a04bb4a47da95d642d
parentabe15e553e58165e7692c0d0842865c488ed7b45 (diff)
downloadsrc-ee791dde723a2089c681d2ab6a9d4f96379d5f49.tar.gz
src-ee791dde723a2089c681d2ab6a9d4f96379d5f49.zip
Update clang to r93512.
Notes
Notes: svn path=/vendor/clang/dist/; revision=202379
-rw-r--r--LICENSE.TXT2
-rw-r--r--docs/InternalsManual.html14
-rw-r--r--docs/LanguageExtensions.html77
-rw-r--r--examples/PrintFunctionNames/README.txt2
-rw-r--r--include/clang-c/Index.h57
-rw-r--r--include/clang/AST/APValue.h31
-rw-r--r--include/clang/AST/ASTContext.h22
-rw-r--r--include/clang/AST/Attr.h88
-rw-r--r--include/clang/AST/CharUnits.h28
-rw-r--r--include/clang/AST/Decl.h2
-rw-r--r--include/clang/AST/DeclCXX.h3
-rw-r--r--include/clang/AST/DeclObjC.h14
-rw-r--r--include/clang/AST/DeclarationName.h9
-rw-r--r--include/clang/AST/Expr.h14
-rw-r--r--include/clang/AST/ExprCXX.h10
-rw-r--r--include/clang/AST/Stmt.h7
-rw-r--r--include/clang/AST/TypeLoc.h90
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h7
-rw-r--r--include/clang/Analysis/PathSensitive/ConstraintManager.h7
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h22
-rw-r--r--include/clang/Analysis/PathSensitive/GRState.h44
-rw-r--r--include/clang/Analysis/PathSensitive/GRSubEngine.h8
-rw-r--r--include/clang/Analysis/PathSensitive/MemRegion.h65
-rw-r--r--include/clang/Analysis/PathSensitive/SValuator.h4
-rw-r--r--include/clang/Analysis/PathSensitive/Store.h6
-rw-r--r--include/clang/Basic/Diagnostic.h5
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td12
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td120
-rw-r--r--include/clang/Basic/PartialDiagnostic.h38
-rw-r--r--include/clang/Basic/SourceLocation.h1
-rw-r--r--include/clang/Basic/TargetInfo.h3
-rw-r--r--include/clang/Driver/CC1Options.td6
-rw-r--r--include/clang/Driver/Options.td1
-rw-r--r--include/clang/Driver/ToolChain.h4
-rw-r--r--include/clang/Driver/Types.def1
-rw-r--r--include/clang/Frontend/CompilerInstance.h38
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h5
-rw-r--r--include/clang/Frontend/PCHReader.h14
-rw-r--r--include/clang/Frontend/Utils.h32
-rw-r--r--include/clang/Lex/DirectoryLookup.h9
-rw-r--r--include/clang/Lex/ExternalPreprocessorSource.h34
-rw-r--r--include/clang/Lex/HeaderMap.h4
-rw-r--r--include/clang/Lex/HeaderSearch.h11
-rw-r--r--include/clang/Lex/Preprocessor.h33
-rw-r--r--include/clang/Parse/Action.h84
-rw-r--r--include/clang/Parse/DeclSpec.h19
-rw-r--r--include/clang/Parse/Parser.h11
-rw-r--r--include/clang/Rewrite/Rewriter.h4
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h33
-rw-r--r--lib/AST/APValue.cpp33
-rw-r--r--lib/AST/ASTContext.cpp62
-rw-r--r--lib/AST/AttrImpl.cpp143
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/Decl.cpp11
-rw-r--r--lib/AST/DeclCXX.cpp35
-rw-r--r--lib/AST/DeclarationName.cpp51
-rw-r--r--lib/AST/Expr.cpp30
-rw-r--r--lib/AST/ExprConstant.cpp108
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp11
-rw-r--r--lib/AST/Stmt.cpp4
-rw-r--r--lib/AST/StmtPrinter.cpp12
-rw-r--r--lib/AST/TypeLoc.cpp12
-rw-r--r--lib/AST/TypePrinter.cpp9
-rw-r--r--lib/Analysis/AnalysisContext.cpp4
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp11
-rw-r--r--lib/Analysis/BugReporter.cpp19
-rw-r--r--lib/Analysis/CFRefCount.cpp25
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp18
-rw-r--r--lib/Analysis/Environment.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp133
-rw-r--r--lib/Analysis/GRState.cpp3
-rw-r--r--lib/Analysis/MemRegion.cpp65
-rw-r--r--lib/Analysis/OSAtomicChecker.cpp28
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp8
-rw-r--r--lib/Analysis/RegionStore.cpp223
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp14
-rw-r--r--lib/Analysis/SVals.cpp4
-rw-r--r--lib/Analysis/SValuator.cpp8
-rw-r--r--lib/Analysis/SimpleConstraintManager.cpp47
-rw-r--r--lib/Analysis/SimpleConstraintManager.h3
-rw-r--r--lib/Analysis/SimpleSValuator.cpp8
-rw-r--r--lib/Analysis/Store.cpp43
-rw-r--r--lib/Basic/Diagnostic.cpp96
-rw-r--r--lib/Basic/Targets.cpp456
-rw-r--r--lib/CodeGen/CGBlocks.cpp60
-rw-r--r--lib/CodeGen/CGBlocks.h7
-rw-r--r--lib/CodeGen/CGCXX.cpp671
-rw-r--r--lib/CodeGen/CGClass.cpp394
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp63
-rw-r--r--lib/CodeGen/CGDebugInfo.h13
-rw-r--r--lib/CodeGen/CGDecl.cpp2
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp36
-rw-r--r--lib/CodeGen/CGExpr.cpp148
-rw-r--r--lib/CodeGen/CGExprAgg.cpp3
-rw-r--r--lib/CodeGen/CGExprCXX.cpp331
-rw-r--r--lib/CodeGen/CGExprComplex.cpp39
-rw-r--r--lib/CodeGen/CGExprConstant.cpp33
-rw-r--r--lib/CodeGen/CGExprScalar.cpp160
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp32
-rw-r--r--lib/CodeGen/CGRTTI.cpp22
-rw-r--r--lib/CodeGen/CGVtable.cpp259
-rw-r--r--lib/CodeGen/CGVtable.h110
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp33
-rw-r--r--lib/CodeGen/CodeGenFunction.h28
-rw-r--r--lib/CodeGen/CodeGenModule.cpp72
-rw-r--r--lib/CodeGen/CodeGenModule.h19
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp43
-rw-r--r--lib/CodeGen/CodeGenTypes.h7
-rw-r--r--lib/CodeGen/Mangle.cpp5
-rw-r--r--lib/CodeGen/TargetInfo.cpp1904
-rw-r--r--lib/CodeGen/TargetInfo.h50
-rw-r--r--lib/Driver/ToolChains.cpp12
-rw-r--r--lib/Driver/ToolChains.h2
-rw-r--r--lib/Driver/Tools.cpp19
-rw-r--r--lib/Driver/Types.cpp2
-rw-r--r--lib/Frontend/ASTConsumers.cpp13
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp12
-rw-r--r--lib/Frontend/CompilerInstance.cpp93
-rw-r--r--lib/Frontend/CompilerInvocation.cpp17
-rw-r--r--lib/Frontend/FixItRewriter.cpp3
-rw-r--r--lib/Frontend/FrontendActions.cpp4
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp6
-rw-r--r--lib/Frontend/InitPreprocessor.cpp442
-rw-r--r--lib/Frontend/PCHReader.cpp71
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp7
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp4
-rw-r--r--lib/Frontend/PCHWriter.cpp16
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp4
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp1
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp314
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp9
-rw-r--r--lib/Headers/xmmintrin.h2
-rw-r--r--lib/Lex/HeaderMap.cpp27
-rw-r--r--lib/Lex/HeaderSearch.cpp52
-rw-r--r--lib/Lex/Lexer.cpp10
-rw-r--r--lib/Lex/LiteralSupport.cpp9
-rw-r--r--lib/Lex/PPDirectives.cpp79
-rw-r--r--lib/Lex/PPLexerChange.cpp3
-rw-r--r--lib/Lex/PPMacroExpansion.cpp72
-rw-r--r--lib/Lex/Pragma.cpp15
-rw-r--r--lib/Lex/Preprocessor.cpp33
-rw-r--r--lib/Parse/DeclSpec.cpp8
-rw-r--r--lib/Parse/ParseDecl.cpp178
-rw-r--r--lib/Parse/ParseDeclCXX.cpp58
-rw-r--r--lib/Parse/ParseExpr.cpp24
-rw-r--r--lib/Parse/ParseExprCXX.cpp52
-rw-r--r--lib/Parse/ParseObjc.cpp39
-rw-r--r--lib/Parse/ParseStmt.cpp8
-rw-r--r--lib/Parse/ParseTemplate.cpp3
-rw-r--r--lib/Parse/Parser.cpp6
-rw-r--r--lib/Rewrite/Rewriter.cpp4
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp51
-rw-r--r--lib/Sema/IdentifierResolver.cpp42
-rw-r--r--lib/Sema/IdentifierResolver.h11
-rw-r--r--lib/Sema/Lookup.h31
-rw-r--r--lib/Sema/Sema.cpp322
-rw-r--r--lib/Sema/Sema.h116
-rw-r--r--lib/Sema/SemaCXXCast.cpp2
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp26
-rw-r--r--lib/Sema/SemaChecking.cpp478
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1598
-rw-r--r--lib/Sema/SemaDecl.cpp319
-rw-r--r--lib/Sema/SemaDeclAttr.cpp21
-rw-r--r--lib/Sema/SemaDeclCXX.cpp244
-rw-r--r--lib/Sema/SemaDeclObjC.cpp110
-rw-r--r--lib/Sema/SemaExpr.cpp340
-rw-r--r--lib/Sema/SemaExprCXX.cpp279
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp62
-rw-r--r--lib/Sema/SemaLookup.cpp295
-rw-r--r--lib/Sema/SemaOverload.cpp816
-rw-r--r--lib/Sema/SemaOverload.h184
-rw-r--r--lib/Sema/SemaStmt.cpp9
-rw-r--r--lib/Sema/SemaTemplate.cpp54
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp29
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp7
-rw-r--r--lib/Sema/SemaType.cpp63
-rw-r--r--lib/Sema/TargetAttributesSema.cpp86
-rw-r--r--lib/Sema/TargetAttributesSema.h27
-rw-r--r--lib/Sema/TreeTransform.h64
-rw-r--r--test/Analysis/CFDateGC.m12
-rw-r--r--test/Analysis/NSString.m16
-rw-r--r--test/Analysis/PR2599.m2
-rw-r--r--test/Analysis/casts.c20
-rw-r--r--test/Analysis/dead-stores.c2
-rw-r--r--test/Analysis/misc-ps-ranges.m37
-rw-r--r--test/Analysis/misc-ps-region-store.cpp43
-rw-r--r--test/Analysis/misc-ps-region-store.m52
-rw-r--r--test/Analysis/misc-ps.m38
-rw-r--r--test/Analysis/rdar-6442306-1.m2
-rw-r--r--test/Analysis/reference.cpp11
-rw-r--r--test/Analysis/retain-release-basic-store.m2
-rw-r--r--test/Analysis/retain-release-region-store.m2
-rw-r--r--test/Analysis/retain-release.m2
-rw-r--r--test/Analysis/security-syntax-checks-no-emit.c33
-rw-r--r--test/Analysis/stack-addr-ps.c7
-rw-r--r--test/Analysis/uninit-vals-ps-region.c1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp27
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp5
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp8
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp4
-rw-r--r--test/CXX/special/class.ctor/p1.cpp42
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p5.cpp78
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp33
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp15
-rw-r--r--test/CXX/temp/temp.param/p3.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp2
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp4
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1.cpp4
-rw-r--r--test/CodeCompletion/Inputs/macros.h4
-rw-r--r--test/CodeCompletion/enum-switch-case-qualified.cpp14
-rw-r--r--test/CodeCompletion/enum-switch-case.c10
-rw-r--r--test/CodeCompletion/enum-switch-case.cpp10
-rw-r--r--test/CodeCompletion/macros.c30
-rw-r--r--test/CodeCompletion/member-access.cpp22
-rw-r--r--test/CodeCompletion/namespace-alias.cpp10
-rw-r--r--test/CodeCompletion/namespace.cpp4
-rw-r--r--test/CodeCompletion/nested-name-specifier.cpp6
-rw-r--r--test/CodeCompletion/objc-message.m16
-rw-r--r--test/CodeCompletion/operator.cpp12
-rw-r--r--test/CodeCompletion/ordinary-name.c7
-rw-r--r--test/CodeCompletion/ordinary-name.cpp171
-rw-r--r--test/CodeCompletion/tag.c4
-rw-r--r--test/CodeCompletion/tag.cpp16
-rw-r--r--test/CodeCompletion/truncation.c10
-rw-r--r--test/CodeCompletion/using-namespace.cpp10
-rw-r--r--test/CodeCompletion/using.cpp12
-rw-r--r--test/CodeGen/annotate.c8
-rw-r--r--test/CodeGen/complex.c32
-rw-r--r--test/CodeGen/ext-vector.c11
-rw-r--r--test/CodeGen/libcalls.c4
-rw-r--r--test/CodeGen/object-size.c46
-rw-r--r--test/CodeGenCXX/attr.cpp3
-rw-r--r--test/CodeGenCXX/condition.cpp28
-rw-r--r--test/CodeGenCXX/constructor-template.cpp4
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-3.cpp2
-rw-r--r--test/CodeGenCXX/default-constructor-default-argument.cpp2
-rw-r--r--test/CodeGenCXX/default-destructor-synthesis.cpp9
-rw-r--r--test/CodeGenCXX/deferred-global-init.cpp16
-rw-r--r--test/CodeGenCXX/delete-two-arg.cpp2
-rw-r--r--test/CodeGenCXX/dyncast.cpp703
-rw-r--r--test/CodeGenCXX/eh.cpp46
-rw-r--r--test/CodeGenCXX/expr.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp7
-rw-r--r--test/CodeGenCXX/member-function-pointers.cpp11
-rw-r--r--test/CodeGenCXX/reference-init.cpp7
-rw-r--r--test/CodeGenCXX/virt.cpp86
-rw-r--r--test/CodeGenCXX/virtual-destructor-calls.cpp8
-rw-r--r--test/CodeGenCXX/vtable-key-function.cpp18
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp95
-rw-r--r--test/Coverage/ast-printing.c1
-rw-r--r--test/Coverage/ast-printing.cpp2
-rw-r--r--test/Coverage/c-language-features.inc9
-rw-r--r--test/Driver/analyze.c1
-rw-r--r--test/Driver/clang_f_opts.c6
-rw-r--r--test/FixIt/typo.c7
-rw-r--r--test/FixIt/typo.cpp31
-rw-r--r--test/FixIt/typo.m82
-rw-r--r--test/Frontend/macros.c4
-rw-r--r--test/Index/TestClassDecl.m26
-rw-r--r--test/Index/c-index-api-loadTU-test.m75
-rw-r--r--test/Index/c-index-getCursor-test.m24
-rw-r--r--test/Index/code-completion.cpp12
-rw-r--r--test/Index/complete-at-directives.m51
-rw-r--r--test/Index/complete-at-exprstmt.m22
-rw-r--r--test/Index/complete-objc-message.m22
-rw-r--r--test/Index/complete-tabs.c9
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp101
-rw-r--r--test/Lexer/hexfloat.cpp8
-rw-r--r--test/Lexer/numeric-literal-trash.c2
-rw-r--r--test/Misc/tabstop.c30
-rw-r--r--test/Parser/cxx0x-literal-operators.cpp6
-rw-r--r--test/Preprocessor/foo.framework/Headers/bar.h3
-rw-r--r--test/Preprocessor/foo.framework/Headers/foo.h6
-rw-r--r--test/Preprocessor/framework-include.m5
-rw-r--r--test/Preprocessor/init.c2
-rw-r--r--test/Preprocessor/stdint.c22
-rw-r--r--test/Rewriter/rewrite-anonymous-union.m30
-rw-r--r--test/Rewriter/rewrite-byref-vars.mm35
-rw-r--r--test/Rewriter/rewrite-eh.m20
-rw-r--r--test/Rewriter/rewrite-foreach-7.m7
-rw-r--r--test/Rewriter/rewrite-forward-class.m8
-rw-r--r--test/Rewriter/rewrite-function-decl.mm31
-rw-r--r--test/Rewriter/rewrite-ivar-use.m25
-rw-r--r--test/Rewriter/rewrite-trivial-constructor.mm21
-rw-r--r--test/Rewriter/rewrite-weak-attr.m13
-rw-r--r--test/Rewriter/weak_byref_objects.m15
-rw-r--r--test/Sema/anonymous-struct-union.c6
-rw-r--r--test/Sema/attr-noreturn.c2
-rw-r--r--test/Sema/attr-section.c5
-rw-r--r--test/Sema/block-labels.c2
-rw-r--r--test/Sema/block-misc.c22
-rw-r--r--test/Sema/block-return.c1
-rw-r--r--test/Sema/compare.c44
-rw-r--r--test/Sema/complex-int.c4
-rw-r--r--test/Sema/conditional.c1
-rw-r--r--test/Sema/conversion.c36
-rw-r--r--test/Sema/declspec.c2
-rw-r--r--test/Sema/enum.c8
-rw-r--r--test/Sema/exprs.c14
-rw-r--r--test/Sema/format-strings.c1
-rw-r--r--test/Sema/i-c-e.c5
-rw-r--r--test/Sema/implicit-builtin-decl.c3
-rw-r--r--test/Sema/implicit-decl.c3
-rw-r--r--test/Sema/invalid-decl.c2
-rw-r--r--test/Sema/ms-fuzzy-asm.c1
-rw-r--r--test/Sema/overloadable.c6
-rw-r--r--test/Sema/parentheses.c12
-rw-r--r--test/Sema/self-comparison.c5
-rw-r--r--test/Sema/switch.c2
-rw-r--r--test/Sema/unused-expr.c6
-rw-r--r--test/Sema/var-redecl.c2
-rw-r--r--test/Sema/warn-unreachable.c20
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp4
-rw-r--r--test/SemaCXX/ambig-user-defined-conversions.cpp98
-rw-r--r--test/SemaCXX/attr-unavailable.cpp4
-rw-r--r--test/SemaCXX/builtin-ptrtomember-overload-1.cpp6
-rw-r--r--test/SemaCXX/composite-pointer-type.cpp7
-rw-r--r--test/SemaCXX/condition.cpp4
-rw-r--r--test/SemaCXX/conditional-expr.cpp17
-rw-r--r--test/SemaCXX/constructor-initializer.cpp7
-rw-r--r--test/SemaCXX/conversion-function.cpp4
-rw-r--r--test/SemaCXX/converting-constructor.cpp2
-rw-r--r--test/SemaCXX/copy-initialization.cpp2
-rw-r--r--test/SemaCXX/dcl_init_aggr.cpp6
-rw-r--r--test/SemaCXX/decl-init-ref.cpp2
-rw-r--r--test/SemaCXX/default2.cpp4
-rw-r--r--test/SemaCXX/direct-initializer.cpp12
-rw-r--r--test/SemaCXX/functional-cast.cpp6
-rw-r--r--test/SemaCXX/implicit-virtual-member-functions.cpp8
-rw-r--r--test/SemaCXX/literal-operators.cpp43
-rw-r--r--test/SemaCXX/member-pointer.cpp14
-rw-r--r--test/SemaCXX/namespace.cpp2
-rw-r--r--test/SemaCXX/nested-name-spec.cpp2
-rw-r--r--test/SemaCXX/overload-call.cpp32
-rw-r--r--test/SemaCXX/overload-member-call.cpp30
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp4
-rw-r--r--test/SemaCXX/overloaded-operator.cpp39
-rw-r--r--test/SemaCXX/rval-references.cpp6
-rw-r--r--test/SemaCXX/unreachable-code.cpp41
-rw-r--r--test/SemaCXX/virtual-member-functions-key-function.cpp23
-rw-r--r--test/SemaCXX/warn-assignment-condition.cpp48
-rw-r--r--test/SemaObjC/bad-receiver-1.m2
-rw-r--r--test/SemaObjC/category-1.m2
-rw-r--r--test/SemaObjC/continuation-class-property.m24
-rw-r--r--test/SemaObjC/ivar-access-package.m2
-rw-r--r--test/SemaObjC/ivar-lookup-resolution-builtin.m40
-rw-r--r--test/SemaObjC/nonnull.m3
-rw-r--r--test/SemaObjC/property-9.m12
-rw-r--r--test/SemaObjC/protocol-archane.m1
-rw-r--r--test/SemaObjC/undef-class-messagin-error.m6
-rw-r--r--test/SemaObjC/undef-superclass-1.m5
-rw-r--r--test/SemaTemplate/ambiguous-ovl-print.cpp2
-rw-r--r--test/SemaTemplate/constructor-template.cpp8
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp2
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp84
-rw-r--r--test/SemaTemplate/explicit-instantiation.cpp4
-rw-r--r--test/SemaTemplate/fun-template-def.cpp2
-rw-r--r--test/SemaTemplate/function-template-specialization.cpp8
-rw-r--r--test/SemaTemplate/injected-class-name.cpp6
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp4
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp4
-rw-r--r--test/SemaTemplate/instantiate-member-expr.cpp24
-rw-r--r--test/SemaTemplate/instantiate-static-var.cpp2
-rw-r--r--test/SemaTemplate/instantiate-subscript.cpp2
-rw-r--r--test/SemaTemplate/temp_class_spec.cpp18
-rw-r--r--test/SemaTemplate/typo-dependent-name.cpp17
-rw-r--r--test/SemaTemplate/virtual-member-functions.cpp35
-rw-r--r--tools/CIndex/CIndex.cpp1167
-rw-r--r--tools/CIndex/CIndex.exports7
-rw-r--r--tools/CIndex/CIndexCodeCompletion.cpp371
-rw-r--r--tools/CIndex/CIndexUSRs.cpp203
-rw-r--r--tools/CIndex/CIndexer.cpp96
-rw-r--r--tools/CIndex/CIndexer.h88
-rw-r--r--tools/CIndex/CMakeLists.txt7
-rw-r--r--tools/c-index-test/c-index-test.c125
-rw-r--r--tools/driver/cc1_main.cpp99
-rw-r--r--utils/VtableTest/Makefile21
-rwxr-xr-xutils/VtableTest/check-zti20
-rwxr-xr-xutils/VtableTest/check-ztt20
-rwxr-xr-xutils/VtableTest/check-zvt18
-rw-r--r--utils/VtableTest/gen.cc350
-rw-r--r--utils/clang-completion-mode.el36
390 files changed, 15118 insertions, 6207 deletions
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 72faf418f287..a378a5f7fd51 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2007-2009 University of Illinois at Urbana-Champaign.
+Copyright (c) 2007-2010 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
index f39224f47dc5..5d75eaa45390 100644
--- a/docs/InternalsManual.html
+++ b/docs/InternalsManual.html
@@ -289,7 +289,7 @@ Clang:</p>
<tr><td>Example:</td><td><tt>"must be a %select{unary|binary|unary or binary}2
operator"</tt></td></tr>
<tr><td>Class:</td><td>Integers</td></tr>
-<tr><td>Description:</td><td>This format specifier is used to merge multiple
+<tr><td>Description:</td><td><p>This format specifier is used to merge multiple
related diagnostics together into one common one, without requiring the
difference to be specified as an English string argument. Instead of
specifying the string, the diagnostic gets an integer argument and the
@@ -298,7 +298,8 @@ Clang:</p>
it is 1 it prints 'binary' if it is 2, it prints 'unary or binary'. This
allows other language translations to substitute reasonable words (or entire
phrases) based on the semantics of the diagnostic instead of having to do
- things textually.</td></tr>
+ things textually.</p>
+ <p>The selected string does undergo formatting.</p></td></tr>
<tr><td colspan="2"><b>"plural" format</b></td></tr>
<tr><td>Example:</td><td><tt>"you have %1 %plural{1:mouse|:mice}1 connected to
@@ -330,6 +331,15 @@ Clang:</p>
abort, as will a failure to match the argument against any
expression.</p></td></tr>
+<tr><td colspan="2"><b>"ordinal" format</b></td></tr>
+<tr><td>Example:</td><td><tt>"ambiguity in %ordinal0 argument"</tt></td></tr>
+<tr><td>Class:</td><td>Integers</td></tr>
+<tr><td>Description:</td><td><p>This is a formatter which represents the
+ argument number as an ordinal: the value <tt>1</tt> becomes <tt>1st</tt>,
+ <tt>3</tt> becomes <tt>3rd</tt>, and so on. Values less than <tt>1</tt>
+ are not supported.</p>
+ <p>This formatter is currently hard-coded to use English ordinals.</p></td></tr>
+
<tr><td colspan="2"><b>"objcclass" format</b></td></tr>
<tr><td>Example:</td><td><tt>"method %objcclass0 not found"</tt></td></tr>
<tr><td>Class:</td><td>DeclarationName</td></tr>
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 414d9c89e59b..e2a44eaed0b9 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -28,6 +28,19 @@ td {
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
<li><a href="#cxx_rtti">C++ RTTI</a></li>
</ul>
+<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
+ <ul>
+ <li><a href="#cxx_attributes">C++0x attributes</a></li>
+ <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
+ <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
+ <li><a href="#cxx_concepts">C++ TR concepts</a></li>
+ <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
+ <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
+ <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
+ <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
+ <li><a href="#cxx_auto_type">C++0x type inference</a></li>
+ <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
+ </ul>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
<li><a href="#builtins">Builtin Functions</a>
@@ -216,6 +229,70 @@ example, compiling code with <tt>-fexceptions</tt> enables C++ exceptions.</p>
compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
<!-- ======================================================================= -->
+<h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
+<!-- ======================================================================= -->
+
+<p>The <tt>__has_feature</tt> macro can be used to query if certain upcoming
+standard language features are enabled. Those features are listed here.</p>
+
+<p>Currently, all features listed here are slated for inclusion in the upcoming
+C++0x standard. As a result, all the features that clang supports are enabled
+with the <tt>-std=c++0x</tt> option when compiling C++ code. Features that are
+not yet implemented will be noted.</p>
+
+<h3 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
+<tt>decltype()</tt> specifier is enabled.</p>
+
+<h3 id="cxx_attributes">C++0x attributes</h3>
+
+<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
+attribute parsing with C++0x's square bracket notation is enabled.
+
+<h3 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
+deleted function definitions (with <tt>= delete</tt>) is enabled.
+
+<h3 id="cxx_concepts">C++ TR <tt>concepts</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
+concepts is enabled. clang does not currently implement this feature.
+
+<h3 id="cxx_lambdas">C++0x lambdas</h3>
+
+<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
+lambdas is enabled. clang does not currently implement this feature.
+
+<h3 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_nullptr)</tt> to determine if support for
+<tt>nullptr</tt> is enabled. clang does not yet fully implement this feature.
+
+<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
+rvalue references is enabled. clang does not yet fully implement this feature.
+
+<h3 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_static_assert)</tt> to determine if support for
+compile-time assertions using <tt>static_assert</tt> is enabled.</p>
+
+<h3 id="cxx_auto_type">C++0x type inference</h3>
+
+<p>Use <tt>__has_feature(cxx_auto_type)</tt> to determine C++0x type inference
+is supported using the <tt>auto</tt> specifier. If this is disabled,
+<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.</p>
+
+<h3 id="cxx_variadic_templates">C++0x variadic templates</tt></h3>
+
+<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> to determine if support
+for templates taking any number of arguments with the ellipsis notation is
+enabled. clang does not yet fully implement this feature.</p>
+
+<!-- ======================================================================= -->
<h2 id="blocks">Blocks</h2>
<!-- ======================================================================= -->
diff --git a/examples/PrintFunctionNames/README.txt b/examples/PrintFunctionNames/README.txt
index ee6f7e865e91..267865c90351 100644
--- a/examples/PrintFunctionNames/README.txt
+++ b/examples/PrintFunctionNames/README.txt
@@ -6,5 +6,5 @@ TOOL_NO_EXPORT in the tools/clang Makefile).
Once the plugin is built, you can run it using:
--
-$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin=print-fns some-input-file.c
+$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin print-fns some-input-file.c
--
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 03b4df12596a..f11a9eb76f43 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -139,10 +139,14 @@ typedef struct {
enum CXCursorKind kind;
CXDecl decl;
CXStmt stmt; /* expression reference */
+ CXDecl referringDecl;
} CXCursor;
/* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */
-typedef void *CXEntity;
+typedef struct {
+ CXIndex index;
+ void *data;
+} CXEntity;
/**
* For functions returning a string that might or might not need
@@ -321,20 +325,40 @@ CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
/*
* CXEntity Operations.
*/
-CINDEX_LINKAGE const char *clang_getDeclarationName(CXEntity);
-CINDEX_LINKAGE const char *clang_getURI(CXEntity);
-CINDEX_LINKAGE CXEntity clang_getEntity(const char *URI);
+
+/* clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any)
+ * in a specified translation unit. */
+CINDEX_LINKAGE CXDecl clang_getDeclaration(CXEntity, CXTranslationUnit);
+
/*
* CXDecl Operations.
*/
CINDEX_LINKAGE CXCursor clang_getCursorFromDecl(CXDecl);
-CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXDecl);
+CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXIndex, CXDecl);
CINDEX_LINKAGE CXString clang_getDeclSpelling(CXDecl);
CINDEX_LINKAGE unsigned clang_getDeclLine(CXDecl);
CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl);
+CINDEX_LINKAGE CXString clang_getDeclUSR(CXDecl);
CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */
CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl);
+typedef struct CXSourceLineColumn {
+ unsigned line;
+ unsigned column;
+} CXSourceLineColumn;
+
+typedef struct CXDeclExtent {
+ CXSourceLineColumn begin;
+ CXSourceLineColumn end;
+} CXSourceExtent;
+
+/* clang_getDeclExtent() returns the physical extent of a declaration. The
+ * beginning line/column pair points to the start of the first token in the
+ * declaration, and the ending line/column pair points to the last character in
+ * the last token of the declaration.
+ */
+CINDEX_LINKAGE CXSourceExtent clang_getDeclExtent(CXDecl);
+
/*
* CXCursor Operations.
*/
@@ -564,7 +588,28 @@ enum CXCompletionChunkKind {
* the text buffer. Rather, it is meant to illustrate the type that an
* expression using the given completion string would have.
*/
- CXCompletionChunk_ResultType
+ CXCompletionChunk_ResultType,
+ /**
+ * \brief A colon (':').
+ */
+ CXCompletionChunk_Colon,
+ /**
+ * \brief A semicolon (';').
+ */
+ CXCompletionChunk_SemiColon,
+ /**
+ * \brief An '=' sign.
+ */
+ CXCompletionChunk_Equal,
+ /**
+ * Horizontal space (' ').
+ */
+ CXCompletionChunk_HorizontalSpace,
+ /**
+ * Vertical space ('\n'), after which it is generally a good idea to
+ * perform indentation.
+ */
+ CXCompletionChunk_VerticalSpace
};
/**
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 94d258d9e4e6..9d4bff893f02 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/APFloat.h"
namespace clang {
+ class CharUnits;
class Expr;
/// APValue - This class implements a discriminated union of [uninitialized]
@@ -47,10 +48,6 @@ private:
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
};
- struct LV {
- Expr* Base;
- uint64_t Offset;
- };
struct Vec {
APValue *Elts;
unsigned NumElts;
@@ -88,9 +85,11 @@ public:
APValue(const APValue &RHS) : Kind(Uninitialized) {
*this = RHS;
}
- APValue(Expr* B, uint64_t O) : Kind(Uninitialized) {
+ APValue(Expr* B, const CharUnits &O) : Kind(Uninitialized) {
MakeLValue(); setLValue(B, O);
}
+ APValue(Expr* B);
+
~APValue() {
MakeUninit();
}
@@ -164,14 +163,8 @@ public:
return const_cast<APValue*>(this)->getComplexFloatImag();
}
- Expr* getLValueBase() const {
- assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Base;
- }
- uint64_t getLValueOffset() const {
- assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Offset;
- }
+ Expr* getLValueBase() const;
+ CharUnits getLValueOffset() const;
void setInt(const APSInt &I) {
assert(isInt() && "Invalid accessor");
@@ -202,11 +195,7 @@ public:
((ComplexAPFloat*)(char*)Data)->Real = R;
((ComplexAPFloat*)(char*)Data)->Imag = I;
}
- void setLValue(Expr *B, uint64_t O) {
- assert(isLValue() && "Invalid accessor");
- ((LV*)(char*)Data)->Base = B;
- ((LV*)(char*)Data)->Offset = O;
- }
+ void setLValue(Expr *B, const CharUnits &O);
const APValue &operator=(const APValue &RHS);
@@ -237,11 +226,7 @@ private:
new ((void*)(char*)Data) ComplexAPFloat();
Kind = ComplexFloat;
}
- void MakeLValue() {
- assert(isUninit() && "Bad state change");
- new ((void*)(char*)Data) LV();
- Kind = LValue;
- }
+ void MakeLValue();
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index bcab46d0f5ed..5db8e20e7e48 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -699,8 +699,8 @@ public:
ObjCProtocolDecl *rProto);
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
- /// purpose.
- int getObjCEncodingTypeSize(QualType t);
+ /// purpose in characters.
+ CharUnits getObjCEncodingTypeSize(QualType t);
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
@@ -898,17 +898,18 @@ public:
return getCanonicalType(T1) == getCanonicalType(T2);
}
- /// \brief Returns this type as a completely-unqualified array type, capturing
- /// the qualifiers in Quals. This only operates on canonical types in order
- /// to ensure the ArrayType doesn't itself have qualifiers.
+ /// \brief Returns this type as a completely-unqualified array type,
+ /// capturing the qualifiers in Quals. This will remove the minimal amount of
+ /// sugaring from the types, similar to the behavior of
+ /// QualType::getUnqualifiedType().
///
- /// \param T is the canonicalized QualType, which may be an ArrayType
+ /// \param T is the qualified type, which may be an ArrayType
///
/// \param Quals will receive the full set of qualifiers that were
- /// applied to the element type of the array.
+ /// applied to the array.
///
/// \returns if this is an array type, the completely unqualified array type
- /// that corresponds to it. Otherwise, returns this->getUnqualifiedType().
+ /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals);
/// \brief Determine whether the given types are equivalent after
@@ -996,7 +997,10 @@ public:
const IncompleteArrayType *getAsIncompleteArrayType(QualType T) {
return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T));
}
-
+ const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) {
+ return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
+ }
+
/// getBaseElementType - Returns the innermost element type of an array type.
/// For example, will return "int" for int[m][n]
QualType getBaseElementType(const ArrayType *VAT);
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 2c7ab9d67e95..03ab0f07020b 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -55,8 +55,6 @@ public:
Cleanup,
Const,
Constructor,
- DLLExport,
- DLLImport,
Deprecated,
Destructor,
FastCall,
@@ -93,7 +91,12 @@ public:
Visibility,
WarnUnusedResult,
Weak,
- WeakImport
+ WeakImport,
+
+ FIRST_TARGET_ATTRIBUTE,
+ DLLExport,
+ DLLImport,
+ MSP430Interrupt
};
private:
@@ -158,7 +161,7 @@ public:
class ATTR##Attr : public Attr { \
public: \
ATTR##Attr() : Attr(ATTR) {} \
- virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }\
+ virtual Attr *clone(ASTContext &C) const; \
static bool classof(const Attr *A) { return A->getKind() == ATTR; } \
static bool classof(const ATTR##Attr *A) { return true; } \
}
@@ -174,9 +177,7 @@ public:
/// getAlignment - The specified alignment in bits.
unsigned getAlignment() const { return Alignment; }
- virtual Attr* clone(ASTContext &C) const {
- return ::new (C) PragmaPackAttr(Alignment);
- }
+ virtual Attr* clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -203,9 +204,7 @@ public:
return Alignment;
}
- virtual Attr* clone(ASTContext &C) const {
- return ::new (C) AlignedAttr(Alignment);
- }
+ virtual Attr* clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -221,7 +220,7 @@ public:
const std::string& getAnnotation() const { return Annotation; }
- virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
+ virtual Attr* clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -237,7 +236,7 @@ public:
const std::string& getLabel() const { return Label; }
- virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
+ virtual Attr* clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -255,7 +254,7 @@ public:
const std::string& getAliasee() const { return Aliasee; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Alias; }
@@ -269,7 +268,7 @@ public:
int getPriority() const { return priority; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
@@ -283,7 +282,7 @@ public:
int getPriority() const { return priority; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
@@ -294,7 +293,7 @@ class GNUInlineAttr : public Attr {
public:
GNUInlineAttr() : Attr(GNUInline) {}
- virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -307,7 +306,7 @@ class IBOutletAttr : public Attr {
public:
IBOutletAttr() : Attr(IBOutletKind) {}
- virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -329,7 +328,7 @@ public:
const std::string& getName() const { return Name; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -374,7 +373,7 @@ public:
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
}
- virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
+ virtual Attr *clone(ASTContext &C) const;
static bool classof(const Attr *A) { return A->getKind() == NonNull; }
static bool classof(const NonNullAttr *A) { return true; }
@@ -392,9 +391,7 @@ public:
int getFormatIdx() const { return formatIdx; }
int getFirstArg() const { return firstArg; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) FormatAttr(Type, formatIdx, firstArg);
- }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Format; }
@@ -407,9 +404,7 @@ public:
FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {}
int getFormatIdx() const { return formatIdx; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) FormatArgAttr(formatIdx);
- }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == FormatArg; }
@@ -424,9 +419,7 @@ public:
int getSentinel() const { return sentinel; }
int getNullPos() const { return NullPos; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) SentinelAttr(sentinel, NullPos);
- }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Sentinel; }
@@ -449,15 +442,13 @@ public:
VisibilityTypes getVisibility() const { return VisibilityType; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Visibility; }
static bool classof(const VisibilityAttr *A) { return true; }
};
-DEF_SIMPLE_ATTR(DLLImport);
-DEF_SIMPLE_ATTR(DLLExport);
DEF_SIMPLE_ATTR(FastCall);
DEF_SIMPLE_ATTR(StdCall);
DEF_SIMPLE_ATTR(CDecl);
@@ -471,9 +462,7 @@ public:
virtual bool isMerged() const { return false; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) OverloadableAttr;
- }
+ virtual Attr *clone(ASTContext &C) const;
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
static bool classof(const OverloadableAttr *) { return true; }
@@ -491,7 +480,7 @@ public:
BlocksAttrTypes getType() const { return BlocksAttrType; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Blocks; }
@@ -508,7 +497,7 @@ public:
const FunctionDecl *getFunctionDecl() const { return FD; }
- virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
@@ -527,9 +516,7 @@ public:
unsigned getNumParams() const { return NumParams; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) RegparmAttr(NumParams);
- }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
@@ -546,9 +533,7 @@ public:
unsigned getYDim() const { return Y; }
unsigned getZDim() const { return Z; }
- virtual Attr *clone(ASTContext &C) const {
- return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
- }
+ virtual Attr *clone(ASTContext &C) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
@@ -566,6 +551,25 @@ DEF_SIMPLE_ATTR(BaseCheck);
DEF_SIMPLE_ATTR(Hiding);
DEF_SIMPLE_ATTR(Override);
+// Target-specific attributes
+DEF_SIMPLE_ATTR(DLLImport);
+DEF_SIMPLE_ATTR(DLLExport);
+
+class MSP430InterruptAttr : public Attr {
+ unsigned Number;
+
+public:
+ MSP430InterruptAttr(unsigned n) : Attr(MSP430Interrupt), Number(n) {}
+
+ unsigned getNumber() const { return Number; }
+
+ virtual Attr *clone(ASTContext &C) const;
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) { return A->getKind() == MSP430Interrupt; }
+ static bool classof(const MSP430InterruptAttr *A) { return true; }
+};
+
#undef DEF_SIMPLE_ATTR
} // end namespace clang
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 7b2833c53ffa..0bb4b769d0f3 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -36,12 +36,12 @@ namespace clang {
/// in character units.
class CharUnits {
public:
- typedef int64_t RawType;
+ typedef int64_t QuantityType;
private:
- RawType Quantity;
+ QuantityType Quantity;
- explicit CharUnits(RawType C) : Quantity(C) {}
+ explicit CharUnits(QuantityType C) : Quantity(C) {}
public:
@@ -58,8 +58,8 @@ namespace clang {
return CharUnits(1);
}
- /// fromRaw - Construct a CharUnits quantity from a raw integer type.
- static CharUnits fromRaw(RawType Quantity) {
+ /// fromQuantity - Construct a CharUnits quantity from a raw integer type.
+ static CharUnits fromQuantity(QuantityType Quantity) {
return CharUnits(Quantity);
}
@@ -103,26 +103,26 @@ namespace clang {
/// isOne - Test whether the quantity equals one.
bool isOne() const { return Quantity == 1; }
- /// isPositive - Test whether the quanity is greater than zero.
+ /// isPositive - Test whether the quantity is greater than zero.
bool isPositive() const { return Quantity > 0; }
/// isNegative - Test whether the quantity is less than zero.
bool isNegative() const { return Quantity < 0; }
// Arithmetic operators.
- CharUnits operator* (RawType N) const {
+ CharUnits operator* (QuantityType N) const {
return CharUnits(Quantity * N);
}
- CharUnits operator/ (RawType N) const {
+ CharUnits operator/ (QuantityType N) const {
return CharUnits(Quantity / N);
}
- RawType operator/ (const CharUnits &Other) const {
+ QuantityType operator/ (const CharUnits &Other) const {
return Quantity / Other.Quantity;
}
- CharUnits operator% (RawType N) const {
+ CharUnits operator% (QuantityType N) const {
return CharUnits(Quantity % N);
}
- RawType operator% (const CharUnits &Other) const {
+ QuantityType operator% (const CharUnits &Other) const {
return Quantity % Other.Quantity;
}
CharUnits operator+ (const CharUnits &Other) const {
@@ -134,14 +134,14 @@ namespace clang {
// Conversions.
- /// getRaw - Get the raw integer representation of this quantity.
- RawType getRaw() const { return Quantity; }
+ /// getQuantity - Get the raw integer representation of this quantity.
+ QuantityType getQuantity() const { return Quantity; }
}; // class CharUnit
} // namespace clang
-inline clang::CharUnits operator* (clang::CharUnits::RawType Scale,
+inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale,
const clang::CharUnits &CU) {
return CU * Scale;
}
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index d0d94aafb8d0..21b59099138a 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1184,6 +1184,8 @@ public:
OverloadedOperatorKind getOverloadedOperator() const;
+ const IdentifierInfo *getLiteralIdentifier() const;
+
/// \brief If this function is an instantiation of a member function
/// of a class template specialization, retrieves the function from
/// which it was instantiated.
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 02581c1241a4..336a895de8cf 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -393,6 +393,9 @@ public:
return reverse_base_class_const_iterator(vbases_begin());
}
+ /// \brief Determine whether this class has any dependent base classes.
+ bool hasAnyDependentBases() const;
+
/// Iterator access to method members. The method iterator visits
/// all method members of the class, including non-instance methods,
/// special methods, etc.
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index ba17eb1c1d60..920d31fc7ce4 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -289,7 +289,9 @@ struct ObjCMethodList {
/// ObjCProtocolDecl, and ObjCImplDecl.
///
class ObjCContainerDecl : public NamedDecl, public DeclContext {
- SourceLocation AtEndLoc; // marks the end of the method container.
+ // These two locations in the range mark the end of the method container.
+ // The first points to the '@' token, and the second to the 'end' token.
+ SourceRange AtEnd;
public:
ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -351,11 +353,15 @@ public:
IdentifierInfo *PropertyId) const;
// Marks the end of the container.
- SourceLocation getAtEndLoc() const { return AtEndLoc; }
- void setAtEndLoc(SourceLocation L) { AtEndLoc = L; }
+ SourceRange getAtEndRange() const {
+ return AtEnd;
+ }
+ void setAtEndRange(SourceRange atEnd) {
+ AtEnd = atEnd;
+ }
virtual SourceRange getSourceRange() const {
- return SourceRange(getLocation(), getAtEndLoc());
+ return SourceRange(getLocation(), getAtEndRange().getEnd());
}
// Implement isa/cast/dyncast/etc.
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index fcb4ae52e7eb..59d7e439e570 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -190,6 +190,14 @@ public:
/// getNameKind - Determine what kind of name this is.
NameKind getNameKind() const;
+ /// \brief Determines whether the name itself is dependent, e.g., because it
+ /// involves a C++ type that is itself dependent.
+ ///
+ /// Note that this does not capture all of the notions of "dependent name",
+ /// because an identifier can be a dependent name if it is used as the
+ /// callee in a call expression with dependent arguments.
+ bool isDependentName() const;
+
/// getName - Retrieve the human-readable string for this name.
std::string getAsString() const;
@@ -301,6 +309,7 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
class DeclarationNameTable {
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
CXXOperatorIdName *CXXOperatorNames; // Operator names
+ void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> *
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 0cb22df92ff7..cfbae9fb2cbf 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -241,6 +241,11 @@ public:
/// stack based objects.
bool EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const;
+ /// EvaluateAsBooleanCondition - Return true if this is a constant
+ /// which we we can fold and convert to a boolean condition using
+ /// any crazy technique that we want to.
+ bool EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const;
+
/// isEvaluatable - Call Evaluate to see if this expression can be constant
/// folded, but discard the result.
bool isEvaluatable(ASTContext &Ctx) const;
@@ -2552,7 +2557,7 @@ private:
unsigned NumSubExprs : 16;
- DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+ DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc, bool GNUSyntax,
Expr **IndexExprs, unsigned NumIndexExprs,
@@ -2565,6 +2570,8 @@ private:
protected:
virtual void DoDestroy(ASTContext &C);
+ void DestroyDesignators(ASTContext &C);
+
public:
/// A field designator, e.g., ".x".
struct FieldDesignator {
@@ -2732,7 +2739,8 @@ public:
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
- void setDesignators(const Designator *Desigs, unsigned NumDesigs);
+ void setDesignators(ASTContext &C, const Designator *Desigs,
+ unsigned NumDesigs);
Expr *getArrayIndex(const Designator& D);
Expr *getArrayRangeStart(const Designator& D);
@@ -2779,7 +2787,7 @@ public:
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
- void ExpandDesignator(unsigned Idx, const Designator *First,
+ void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
const Designator *Last);
virtual SourceRange getSourceRange() const;
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index d0e21f576d75..55d5108e6174 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -324,17 +324,21 @@ public:
/// @endcode
class CXXThisExpr : public Expr {
SourceLocation Loc;
-
+ bool Implicit : 1;
+
public:
- CXXThisExpr(SourceLocation L, QualType Type)
+ CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit)
: Expr(CXXThisExprClass, Type,
// 'this' is type-dependent if the class type of the enclosing
// member function is dependent (C++ [temp.dep.expr]p2)
Type->isDependentType(), Type->isDependentType()),
- Loc(L) { }
+ Loc(L), Implicit(isImplicit) { }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
+ bool isImplicit() const { return Implicit; }
+ void setImplicit(bool I) { Implicit = I; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 33edadc3a5e6..d058f838a008 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -1116,6 +1116,7 @@ class AsmStmt : public Stmt {
bool IsSimple;
bool IsVolatile;
+ bool MSAsm;
unsigned NumOutputs;
unsigned NumInputs;
@@ -1126,7 +1127,7 @@ class AsmStmt : public Stmt {
llvm::SmallVector<StringLiteral*, 4> Clobbers;
public:
- AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
+ AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, bool msasm,
unsigned numoutputs, unsigned numinputs,
std::string *names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
@@ -1143,7 +1144,9 @@ public:
bool isVolatile() const { return IsVolatile; }
void setVolatile(bool V) { IsVolatile = V; }
bool isSimple() const { return IsSimple; }
- void setSimple(bool V) { IsSimple = false; }
+ void setSimple(bool V) { IsSimple = V; }
+ bool isMSAsm() const { return MSAsm; }
+ void setMSAsm(bool V) { MSAsm = V; }
//===--- Asm String Analysis ---===//
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 3e74d07ff7f3..c36c0ffde32e 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1029,18 +1029,88 @@ class ComplexTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
ComplexType> {
};
-// FIXME: location of the 'typeof' and parens (the expression is
-// carried by the type).
-class TypeOfExprTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TypeOfExprTypeLoc,
- TypeOfExprType> {
+struct TypeofLocInfo {
+ SourceLocation TypeofLoc;
+ SourceLocation LParenLoc;
+ SourceLocation RParenLoc;
};
-// FIXME: location of the 'typeof' and parens; also the TypeSourceInfo
-// for the inner type, or (maybe) just express that inline to the TypeLoc.
-class TypeOfTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TypeOfTypeLoc,
- TypeOfType> {
+struct TypeOfExprTypeLocInfo : public TypeofLocInfo {
+};
+
+struct TypeOfTypeLocInfo : public TypeofLocInfo {
+ TypeSourceInfo* UnderlyingTInfo;
+};
+
+template <class Derived, class TypeClass, class LocalData = TypeofLocInfo>
+class TypeofLikeTypeLoc
+ : public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> {
+public:
+ SourceLocation getTypeofLoc() const {
+ return this->getLocalData()->TypeofLoc;
+ }
+ void setTypeofLoc(SourceLocation Loc) {
+ this->getLocalData()->TypeofLoc = Loc;
+ }
+
+ SourceLocation getLParenLoc() const {
+ return this->getLocalData()->LParenLoc;
+ }
+ void setLParenLoc(SourceLocation Loc) {
+ this->getLocalData()->LParenLoc = Loc;
+ }
+
+ SourceLocation getRParenLoc() const {
+ return this->getLocalData()->RParenLoc;
+ }
+ void setRParenLoc(SourceLocation Loc) {
+ this->getLocalData()->RParenLoc = Loc;
+ }
+
+ SourceRange getParensRange() const {
+ return SourceRange(getLParenLoc(), getRParenLoc());
+ }
+ void setParensRange(SourceRange range) {
+ setLParenLoc(range.getBegin());
+ setRParenLoc(range.getEnd());
+ }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(getTypeofLoc(), getRParenLoc());
+ }
+
+ void initializeLocal(SourceLocation Loc) {
+ setTypeofLoc(Loc);
+ setLParenLoc(Loc);
+ setRParenLoc(Loc);
+ }
+};
+
+class TypeOfExprTypeLoc : public TypeofLikeTypeLoc<TypeOfExprTypeLoc,
+ TypeOfExprType,
+ TypeOfExprTypeLocInfo> {
+public:
+ Expr* getUnderlyingExpr() const {
+ return getTypePtr()->getUnderlyingExpr();
+ }
+ // Reimplemented to account for GNU/C++ extension
+ // typeof unary-expression
+ // where there are no parentheses.
+ SourceRange getSourceRange() const;
+};
+
+class TypeOfTypeLoc
+ : public TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> {
+public:
+ QualType getUnderlyingType() const {
+ return this->getTypePtr()->getUnderlyingType();
+ }
+ TypeSourceInfo* getUnderlyingTInfo() const {
+ return this->getLocalData()->UnderlyingTInfo;
+ }
+ void setUnderlyingTInfo(TypeSourceInfo* TI) const {
+ this->getLocalData()->UnderlyingTInfo = TI;
+ }
};
// FIXME: location of the 'decltype' and parens.
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index ccebf01b76af..6f6681a3629b 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -23,7 +23,6 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/ImmutableSet.h"
#include <list>
@@ -104,9 +103,9 @@ public:
// BugReporter.
const Stmt* getStmt() const;
- const std::string& getDescription() const { return Description; }
+ const llvm::StringRef getDescription() const { return Description; }
- const std::string& getShortDescription() const {
+ const llvm::StringRef getShortDescription() const {
return ShortDescription.empty() ? Description : ShortDescription;
}
@@ -444,7 +443,7 @@ public:
// FIXME: Move out-of-line (virtual function).
SourceLocation getLocation() const { return L; }
- void addString(const std::string& s) { Strs.push_back(s); }
+ void addString(llvm::StringRef s) { Strs.push_back(s); }
typedef std::list<std::string>::const_iterator str_iterator;
str_iterator str_begin() const { return Strs.begin(); }
diff --git a/include/clang/Analysis/PathSensitive/ConstraintManager.h b/include/clang/Analysis/PathSensitive/ConstraintManager.h
index 37a14083ac55..c8292802ae9d 100644
--- a/include/clang/Analysis/PathSensitive/ConstraintManager.h
+++ b/include/clang/Analysis/PathSensitive/ConstraintManager.h
@@ -25,6 +25,7 @@ namespace clang {
class GRState;
class GRStateManager;
+class GRSubEngine;
class SVal;
class ConstraintManager {
@@ -64,8 +65,10 @@ public:
virtual bool canReasonAbout(SVal X) const = 0;
};
-ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
-ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr);
+ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine);
+ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine);
} // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index e05c6243846d..fb0e88301fd6 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -87,9 +87,11 @@ class GRExprEngine : public GRSubEngine {
// this object be placed at the very end of member variables so that its
// destructor is called before the rest of the GRExprEngine is destroyed.
GRBugReporter BR;
+
+ llvm::OwningPtr<GRTransferFuncs> TF;
public:
- GRExprEngine(AnalysisManager &mgr);
+ GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf);
~GRExprEngine();
@@ -104,18 +106,14 @@ public:
SValuator &getSValuator() { return SVator; }
- GRTransferFuncs& getTF() { return *StateMgr.TF; }
+ GRTransferFuncs& getTF() { return *TF; }
BugReporter& getBugReporter() { return BR; }
GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
- /// setTransferFunctions
- void setTransferFunctionsAndCheckers(GRTransferFuncs* tf);
-
- void setTransferFunctions(GRTransferFuncs& tf) {
- setTransferFunctionsAndCheckers(&tf);
- }
+ // FIXME: Remove once GRTransferFuncs is no longer referenced.
+ void setTransferFunction(GRTransferFuncs* tf);
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
@@ -173,6 +171,10 @@ public:
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ProcessEndPath(GREndPathNodeBuilder& builder);
+
+ /// EvalAssume - Callback function invoked by the ConstraintManager when
+ /// making assumptions about state values.
+ const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption);
GRStateManager& getStateManager() { return StateMgr; }
const GRStateManager& getStateManager() const { return StateMgr; }
@@ -351,6 +353,10 @@ protected:
void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst);
+ /// Create a C++ temporary object for an rvalue.
+ void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h
index 424b0d77e84c..11cdac0e96de 100644
--- a/include/clang/Analysis/PathSensitive/GRState.h
+++ b/include/clang/Analysis/PathSensitive/GRState.h
@@ -40,10 +40,10 @@
namespace clang {
class GRStateManager;
-class GRTransferFuncs;
class Checker;
-typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
+typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
+ GRSubEngine&);
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
//===----------------------------------------------------------------------===//
@@ -159,10 +159,6 @@ public:
BasicValueFactory &getBasicVals() const;
SymbolManager &getSymbolManager() const;
- GRTransferFuncs &getTransferFuncs() const;
-
- std::vector<std::pair<void *, Checker *> >::iterator checker_begin() const;
- std::vector<std::pair<void *, Checker *> >::iterator checker_end() const;
//==---------------------------------------------------------------------==//
// Constraints on values.
@@ -391,9 +387,8 @@ public:
//===----------------------------------------------------------------------===//
class GRStateManager {
- friend class GRExprEngine;
friend class GRState;
-
+ friend class GRExprEngine; // FIXME: Remove.
private:
EnvironmentManager EnvMgr;
llvm::OwningPtr<StoreManager> StoreMgr;
@@ -416,27 +411,20 @@ private:
ValueManager ValueMgr;
/// Alloc - A BumpPtrAllocator to allocate states.
- llvm::BumpPtrAllocator& Alloc;
-
- /// TF - Object that represents a bundle of transfer functions
- /// for manipulating and creating SVals.
- GRTransferFuncs* TF;
-
- /// Reference to all checkers in GRExprEngine.
- std::vector<std::pair<void *, Checker*> > *Checkers;
+ llvm::BumpPtrAllocator &Alloc;
public:
-
GRStateManager(ASTContext& Ctx,
StoreManagerCreator CreateStoreManager,
ConstraintManagerCreator CreateConstraintManager,
- llvm::BumpPtrAllocator& alloc)
+ llvm::BumpPtrAllocator& alloc,
+ GRSubEngine &subeng)
: EnvMgr(alloc),
GDMFactory(alloc),
ValueMgr(alloc, Ctx, *this),
Alloc(alloc) {
StoreMgr.reset((*CreateStoreManager)(*this));
- ConstraintMgr.reset((*CreateConstraintManager)(*this));
+ ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
}
~GRStateManager();
@@ -446,10 +434,6 @@ public:
ASTContext &getContext() { return ValueMgr.getContext(); }
const ASTContext &getContext() const { return ValueMgr.getContext(); }
- GRTransferFuncs& getTransferFuncs() { return *TF; }
-
- std::vector<std::pair<void *, Checker *> > &getCheckers() { return *Checkers;}
-
BasicValueFactory &getBasicVals() {
return ValueMgr.getBasicValueFactory();
}
@@ -702,20 +686,6 @@ inline SymbolManager &GRState::getSymbolManager() const {
return getStateManager().getSymbolManager();
}
-inline GRTransferFuncs &GRState::getTransferFuncs() const {
- return getStateManager().getTransferFuncs();
-}
-
-inline std::vector<std::pair<void *, Checker *> >::iterator
-GRState::checker_begin() const {
- return getStateManager().getCheckers().begin();
-}
-
-inline std::vector<std::pair<void *, Checker *> >::iterator
-GRState::checker_end() const {
- return getStateManager().getCheckers().end();
-}
-
template<typename T>
const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
return getStateManager().add<T>(this, K, get_context<T>());
diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h
index 330742d8bf99..5b383fae9bd0 100644
--- a/include/clang/Analysis/PathSensitive/GRSubEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRSubEngine.h
@@ -13,6 +13,8 @@
#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
+#include "clang/Analysis/PathSensitive/SVals.h"
+
namespace clang {
class Stmt;
@@ -62,8 +64,12 @@ public:
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
+
+ /// EvalAssume - Called by ConstraintManager. Used to call checker-specific
+ /// logic for handling assumptions on symbolic values.
+ virtual const GRState* ProcessAssume(const GRState *state,
+ SVal cond, bool assumption) = 0;
};
-
}
#endif
diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h
index b57cfd7b5205..3bcedbefd65c 100644
--- a/include/clang/Analysis/PathSensitive/MemRegion.h
+++ b/include/clang/Analysis/PathSensitive/MemRegion.h
@@ -65,6 +65,7 @@ public:
BlockTextRegionKind,
BlockDataRegionKind,
CompoundLiteralRegionKind,
+ CXXThisRegionKind,
StringRegionKind,
ElementRegionKind,
// Decl Regions.
@@ -99,17 +100,13 @@ public:
const MemRegion *StripCasts() const;
- bool hasStackStorage() const;
-
- bool hasParametersStorage() const;
-
- bool hasGlobalsStorage() const;
-
bool hasGlobalsOrParametersStorage() const;
- bool hasHeapStorage() const;
-
- bool hasHeapOrStackStorage() const;
+ bool hasStackStorage() const;
+
+ bool hasStackNonParametersStorage() const;
+
+ bool hasStackParametersStorage() const;
virtual void dumpToStream(llvm::raw_ostream& os) const;
@@ -634,6 +631,36 @@ public:
return R->getKind() == VarRegionKind;
}
};
+
+/// CXXThisRegion - Represents the region for the implicit 'this' parameter
+/// in a call to a C++ method. This region doesn't represent the object
+/// referred to by 'this', but rather 'this' itself.
+class CXXThisRegion : public TypedRegion {
+ friend class MemRegionManager;
+ CXXThisRegion(const PointerType *thisPointerTy,
+ const MemRegion *sReg)
+ : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sReg);
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+public:
+ QualType getValueType(ASTContext &C) const {
+ return QualType(ThisPointerTy, 0);
+ }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CXXThisRegionKind;
+ }
+
+private:
+ const PointerType *ThisPointerTy;
+};
class FieldRegion : public DeclRegion {
friend class MemRegionManager;
@@ -725,21 +752,21 @@ public:
}
};
+// C++ temporary object associated with an expression.
class CXXObjectRegion : public TypedRegion {
friend class MemRegionManager;
- // T - The object type.
- QualType T;
+ Expr const *Ex;
- CXXObjectRegion(QualType t, const MemRegion *sReg)
- : TypedRegion(sReg, CXXObjectRegionKind), T(t) {}
+ CXXObjectRegion(Expr const *E, MemRegion const *sReg)
+ : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {}
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
- QualType T, const MemRegion *sReg);
+ Expr const *E, const MemRegion *sReg);
public:
QualType getValueType(ASTContext& C) const {
- return T;
+ return Ex->getType();
}
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -824,6 +851,11 @@ public:
const CompoundLiteralRegion*
getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
const LocationContext *LC);
+
+ /// getCXXThisRegion - Retrieve the [artifical] region associated with the
+ /// parameter 'this'.
+ const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC);
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
@@ -869,7 +901,8 @@ public:
const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
const MemRegion* superRegion);
- const CXXObjectRegion *getCXXObjectRegion(QualType T);
+ const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex,
+ LocationContext const *LC);
const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
diff --git a/include/clang/Analysis/PathSensitive/SValuator.h b/include/clang/Analysis/PathSensitive/SValuator.h
index e63eb12cf8ea..4a4b502c6271 100644
--- a/include/clang/Analysis/PathSensitive/SValuator.h
+++ b/include/clang/Analysis/PathSensitive/SValuator.h
@@ -28,8 +28,10 @@ class SValuator {
protected:
ValueManager &ValMgr;
+public:
+ // FIXME: Make these protected again one RegionStoreManager correctly
+ // handles loads from differening bound value types.
virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0;
-
virtual SVal EvalCastL(Loc val, QualType castTy) = 0;
public:
diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h
index 52d73da15bc1..70c17accb725 100644
--- a/include/clang/Analysis/PathSensitive/Store.h
+++ b/include/clang/Analysis/PathSensitive/Store.h
@@ -103,9 +103,6 @@ public:
virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0;
- // T - the object type.
- Loc getThisObject(QualType T);
-
// FIXME: Make out-of-line.
virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
const MemRegion *region) {
@@ -192,7 +189,8 @@ protected:
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
- SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy);
+ SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy,
+ bool performTestOnly = true);
};
// FIXME: Do we still need this?
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index a2ccea7525ac..c5d6d7c71316 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -781,6 +781,11 @@ public:
/// formal arguments into the %0 slots. The result is appended onto the Str
/// array.
void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
+
+ /// FormatDiagnostic - Format the given format-string into the
+ /// output buffer using the arguments stored in this diagnostic.
+ void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
+ llvm::SmallVectorImpl<char> &OutStr) const;
};
/// DiagnosticClient - This is an abstract interface implemented by clients of
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index efbc787ef0ee..dfb6f8ddc1da 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -81,5 +81,7 @@ def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_assuming_mfloat_abi_is : Warning<
"unknown platform, assuming -mfloat-abi=%0">;
+def warn_ignoring_ftabstop_value : Warning<
+ "ignoring invalid -ftabstop value '%0', using default value %1">;
}
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index d8b5f2dad3c9..26a80b51c852 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -84,6 +84,9 @@ def err_exponent_has_no_digits : Error<"exponent has no digits">;
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
def err_hexconstant_requires_exponent : Error<
"hexadecimal floating constants require an exponent">;
+def ext_hexconstant_cplusplus : ExtWarn<
+ "hexadecimal floating constants are a C99 feature that is incompatible with "
+ "C++0x">;
def ext_hexconstant_invalid : Extension<
"hexadecimal floating constants are a C99 feature">;
def ext_binary_literal : Extension<
@@ -169,6 +172,9 @@ 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': %1">, DefaultFatal;
+def warn_pp_relative_include_from_framework : Warning<
+ "published framework headers should always #import headers within the "
+ "framework with framework paths">, InGroup<DiagGroup<"framework-headers">>;
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 98a74a5a0395..c6d060525285 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -261,6 +261,8 @@ def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
/// C++ Templates
def err_expected_template : Error<"expected template">;
+def err_unknown_template_name : Error<
+ "unknown template name %0">;
def err_expected_comma_greater : Error<
"expected ',' or '>' in template-parameter-list">;
def err_expected_type_id_after : Error<"expected type-id after '%0'">;
@@ -289,6 +291,16 @@ def err_explicit_instantiation_with_definition : Error<
"definition is meant to be an explicit specialization, add '<>' after the "
"'template' keyword">;
+// Constructor template diagnostics.
+def err_out_of_line_constructor_template_id : Error<
+ "out-of-line constructor for %0 cannot have template arguments">;
+def err_out_of_line_template_id_names_constructor : Error<
+ "qualified reference to %0 is a constructor name rather than a "
+ "template name wherever a constructor can be declared">;
+def err_out_of_line_type_names_constructor : Error<
+ "qualified reference to %0 is a constructor name rather than a "
+ "type wherever a constructor can be declared">;
+
def err_expected_qualified_after_typename : Error<
"expected a qualified name after 'typename'">;
def err_typename_refers_to_non_type_template : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 155633b08f3b..7e59f88fcef5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -89,7 +89,7 @@ def warn_decl_in_param_list : Warning<
def warn_implicit_function_decl : Warning<
"implicit declaration of function %0">,
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
-def ext_implicit_function_decl : Extension<
+def ext_implicit_function_decl : ExtWarn<
"implicit declaration of function %0 is invalid in C99">,
InGroup<ImplicitFunctionDeclare>;
@@ -160,6 +160,8 @@ def warn_suggest_noreturn_function : Warning<
def warn_suggest_noreturn_block : Warning<
"block could be attribute 'noreturn'">,
InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+def warn_unreachable : Warning<"will never be executed">,
+ InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
@@ -683,6 +685,8 @@ def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">;
def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
+def err_attribute_section_local_variable : Error<
+ "'section' attribute is not valid on local variables">;
def err_attribute_aligned_not_power_of_two : Error<
"requested alignment is not a power of 2">;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
@@ -895,18 +899,61 @@ def err_ovl_ambiguous_member_call : Error<
"call to member function %0 is ambiguous">;
def err_ovl_deleted_member_call : Error<
"call to %select{unavailable|deleted}0 member function %1">;
-def err_ovl_candidate : Note<"candidate function">;
-def err_ovl_candidate_not_viable : Note<"function not viable because"
- " of ambiguity in conversion of argument %0">;
+def note_ovl_candidate : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "is the implicit default constructor|"
+ "is the implicit copy constructor|"
+ "is the implicit copy assignment operator}0%1">;
+// Note that we don't treat templates differently for this diagnostic.
+def note_ovl_candidate_arity : Note<"candidate "
+ "%select{function|function|constructor|function|function|constructor|"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)}0 not viable: requires"
+ "%select{ at least| at most|}2 %3 argument%s3, but %4 %plural{1:was|:were}4 "
+ "provided">;
+def note_ovl_candidate_deleted : Note<
+ "candidate %select{function|function|constructor|"
+ "function |function |constructor |||}0%1 "
+ "has been explicitly %select{made unavailable|deleted}2">;
+def note_ovl_candidate_bad_conv : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)}0%1"
+ " not viable: no known conversion from %2 to %3 for "
+ "%select{%ordinal5 argument|object argument}4">;
+def note_ovl_candidate_bad_addrspace : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)}0%1 not viable: "
+ "%select{%ordinal6|'this'}5 argument (%2) is in "
+ "address space %3, but parameter must be in address space %4">;
+def note_ovl_candidate_bad_cvr_this : Note<"candidate "
+ "%select{|function|||function||||"
+ "function (the implicit copy assignment operator)}0 not viable: "
+ "'this' argument has type %2, but method is not marked "
+ "%select{const|volatile|const or volatile|restrict|const or restrict|"
+ "volatile or restrict|const, volatile, or restrict}3">;
+def note_ovl_candidate_bad_cvr : Note<"candidate "
+ "%select{function|function|constructor|"
+ "function |function |constructor |"
+ "constructor (the implicit default constructor)|"
+ "constructor (the implicit copy constructor)|"
+ "function (the implicit copy assignment operator)}0%1 not viable: "
+ "%ordinal4 argument (%2) would lose "
+ "%select{const|volatile|const and volatile|restrict|const and restrict|"
+ "volatile and restrict|const, volatile, and restrict}3 qualifier"
+ "%select{||s||s|s|s}3">;
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion of %0 to %1">;
-def err_ovl_template_candidate : Note<
- "candidate function template specialization %0">;
-def err_ovl_candidate_deleted : Note<
- "candidate function has been explicitly %select{made unavailable|deleted}0">;
-def err_ovl_builtin_binary_candidate : Note<
+def note_ovl_builtin_binary_candidate : Note<
"built-in candidate %0">;
-def err_ovl_builtin_unary_candidate : Note<
+def note_ovl_builtin_unary_candidate : Note<
"built-in candidate %0">;
def err_ovl_no_viable_function_in_init : Error<
"no matching constructor for initialization of %0">;
@@ -920,6 +967,10 @@ def err_ovl_ambiguous_oper : Error<
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def err_ovl_deleted_oper : Error<
"overload resolution selected %select{unavailable|deleted}0 operator '%1'">;
+def err_ovl_no_viable_subscript :
+ Error<"no viable overloaded operator[] for type %0">;
+def err_ovl_no_oper :
+ Error<"type %0 does not provide a %select{subscript|call}1 operator">;
def err_ovl_no_viable_object_call : Error<
"no matching function for call to object of type %0">;
@@ -927,7 +978,7 @@ def err_ovl_ambiguous_object_call : Error<
"call to object of type %0 is ambiguous">;
def err_ovl_deleted_object_call : Error<
"call to %select{unavailable|deleted}0 function call operator in type %1">;
-def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
+def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
def err_member_call_without_object : Error<
"call to non-static member function without an object argument">;
@@ -1295,6 +1346,8 @@ 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">;
+def err_template_kw_missing : Error<
+ "missing 'template' keyword prior to dependent template name '%0%1'">;
// C++0x Variadic Templates
def err_template_param_pack_default_arg : Error<
@@ -1472,7 +1525,7 @@ def note_protected_by___block : Note<
"jump bypasses setup of __block variable">;
def err_func_returning_array_function : Error<
- "function cannot return array or function type %0">;
+ "function cannot return %select{array|function}0 type %1">;
def err_field_declared_as_function : Error<"field %0 declared as a function">;
def err_field_incomplete : Error<"field has incomplete type %0">;
def ext_variable_sized_type_in_struct : ExtWarn<
@@ -1543,15 +1596,17 @@ def warn_floatingpoint_eq : Warning<
"comparing floating point with == or != is unsafe">,
InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
-def warn_shift_negative : Warning<
- "shift count is negative">;
-def warn_shift_gt_typewidth : Warning<
- "shift count >= width of type">;
+def warn_division_by_zero : Warning<"division by zero is undefined">;
+def warn_remainder_by_zero : Warning<"remainder by zero is undefined">;
+def warn_shift_negative : Warning<"shift count is negative">;
+def warn_shift_gt_typewidth : Warning<"shift count >= width of type">;
def warn_precedence_bitwise_rel : Warning<
"%0 has lower precedence than %1; %1 will be evaluated first">,
InGroup<Parentheses>;
-
+def note_precedence_bitwise_first : Note<
+ "place parentheses around the %0 expression to evaluate it first">;
+
def err_sizeof_nonfragile_interface : Error<
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
"non-fragile ABI">;
@@ -1647,6 +1702,8 @@ def err_static_block_func : Error<
def err_typecheck_address_of : Error<"address of %0 requested">;
def ext_typecheck_addrof_void : Extension<
"ISO C forbids taking the address of an expression of type 'void'">;
+def err_unqualified_pointer_member_function : Error<
+ "must explicitly qualify member function %0 when taking its address">;
def err_typecheck_invalid_lvalue_addrof : Error<
"address expression must be an lvalue or a function designator">;
def err_typecheck_unary_expr : Error<
@@ -1721,6 +1778,10 @@ def warn_printf_nonliteral : Warning<
def err_unexpected_interface : Error<
"unexpected interface name %0: expected expression">;
def err_ref_non_value : Error<"%0 does not refer to a value">;
+def err_ref_vm_type : Error<
+ "cannot refer to declaration with a variably modified type inside block">;
+def err_ref_array_type : Error<
+ "cannot refer to declaration with an array type inside block">;
def err_property_not_found : Error<
"property %0 not found on object of type %1">;
def err_duplicate_property : Error<
@@ -1952,6 +2013,8 @@ def warn_condition_is_assignment : Warning<"using the result of an "
def warn_condition_is_idiomatic_assignment : Warning<"using the result "
"of an assignment as a condition without parentheses">,
InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore;
+def note_condition_assign_to_comparison : Note<
+ "use '==' to turn this assignment into an equality comparison">;
def warn_value_always_zero : Warning<
"%0 is always %select{zero|false|NULL}1 in this context">;
@@ -2303,6 +2366,13 @@ def err_operator_delete_dependent_param_type : Error<
def err_operator_delete_param_type : Error<
"%0 takes type %1 as first parameter">;
+// C++ literal operators
+def err_literal_operator_outside_namespace : Error<
+ "literal operator %0 must be in a namespace or global scope">;
+// FIXME: This diagnostic sucks
+def err_literal_operator_params : Error<
+ "parameter declaration for literal operator %0 is not valid">;
+
// C++ conversion functions
def err_conv_function_not_member : Error<
"conversion function must be a non-static member function">;
@@ -2569,7 +2639,21 @@ def err_mem_init_not_member_or_class_suggest : Error<
def err_field_designator_unknown_suggest : Error<
"field designator %0 does not refer to any field in type %1; did you mean "
"%2?">;
-
+def err_typecheck_member_reference_ivar_suggest : Error<
+ "%0 does not have a member named %1; did you mean %2?">;
+def err_property_not_found_suggest : Error<
+ "property %0 not found on object of type %1; did you mean %2?">;
+def err_undef_interface_suggest : Error<
+ "cannot find interface declaration for %0; did you mean %1?">;
+def warn_undef_interface_suggest : Warning<
+ "cannot find interface declaration for %0; did you mean %1?">;
+def err_undef_superclass_suggest : Error<
+ "cannot find interface declaration for %0, superclass of %1; did you mean "
+ "%2?">;
+def err_undeclared_protocol_suggest : Error<
+ "cannot find protocol declaration for %0; did you mean %1?">;
+def note_base_class_specified_here : Note<
+ "base class %0 specified here">;
}
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index ae11a755cce4..0d970123f745 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -26,7 +26,8 @@ class DeclarationName;
class PartialDiagnostic {
struct Storage {
- Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
+ Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) {
+ }
enum {
/// MaxArguments - The maximum number of arguments we can hold. We
@@ -42,6 +43,10 @@ class PartialDiagnostic {
/// NumDiagRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
+ /// \brief The number of code modifications hints in the
+ /// CodeModificationHints array.
+ unsigned char NumCodeModificationHints;
+
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
/// is in DiagArgumentsStr or in DiagArguments.
@@ -56,6 +61,12 @@ class PartialDiagnostic {
/// DiagRanges - The list of ranges added to this diagnostic. It currently
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
+
+ enum { MaxCodeModificationHints = 3 };
+
+ /// CodeModificationHints - If valid, provides a hint with some code
+ /// to insert, remove, or modify at a particular position.
+ CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
};
/// DiagID - The diagnostic ID.
@@ -84,6 +95,20 @@ class PartialDiagnostic {
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
}
+ void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ if (Hint.isNull())
+ return;
+
+ if (!DiagStorage)
+ DiagStorage = new Storage;
+
+ assert(DiagStorage->NumCodeModificationHints <
+ Storage::MaxCodeModificationHints &&
+ "Too many code modification hints!");
+ DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++]
+ = Hint;
+ }
+
public:
PartialDiagnostic(unsigned DiagID)
: DiagID(DiagID), DiagStorage(0) { }
@@ -130,6 +155,10 @@ public:
// Add all ranges.
for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
+
+ // Add all code modification hints
+ for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i)
+ DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]);
}
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
@@ -165,6 +194,13 @@ public:
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
DeclarationName N);
+
+ friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ const CodeModificationHint &Hint) {
+ PD.AddCodeModificationHint(Hint);
+ return PD;
+ }
+
};
inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 36baf5feecce..d4f557b57d0b 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -162,6 +162,7 @@ public:
void setEnd(SourceLocation e) { E = e; }
bool isValid() const { return B.isValid() && E.isValid(); }
+ bool isInvalid() const { return !isValid(); }
bool operator==(const SourceRange &X) const {
return B == X.B && E == X.E;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 0d95e6a60323..97e0495bfbe2 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -30,6 +30,7 @@ class StringRef;
namespace clang {
class Diagnostic;
class LangOptions;
+class MacroBuilder;
class SourceLocation;
class SourceManager;
class TargetOptions;
@@ -209,7 +210,7 @@ public:
/// getTargetDefines - Appends the target-specific #define values for this
/// target set to the specified buffer.
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &DefineBuffer) const = 0;
+ MacroBuilder &Builder) const = 0;
/// getTargetBuiltins - Return information about target-specific builtins for
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 6a0d81692045..2511dfb7677a 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -178,6 +178,8 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang
HelpText<"Print source range spans in numeric form">;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
HelpText<"Print diagnostic name with mappable diagnostics">;
+def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
+ HelpText<"Set the tab stop distance.">;
def 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">,
@@ -323,6 +325,8 @@ 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 fmath_errno : Flag<"-fmath-errno">,
+ HelpText<"Require math functions to indicate errors by setting errno">;
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">,
@@ -331,8 +335,6 @@ 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">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 247e1f5117f9..955d98e4e914 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -345,6 +345,7 @@ def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<clang_ignored_f_Group>;
def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
+def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index b3c2d05ef563..cc8d438db3e9 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -87,10 +87,6 @@ public:
// Platform defaults information
- /// IsMathErrnoDefault - Does this tool chain set -fmath-errno by
- /// default.
- virtual bool IsMathErrnoDefault() const = 0;
-
/// IsBlocksDefault - Does this tool chain enable -fblocks by default.
virtual bool IsBlocksDefault() const { return false; }
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index e01a04c67ae1..d66fe9221a30 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -41,6 +41,7 @@
// C family source language (with and without preprocessing).
TYPE("cpp-output", PP_C, INVALID, "i", "u")
TYPE("c", C, PP_C, 0, "u")
+TYPE("cl", CL, PP_C, 0, "u")
TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u")
TYPE("objective-c", ObjC, PP_ObjC, 0, "u")
TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u")
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 18ec429db7e8..edafe623a4f6 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -32,6 +32,7 @@ class Diagnostic;
class DiagnosticClient;
class ExternalASTSource;
class FileManager;
+class FrontendAction;
class Preprocessor;
class Source;
class SourceManager;
@@ -103,6 +104,42 @@ public:
bool _OwnsLLVMContext = true);
~CompilerInstance();
+ /// @name High-Level Operations
+ /// {
+
+ /// ExecuteAction - Execute the provided action against the compiler's
+ /// CompilerInvocation object.
+ ///
+ /// This function makes the following assumptions:
+ ///
+ /// - The invocation options should be initialized. This function does not
+ /// handle the '-help' or '-version' options, clients should handle those
+ /// directly.
+ ///
+ /// - The diagnostics engine should have already been created by the client.
+ ///
+ /// - No other CompilerInstance state should have been initialized (this is
+ /// an unchecked error).
+ ///
+ /// - Clients should have initialized any LLVM target features that may be
+ /// required.
+ ///
+ /// - Clients should eventually call llvm_shutdown() upon the completion of
+ /// this routine to ensure that any managed objects are properly destroyed.
+ ///
+ /// Note that this routine may write output to 'stderr'.
+ ///
+ /// \param Act - The action to execute.
+ /// \return - True on success.
+ //
+ // FIXME: This function should take the stream to write any debugging /
+ // verbose output to as an argument.
+ //
+ // FIXME: Eliminate the llvm_shutdown requirement, that should either be part
+ // of the context or else not CompilerInstance specific.
+ bool ExecuteAction(FrontendAction &Act);
+
+ /// }
/// @name LLVM Context
/// {
@@ -451,6 +488,7 @@ public:
const HeaderSearchOptions &,
const DependencyOutputOptions &,
const TargetInfo &,
+ const FrontendOptions &,
SourceManager &, FileManager &);
/// Create the AST context.
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index 6346dc0bfdec..13039bb5063e 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -35,6 +35,10 @@ public:
/// diagnostics, indicated by markers in the
/// input source file.
+ /// The distance between tab stops.
+ unsigned TabStop;
+ enum { DefaultTabStop = 8, MaxTabStop = 100 };
+
/// Column limit for formatting message diagnostics, or 0 if unused.
unsigned MessageLength;
@@ -49,6 +53,7 @@ public:
public:
DiagnosticOptions() {
IgnoreWarnings = 0;
+ TabStop = DefaultTabStop;
MessageLength = 0;
NoRewriteMacros = 0;
Pedantic = 0;
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index 7e2c65690fd6..9665ce189f4a 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -20,6 +20,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
@@ -146,7 +147,8 @@ public:
/// required when traversing the AST. Only those AST nodes that are
/// actually required will be de-serialized.
class PCHReader
- : public ExternalSemaSource,
+ : public ExternalPreprocessorSource,
+ public ExternalSemaSource,
public IdentifierInfoLookup,
public ExternalIdentifierLookup,
public ExternalSLocEntrySource {
@@ -183,6 +185,10 @@ private:
llvm::BitstreamReader StreamFile;
llvm::BitstreamCursor Stream;
+ /// \brief The cursor to the start of the preprocessor block, which stores
+ /// all of the macro definitions.
+ llvm::BitstreamCursor MacroCursor;
+
/// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It
/// has read all the abbreviations at the start of the block and is ready to
/// jump around with these in context.
@@ -634,8 +640,7 @@ public:
/// This routine builds a new IdentifierInfo for the given identifier. If any
/// declarations with this name are visible from translation unit scope, their
/// declarations will be deserialized and introduced into the declaration
- /// chain of the identifier. FIXME: if this identifier names a macro,
- /// deserialize the macro.
+ /// chain of the identifier.
virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd);
IdentifierInfo* get(llvm::StringRef Name) {
return get(Name.begin(), Name.end());
@@ -712,6 +717,9 @@ public:
/// \brief Reads the macro record located at the given offset.
void ReadMacroRecord(uint64_t Offset);
+ /// \brief Read the set of macros defined by this external macro source.
+ virtual void ReadDefinedMacros();
+
/// \brief Retrieve the AST context that this PCH reader
/// supplements.
ASTContext *getContext() { return Context; }
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 27c14c917015..c8df4941cc21 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -15,13 +15,11 @@
#define LLVM_CLANG_FRONTEND_UTILS_H
#include "llvm/ADT/StringRef.h"
-#include <vector>
-#include <string>
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
namespace llvm {
class Triple;
-class raw_ostream;
-class raw_fd_ostream;
}
namespace clang {
@@ -41,6 +39,29 @@ class PreprocessorOutputOptions;
class SourceManager;
class Stmt;
class TargetInfo;
+class FrontendOptions;
+
+class MacroBuilder {
+ llvm::raw_ostream &Out;
+public:
+ MacroBuilder(llvm::raw_ostream &Output) : Out(Output) {}
+
+ /// Append a #define line for macro of the form "#define Name Value\n".
+ void defineMacro(const llvm::Twine &Name, const llvm::Twine &Value = "1") {
+ Out << "#define " << Name << ' ' << Value << '\n';
+ }
+
+ /// Append a #undef line for Name. Name should be of the form XXX
+ /// and we emit "#undef XXX".
+ void undefineMacro(const llvm::Twine &Name) {
+ Out << "#undef " << Name << '\n';
+ }
+
+ /// Directly append Str and a newline to the underlying buffer.
+ void append(const llvm::Twine &Str) {
+ Out << Str << '\n';
+ }
+};
/// Normalize \arg File for use in a user defined #include directive (in the
/// predefines buffer).
@@ -56,7 +77,8 @@ void ApplyHeaderSearchOptions(HeaderSearch &HS,
/// environment ready to process a single file.
void InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &PPOpts,
- const HeaderSearchOptions &HSOpts);
+ const HeaderSearchOptions &HSOpts,
+ const FrontendOptions &FEOpts);
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index c94a99022415..64687a18e2b6 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -16,6 +16,9 @@
#include "clang/Basic/SourceManager.h"
+namespace llvm {
+ class StringRef;
+}
namespace clang {
class HeaderMap;
class DirectoryEntry;
@@ -118,12 +121,10 @@ public:
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
- const FileEntry *LookupFile(const char *FilenameStart,
- const char *FilenameEnd, HeaderSearch &HS) const;
+ const FileEntry *LookupFile(llvm::StringRef Filename, HeaderSearch &HS) const;
private:
- const FileEntry *DoFrameworkLookup(const char *FilenameStart,
- const char *FilenameEnd,
+ const FileEntry *DoFrameworkLookup(llvm::StringRef Filename,
HeaderSearch &HS) const;
};
diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h
new file mode 100644
index 000000000000..af5c3898161e
--- /dev/null
+++ b/include/clang/Lex/ExternalPreprocessorSource.h
@@ -0,0 +1,34 @@
+//===- ExternalPreprocessorSource.h - Abstract Macro Interface --*- 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 ExternalPreprocessorSource interface, which enables
+// construction of macro definitions from some external source.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
+#define LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
+
+namespace clang {
+
+/// \brief Abstract interface for external sources of preprocessor
+/// information.
+///
+/// This abstract class allows an external sources (such as the \c PCHReader)
+/// to provide additional macro definitions.
+class ExternalPreprocessorSource {
+public:
+ virtual ~ExternalPreprocessorSource();
+
+ /// \brief Read the set of macros defined by this external macro source.
+ virtual void ReadDefinedMacros() = 0;
+};
+
+}
+
+#endif // LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index 6bb7c25947d7..9837e296535f 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -16,6 +16,7 @@
namespace llvm {
class MemoryBuffer;
+ class StringRef;
}
namespace clang {
class FileEntry;
@@ -46,8 +47,7 @@ public:
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
- const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
- FileManager &FM) const;
+ const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM) const;
/// getFileName - Return the filename of the headermap.
const char *getFileName() const;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 7517440983b1..16b8379045e5 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -150,8 +150,7 @@ public:
/// search location. This is used to implement #include_next. CurFileEnt, if
/// non-null, indicates where the #including file is, in case a relative
/// search is needed.
- const FileEntry *LookupFile(const char *FilenameStart,
- const char *FilenameEnd, bool isAngled,
+ const FileEntry *LookupFile(llvm::StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt);
@@ -161,16 +160,14 @@ public:
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
- const FileEntry *LookupSubframeworkHeader(const char *FilenameStart,
- const char *FilenameEnd,
+ const FileEntry *LookupSubframeworkHeader(llvm::StringRef Filename,
const FileEntry *RelativeFileEnt);
/// LookupFrameworkCache - Look up the specified framework name in our
/// framework cache, returning the DirectoryEntry it is in if we know,
/// otherwise, return null.
- const DirectoryEntry *&LookupFrameworkCache(const char *FWNameStart,
- const char *FWNameEnd) {
- return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue();
+ const DirectoryEntry *&LookupFrameworkCache(llvm::StringRef FWName) {
+ return FrameworkMap.GetOrCreateValue(FWName).getValue();
}
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 7c838ff86243..fc2671f48112 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -32,6 +32,7 @@
namespace clang {
class SourceManager;
+class ExternalPreprocessorSource;
class FileManager;
class FileEntry;
class HeaderSearch;
@@ -42,7 +43,7 @@ class ScratchBuffer;
class TargetInfo;
class PPCallbacks;
class DirectoryLookup;
-
+
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues
@@ -57,6 +58,9 @@ class Preprocessor {
ScratchBuffer *ScratchBuf;
HeaderSearch &HeaderInfo;
+ /// \brief External source of macros.
+ ExternalPreprocessorSource *ExternalSource;
+
/// PTH - An optional PTHManager object used for getting tokens from
/// a token cache rather than lexing the original source file.
llvm::OwningPtr<PTHManager> PTH;
@@ -99,6 +103,9 @@ class Preprocessor {
/// DisableMacroExpansion - True if macro expansion is disabled.
bool DisableMacroExpansion : 1;
+ /// \brief Whether we have already loaded macros from the external source.
+ mutable bool ReadMacrosFromExternalSource : 1;
+
/// Identifiers - This is mapping/lookup information for all identifiers in
/// the program, including program keywords.
mutable IdentifierTable Identifiers;
@@ -247,6 +254,14 @@ public:
PTHManager *getPTHManager() { return PTH.get(); }
+ void setExternalSource(ExternalPreprocessorSource *Source) {
+ ExternalSource = Source;
+ }
+
+ ExternalPreprocessorSource *getExternalSource() const {
+ return ExternalSource;
+ }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
@@ -296,11 +311,9 @@ public:
/// state of the macro table. This visits every currently-defined macro.
typedef llvm::DenseMap<IdentifierInfo*,
MacroInfo*>::const_iterator macro_iterator;
- macro_iterator macro_begin() const { return Macros.begin(); }
- macro_iterator macro_end() const { return Macros.end(); }
-
-
-
+ macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
+ macro_iterator macro_end(bool IncludeExternalMacros = true) const;
+
const std::string &getPredefines() const { return Predefines; }
/// setPredefines - Set the predefines for this Preprocessor. These
/// predefines are automatically injected when parsing the main file.
@@ -678,14 +691,14 @@ public:
/// caller is expected to provide a buffer that is large enough to hold the
/// spelling of the filename, but is also expected to handle the case when
/// this method decides to use a different buffer.
- bool GetIncludeFilenameSpelling(SourceLocation Loc,
- const char *&BufStart, const char *&BufEnd);
+ bool GetIncludeFilenameSpelling(SourceLocation Loc,llvm::StringRef &Filename);
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
- const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
- bool isAngled, const DirectoryLookup *FromDir,
+ const FileEntry *LookupFile(llvm::StringRef Filename,
+ SourceLocation FilenameTokLoc, bool isAngled,
+ const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir);
/// GetCurLookup - The DirectoryLookup structure used to find the current
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 4cbc21ad014a..7209e0a843cd 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -291,6 +291,42 @@ public:
bool EnteringContext,
TemplateTy &Template) = 0;
+ /// \brief Action called as part of error recovery when the parser has
+ /// determined that the given name must refer to a template, but
+ /// \c isTemplateName() did not return a result.
+ ///
+ /// This callback permits the action to give a detailed diagnostic when an
+ /// unknown template name is encountered and, potentially, to try to recover
+ /// by producing a new template in \p SuggestedTemplate.
+ ///
+ /// \param II the name that should be a template.
+ ///
+ /// \param IILoc the location of the name in the source.
+ ///
+ /// \param S the scope in which name lookup was performed.
+ ///
+ /// \param SS the C++ scope specifier that preceded the name.
+ ///
+ /// \param SuggestedTemplate if the action sets this template to a non-NULL,
+ /// template, the parser will recover by consuming the template name token
+ /// and the template argument list that follows.
+ ///
+ /// \param SuggestedTemplateKind as input, the kind of template that we
+ /// expect (e.g., \c TNK_Type_template or \c TNK_Function_template). If the
+ /// action provides a suggested template, this should be set to the kind of
+ /// template.
+ ///
+ /// \returns true if a diagnostic was emitted, false otherwise. When false,
+ /// the parser itself will emit a generic "unknown template name" diagnostic.
+ virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TemplateTy &SuggestedTemplate,
+ TemplateNameKind &SuggestedKind) {
+ return false;
+ }
+
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
@@ -866,7 +902,8 @@ public:
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool MSAsm = false) {
return StmtEmpty();
}
@@ -2176,7 +2213,7 @@ public:
// protocols, categories), the parser passes all methods/properties.
// For class implementations, these values default to 0. For implementations,
// methods are processed incrementally (by ActOnMethodDeclaration above).
- virtual void ActOnAtEnd(SourceLocation AtEndLoc,
+ virtual void ActOnAtEnd(SourceRange AtEnd,
DeclPtrTy classDecl,
DeclPtrTy *allMethods = 0,
unsigned allNum = 0,
@@ -2339,11 +2376,49 @@ public:
/// \todo Code completion for attributes.
//@{
+ /// \brief Describes the context in which code completion occurs.
+ enum CodeCompletionContext {
+ /// \brief Code completion occurs at top-level or namespace context.
+ CCC_Namespace,
+ /// \brief Code completion occurs within a class, struct, or union.
+ CCC_Class,
+ /// \brief Code completion occurs within an Objective-C interface, protocol,
+ /// or category.
+ CCC_ObjCInterface,
+ /// \brief Code completion occurs within an Objective-C implementation or
+ /// category implementation
+ CCC_ObjCImplementation,
+ /// \brief Code completion occurs within the list of instance variables
+ /// in an Objective-C interface, protocol, category, or implementation.
+ CCC_ObjCInstanceVariableList,
+ /// \brief Code completion occurs following one or more template
+ /// headers.
+ CCC_Template,
+ /// \brief Code completion occurs following one or more template
+ /// headers within a class.
+ CCC_MemberTemplate,
+ /// \brief Code completion occurs within an expression.
+ CCC_Expression,
+ /// \brief Code completion occurs within a statement, which may
+ /// also be an expression or a declaration.
+ CCC_Statement,
+ /// \brief Code completion occurs at the beginning of the
+ /// initialization statement (or expression) in a for loop.
+ CCC_ForInit,
+ /// \brief Code completion ocurs within the condition of an if,
+ /// while, switch, or for statement.
+ CCC_Condition
+ };
+
/// \brief Code completion for an ordinary name that occurs within the given
/// scope.
///
/// \param S the scope in which the name occurs.
- virtual void CodeCompleteOrdinaryName(Scope *S) { }
+ ///
+ /// \param CompletionContext the context in which code completion
+ /// occurs.
+ virtual void CodeCompleteOrdinaryName(Scope *S,
+ CodeCompletionContext CompletionContext) { }
/// \brief Code completion for a member access expression.
///
@@ -2458,6 +2533,9 @@ public:
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
bool InInterface) { }
+ /// \brief Code completion after the '@' in the list of instance variables.
+ virtual void CodeCompleteObjCAtVisibility(Scope *S) { }
+
/// \brief Code completion after the '@' in a statement.
virtual void CodeCompleteObjCAtStatement(Scope *S) { }
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 7c99e3e58254..6a3d8a924e07 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -194,6 +194,7 @@ private:
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc;
+ SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
SourceLocation FriendLoc, ConstexprLoc;
@@ -257,6 +258,9 @@ public:
SourceLocation getTypeSpecSignLoc() const { return TSSLoc; }
SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; }
+ SourceRange getTypeofParensRange() const { return TypeofParensRange; }
+ void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
+
/// getSpecifierName - Turn a type-specifier-type into a string like "_Bool"
/// or "union".
static const char *getSpecifierName(DeclSpec::TST T);
@@ -493,6 +497,8 @@ public:
IK_LiteralOperatorId,
/// \brief A constructor name.
IK_ConstructorName,
+ /// \brief A constructor named via a template-id.
+ IK_ConstructorTemplateId,
/// \brief A destructor name.
IK_DestructorName,
/// \brief A template-id, e.g., f<int>.
@@ -534,8 +540,9 @@ public:
/// class-name.
ActionBase::TypeTy *DestructorName;
- /// \brief When Kind == IK_TemplateId, the template-id annotation that
- /// contains the template name and template arguments.
+ /// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
+ /// the template-id annotation that contains the template name and
+ /// template arguments.
TemplateIdAnnotation *TemplateId;
};
@@ -648,6 +655,14 @@ public:
ConstructorName = ClassType;
}
+ /// \brief Specify that this unqualified-id was parsed as a
+ /// template-id that names a constructor.
+ ///
+ /// \param TemplateId the template-id annotation that describes the parsed
+ /// template-id. This UnqualifiedId instance will take ownership of the
+ /// \p TemplateId and will free it on destruction.
+ void setConstructorTemplateId(TemplateIdAnnotation *TemplateId);
+
/// \brief Specify that this unqualified-id was parsed as a destructor name.
///
/// \param TildeLoc the location of the '~' that introduces the destructor
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2214797b8f7b..0fc9413c30c3 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -784,7 +784,7 @@ private:
llvm::SmallVector<DeclPtrTy, 4> PendingObjCImpDecl;
DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
- DeclPtrTy ParseObjCAtEndDeclaration(SourceLocation atLoc);
+ DeclPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
DeclPtrTy ParseObjCAtAliasDeclaration(SourceLocation atLoc);
DeclPtrTy ParseObjCPropertySynthesize(SourceLocation atLoc);
DeclPtrTy ParseObjCPropertyDynamic(SourceLocation atLoc);
@@ -1037,7 +1037,8 @@ private:
/// would be best implemented in the parser.
enum DeclSpecContext {
DSC_normal, // normal context
- DSC_class // class context, enables 'friend'
+ DSC_class, // class context, enables 'friend'
+ DSC_top_level // top-level/namespace declaration context
};
DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd,
@@ -1056,6 +1057,7 @@ private:
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS);
+ DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
void ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
@@ -1109,6 +1111,11 @@ private:
return isDeclarationSpecifier();
}
+ /// \brief Starting with a scope specifier, identifier, or
+ /// template-id that refers to the current class, determine whether
+ /// this is a constructor declarator.
+ bool isConstructorDeclarator();
+
/// \brief Specifies the context in which type-id/expression
/// disambiguation will occur.
enum TentativeCXXTypeIdContext {
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
index 29e78fa27958..1692180a6da9 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -146,13 +146,13 @@ public:
/// are in the same file. If not, this returns -1.
int getRangeSize(SourceRange Range) const;
- /// getRewritenText - Return the rewritten form of the text in the specified
+ /// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
///
- std::string getRewritenText(SourceRange Range) const;
+ std::string getRewrittenText(SourceRange Range) const;
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index aec10f32fe63..348917a7d034 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -85,7 +85,18 @@ public:
/// \brief A right angle bracket ('>').
CK_RightAngle,
/// \brief A comma separator (',').
- CK_Comma
+ CK_Comma,
+ /// \brief A colon (':').
+ CK_Colon,
+ /// \brief A semicolon (';').
+ CK_SemiColon,
+ /// \brief An '=' sign.
+ CK_Equal,
+ /// \brief Horizontal whitespace (' ').
+ CK_HorizontalSpace,
+ /// \brief Verticle whitespace ('\n' or '\r\n', depending on the
+ /// platform).
+ CK_VerticalSpace
};
/// \brief One piece of the code completion string.
@@ -270,10 +281,6 @@ public:
IdentifierInfo *Macro;
};
- /// \brief Describes how good this result is, with zero being the best
- /// result and progressively higher numbers representing poorer results.
- unsigned Rank;
-
/// \brief Specifiers which parameter (of a function, Objective-C method,
/// macro, etc.) we should start with when formatting the result.
unsigned StartParameter;
@@ -298,32 +305,32 @@ public:
NestedNameSpecifier *Qualifier;
/// \brief Build a result that refers to a declaration.
- Result(NamedDecl *Declaration, unsigned Rank,
+ Result(NamedDecl *Declaration,
NestedNameSpecifier *Qualifier = 0,
bool QualifierIsInformative = false)
- : Kind(RK_Declaration), Declaration(Declaration), Rank(Rank),
+ : Kind(RK_Declaration), Declaration(Declaration),
StartParameter(0), Hidden(false),
QualifierIsInformative(QualifierIsInformative),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(Qualifier) { }
/// \brief Build a result that refers to a keyword or symbol.
- Result(const char *Keyword, unsigned Rank)
- : Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), StartParameter(0),
+ Result(const char *Keyword)
+ : Kind(RK_Keyword), Keyword(Keyword), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
/// \brief Build a result that refers to a macro.
- Result(IdentifierInfo *Macro, unsigned Rank)
- : Kind(RK_Macro), Macro(Macro), Rank(Rank), StartParameter(0),
+ Result(IdentifierInfo *Macro)
+ : Kind(RK_Macro), Macro(Macro), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
/// \brief Build a result that refers to a pattern.
- Result(CodeCompletionString *Pattern, unsigned Rank)
- : Kind(RK_Pattern), Pattern(Pattern), Rank(Rank), StartParameter(0),
+ Result(CodeCompletionString *Pattern)
+ : Kind(RK_Pattern), Pattern(Pattern), StartParameter(0),
Hidden(false), QualifierIsInformative(0),
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
Qualifier(0) { }
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 772a884c90d3..50a6e0a50d8b 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -12,9 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/APValue.h"
+#include "clang/AST/CharUnits.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+namespace {
+ struct LV {
+ Expr* Base;
+ CharUnits Offset;
+ };
+}
+
+APValue::APValue(Expr* B) : Kind(Uninitialized) {
+ MakeLValue(); setLValue(B, CharUnits::Zero());
+}
const APValue &APValue::operator=(const APValue &RHS) {
if (Kind != RHS.Kind) {
@@ -106,3 +117,25 @@ void APValue::print(llvm::raw_ostream &OS) const {
}
}
+Expr* APValue::getLValueBase() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Base;
+}
+
+CharUnits APValue::getLValueOffset() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->Offset;
+}
+
+void APValue::setLValue(Expr *B, const CharUnits &O) {
+ assert(isLValue() && "Invalid accessor");
+ ((LV*)(char*)Data)->Base = B;
+ ((LV*)(char*)Data)->Offset = O;
+}
+
+void APValue::MakeLValue() {
+ assert(isUninit() && "Bad state change");
+ new ((void*)(char*)Data) LV();
+ Kind = LValue;
+}
+
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 74e74e7aba0b..76ec852cb89e 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -814,10 +814,10 @@ ASTContext::getTypeInfo(const Type *T) {
/// getTypeSizeInChars - Return the size of the specified type, in characters.
/// This method does not work on incomplete types.
CharUnits ASTContext::getTypeSizeInChars(QualType T) {
- return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
+ return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
- return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
+ return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
}
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
@@ -2374,16 +2374,14 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
QualType ASTContext::getUnqualifiedArrayType(QualType T,
Qualifiers &Quals) {
- assert(T.isCanonical() && "Only operates on canonical types");
+ Quals = T.getQualifiers();
if (!isa<ArrayType>(T)) {
- Quals = T.getLocalQualifiers();
- return T.getLocalUnqualifiedType();
+ return T.getUnqualifiedType();
}
- assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
const ArrayType *AT = cast<ArrayType>(T);
QualType Elt = AT->getElementType();
- QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals);
+ QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
if (Elt == UnqualElt)
return T;
@@ -2396,12 +2394,6 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T,
return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
}
- if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) {
- return getVariableArrayType(UnqualElt, VAT->getSizeExpr()->Retain(),
- VAT->getSizeModifier(), 0,
- SourceRange());
- }
-
const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
DSAT->getSizeModifier(), 0,
@@ -3143,16 +3135,21 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
-int ASTContext::getObjCEncodingTypeSize(QualType type) {
- uint64_t sz = getTypeSize(type);
+CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) {
+ CharUnits sz = getTypeSizeInChars(type);
// Make all integer and enum types at least as large as an int
- if (sz > 0 && type->isIntegralType())
- sz = std::max(sz, getTypeSize(IntTy));
+ if (sz.isPositive() && type->isIntegralType())
+ sz = std::max(sz, getTypeSizeInChars(IntTy));
// Treat arrays as pointers, since that's how they're passed in.
else if (type->isArrayType())
- sz = getTypeSize(VoidPtrTy);
- return sz / getTypeSize(CharTy);
+ sz = getTypeSizeInChars(VoidPtrTy);
+ return sz;
+}
+
+static inline
+std::string charUnitsToString(const CharUnits &CU) {
+ return llvm::itostr(CU.getQuantity());
}
/// getObjCEncodingForBlockDecl - Return the encoded type for this method
@@ -3168,17 +3165,17 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
- int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
- int ParmOffset = PtrSize;
+ CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
+ CharUnits ParmOffset = PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
- int sz = getObjCEncodingTypeSize(PType);
- assert (sz > 0 && "BlockExpr - Incomplete param type");
+ CharUnits sz = getObjCEncodingTypeSize(PType);
+ assert (sz.isPositive() && "BlockExpr - Incomplete param type");
ParmOffset += sz;
}
// Size of the argument frame
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
// Block pointer and offset.
S += "@?0";
ParmOffset = PtrSize;
@@ -3198,7 +3195,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
} else if (PType->isFunctionType())
PType = PVDecl->getType();
getObjCEncodingForType(PType, S);
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
}
@@ -3216,20 +3213,21 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
- int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
// The first two arguments (self and _cmd) are pointers; account for
// their size.
- int ParmOffset = 2 * PtrSize;
+ CharUnits ParmOffset = 2 * PtrSize;
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
- int sz = getObjCEncodingTypeSize(PType);
- assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
+ CharUnits sz = getObjCEncodingTypeSize(PType);
+ assert (sz.isPositive() &&
+ "getObjCEncodingForMethodDecl - Incomplete param type");
ParmOffset += sz;
}
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
S += "@0:";
- S += llvm::utostr(PtrSize);
+ S += charUnitsToString(PtrSize);
// Argument types.
ParmOffset = 2 * PtrSize;
@@ -3249,7 +3247,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
// 'in', 'inout', etc.
getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
getObjCEncodingForType(PType, S);
- S += llvm::utostr(ParmOffset);
+ S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
new file mode 100644
index 000000000000..02c70b651119
--- /dev/null
+++ b/lib/AST/AttrImpl.cpp
@@ -0,0 +1,143 @@
+//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains out-of-line virtual methods for Attr classes.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+
+#define DEF_SIMPLE_ATTR_CLONE(ATTR) \
+ Attr *ATTR##Attr::clone(ASTContext &C) const { \
+ return ::new (C) ATTR##Attr; \
+ }
+
+// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for
+// "non-simple" classes?
+
+DEF_SIMPLE_ATTR_CLONE(Packed)
+DEF_SIMPLE_ATTR_CLONE(AlwaysInline)
+DEF_SIMPLE_ATTR_CLONE(Malloc)
+DEF_SIMPLE_ATTR_CLONE(NoReturn)
+DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn)
+DEF_SIMPLE_ATTR_CLONE(Deprecated)
+DEF_SIMPLE_ATTR_CLONE(Final)
+DEF_SIMPLE_ATTR_CLONE(Unavailable)
+DEF_SIMPLE_ATTR_CLONE(Unused)
+DEF_SIMPLE_ATTR_CLONE(Used)
+DEF_SIMPLE_ATTR_CLONE(Weak)
+DEF_SIMPLE_ATTR_CLONE(WeakImport)
+DEF_SIMPLE_ATTR_CLONE(NoThrow)
+DEF_SIMPLE_ATTR_CLONE(Const)
+DEF_SIMPLE_ATTR_CLONE(Pure)
+DEF_SIMPLE_ATTR_CLONE(FastCall)
+DEF_SIMPLE_ATTR_CLONE(StdCall)
+DEF_SIMPLE_ATTR_CLONE(CDecl)
+DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
+DEF_SIMPLE_ATTR_CLONE(ObjCNSObject)
+DEF_SIMPLE_ATTR_CLONE(ObjCException)
+DEF_SIMPLE_ATTR_CLONE(NoDebug)
+DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult)
+DEF_SIMPLE_ATTR_CLONE(NoInline)
+DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained)
+DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
+DEF_SIMPLE_ATTR_CLONE(BaseCheck)
+DEF_SIMPLE_ATTR_CLONE(Hiding)
+DEF_SIMPLE_ATTR_CLONE(Override)
+DEF_SIMPLE_ATTR_CLONE(DLLImport)
+DEF_SIMPLE_ATTR_CLONE(DLLExport)
+
+Attr* PragmaPackAttr::clone(ASTContext &C) const {
+ return ::new (C) PragmaPackAttr(Alignment);
+}
+
+Attr* AlignedAttr::clone(ASTContext &C) const {
+ return ::new (C) AlignedAttr(Alignment);
+}
+
+Attr* AnnotateAttr::clone(ASTContext &C) const {
+ return ::new (C) AnnotateAttr(Annotation);
+}
+
+Attr *AsmLabelAttr::clone(ASTContext &C) const {
+ return ::new (C) AsmLabelAttr(Label);
+}
+
+Attr *AliasAttr::clone(ASTContext &C) const {
+ return ::new (C) AliasAttr(Aliasee);
+}
+
+Attr *ConstructorAttr::clone(ASTContext &C) const {
+ return ::new (C) ConstructorAttr(priority);
+}
+
+Attr *DestructorAttr::clone(ASTContext &C) const {
+ return ::new (C) DestructorAttr(priority);
+}
+
+Attr *IBOutletAttr::clone(ASTContext &C) const {
+ return ::new (C) IBOutletAttr;
+}
+
+Attr *GNUInlineAttr::clone(ASTContext &C) const {
+ return ::new (C) GNUInlineAttr;
+}
+
+Attr *SectionAttr::clone(ASTContext &C) const {
+ return ::new (C) SectionAttr(Name);
+}
+
+Attr *NonNullAttr::clone(ASTContext &C) const {
+ return ::new (C) NonNullAttr(ArgNums, Size);
+}
+
+Attr *FormatAttr::clone(ASTContext &C) const {
+ return ::new (C) FormatAttr(Type, formatIdx, firstArg);
+}
+
+Attr *FormatArgAttr::clone(ASTContext &C) const {
+ return ::new (C) FormatArgAttr(formatIdx);
+}
+
+Attr *SentinelAttr::clone(ASTContext &C) const {
+ return ::new (C) SentinelAttr(sentinel, NullPos);
+}
+
+Attr *VisibilityAttr::clone(ASTContext &C) const {
+ return ::new (C) VisibilityAttr(VisibilityType);
+}
+
+Attr *OverloadableAttr::clone(ASTContext &C) const {
+ return ::new (C) OverloadableAttr;
+}
+
+Attr *BlocksAttr::clone(ASTContext &C) const {
+ return ::new (C) BlocksAttr(BlocksAttrType);
+}
+
+Attr *CleanupAttr::clone(ASTContext &C) const {
+ return ::new (C) CleanupAttr(FD);
+}
+
+Attr *RegparmAttr::clone(ASTContext &C) const {
+ return ::new (C) RegparmAttr(NumParams);
+}
+
+Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const {
+ return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
+}
+
+Attr *MSP430InterruptAttr::clone(ASTContext &C) const {
+ return ::new (C) MSP430InterruptAttr(Number);
+}
+
+
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 5aecf878c920..dea96e7866ec 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
+ AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
DeclBase.cpp
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e112fa3928de..e77661a9fbd4 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -957,7 +957,7 @@ bool FunctionDecl::isInlined() const {
/// "externally" visible to other translation units in the program.
///
/// In C99, inline definitions are not externally visible by default. However,
-/// if even one of the globa-scope declarations is marked "extern inline", the
+/// if even one of the global-scope declarations is marked "extern inline", the
/// inline definition becomes externally visible (C99 6.7.4p6).
///
/// In GNU89 mode, or if the gnu_inline attribute is attached to the function
@@ -1039,6 +1039,15 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
return OO_None;
}
+/// getLiteralIdentifier - The literal suffix identifier this function
+/// represents, if any.
+const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
+ if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName)
+ return getDeclName().getCXXLiteralIdentifier();
+ else
+ return 0;
+}
+
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
return cast<FunctionDecl>(Info->getInstantiatedFrom());
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index bbbb19a35b4a..1cce35c0b39a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -144,6 +144,19 @@ CXXRecordDecl::setBases(ASTContext &C,
}
}
+/// Callback function for CXXRecordDecl::forallBases that acknowledges
+/// that it saw a base class.
+static bool SawBase(const CXXRecordDecl *, void *) {
+ return true;
+}
+
+bool CXXRecordDecl::hasAnyDependentBases() const {
+ if (!isDependentContext())
+ return false;
+
+ return !forallBases(SawBase, 0);
+}
+
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
@@ -643,23 +656,15 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
return C.getPointerType(ClassTy);
}
-static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) {
- // Simple case: function has a body
- if (MD->getBody(fn))
- return true;
-
- // Complex case: function is an instantiation of a function which has a
- // body, but the definition hasn't been instantiated.
- const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern();
- if (PatternDecl && PatternDecl->getBody(fn))
- return true;
-
- return false;
-}
-
bool CXXMethodDecl::hasInlineBody() const {
+ // If this function is a template instantiation, look at the template from
+ // which it was instantiated.
+ const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
+ if (!CheckFn)
+ CheckFn = this;
+
const FunctionDecl *fn;
- return MethodHasBody(this, fn) && !fn->isOutOfLine();
+ return CheckFn->getBody(fn) && !fn->isOutOfLine();
}
CXXBaseOrMemberInitializer::
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 60c40e24fb31..ff810735bc81 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -56,9 +56,14 @@ public:
/// 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 {
+class CXXLiteralOperatorIdName
+ : public DeclarationNameExtra, public llvm::FoldingSetNode {
public:
IdentifierInfo *ID;
+
+ void Profile(llvm::FoldingSetNodeID &FSID) {
+ FSID.AddPointer(ID);
+ }
};
bool operator<(DeclarationName LHS, DeclarationName RHS) {
@@ -180,6 +185,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
return Identifier;
}
+bool DeclarationName::isDependentName() const {
+ QualType T = getCXXNameType();
+ return !T.isNull() && T->isDependentType();
+}
+
std::string DeclarationName::getAsString() const {
switch (getNameKind()) {
case Identifier:
@@ -353,6 +363,7 @@ void DeclarationName::dump() const {
DeclarationNameTable::DeclarationNameTable() {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
+ CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
// Initialize the overloaded operator names.
CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
@@ -364,16 +375,30 @@ DeclarationNameTable::DeclarationNameTable() {
}
DeclarationNameTable::~DeclarationNameTable() {
- llvm::FoldingSet<CXXSpecialName> *set =
+ llvm::FoldingSet<CXXSpecialName> *SpecialNames =
static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
- llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end();
+ llvm::FoldingSetIterator<CXXSpecialName>
+ SI = SpecialNames->begin(), SE = SpecialNames->end();
+
+ while (SI != SE) {
+ CXXSpecialName *n = &*SI++;
+ delete n;
+ }
- while (I != E) {
- CXXSpecialName *n = &*I++;
+
+ llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+ = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+ (CXXLiteralOperatorNames);
+ llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
+ LI = LiteralNames->begin(), LE = LiteralNames->end();
+
+ while (LI != LE) {
+ CXXLiteralOperatorIdName *n = &*LI++;
delete n;
}
- delete set;
+ delete SpecialNames;
+ delete LiteralNames;
delete [] CXXOperatorNames;
}
@@ -428,9 +453,23 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
DeclarationName
DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
+ llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
+ = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
+ (CXXLiteralOperatorNames);
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(II);
+
+ void *InsertPos = 0;
+ if (CXXLiteralOperatorIdName *Name =
+ LiteralNames->FindNodeOrInsertPos(ID, InsertPos))
+ return DeclarationName (Name);
+
CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
LiteralName->ID = II;
+
+ LiteralNames->InsertNode(LiteralName, InsertPos);
return DeclarationName(LiteralName);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 04a6abca87c9..4c3046bed10b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2154,7 +2154,8 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
+DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
+ unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
bool GNUSyntax,
@@ -2165,7 +2166,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
Init->isTypeDependent(), Init->isValueDependent()),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
- this->Designators = new Designator[NumDesignators];
+ this->Designators = new (C) Designator[NumDesignators];
// Record the initializer itself.
child_iterator Child = child_begin();
@@ -2210,7 +2211,7 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
bool UsesColonSyntax, Expr *Init) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
- return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
+ return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
ColonOrEqualLoc, UsesColonSyntax,
IndexExprs, NumIndexExprs, Init);
}
@@ -2222,12 +2223,12 @@ DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
-void DesignatedInitExpr::setDesignators(const Designator *Desigs,
+void DesignatedInitExpr::setDesignators(ASTContext &C,
+ const Designator *Desigs,
unsigned NumDesigs) {
- if (Designators)
- delete [] Designators;
+ DestroyDesignators(C);
- Designators = new Designator[NumDesigs];
+ Designators = new (C) Designator[NumDesigs];
NumDesignators = NumDesigs;
for (unsigned I = 0; I != NumDesigs; ++I)
Designators[I] = Desigs[I];
@@ -2276,7 +2277,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
+void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
@@ -2292,21 +2293,28 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
}
Designator *NewDesignators
- = new Designator[NumDesignators - 1 + NumNewDesignators];
+ = new (C) Designator[NumDesignators - 1 + NumNewDesignators];
std::copy(Designators, Designators + Idx, NewDesignators);
std::copy(First, Last, NewDesignators + Idx);
std::copy(Designators + Idx + 1, Designators + NumDesignators,
NewDesignators + Idx + NumNewDesignators);
- delete [] Designators;
+ DestroyDesignators(C);
Designators = NewDesignators;
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
void DesignatedInitExpr::DoDestroy(ASTContext &C) {
- delete [] Designators;
+ DestroyDesignators(C);
Expr::DoDestroy(C);
}
+void DesignatedInitExpr::DestroyDesignators(ASTContext &C) {
+ for (unsigned I = 0; I != NumDesignators; ++I)
+ Designators[I].~Designator();
+ C.Deallocate(Designators);
+ Designators = 0;
+}
+
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
Expr **exprs, unsigned nexprs,
SourceLocation rparenloc)
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 06afec7675f1..dfff2099cbd6 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/ASTDiagnostic.h"
@@ -69,11 +70,12 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info);
static bool EvalPointerValueAsBool(APValue& Value, bool& Result) {
// FIXME: Is this accurate for all kinds of bases? If not, what would
// the check look like?
- Result = Value.getLValueBase() || Value.getLValueOffset();
+ Result = Value.getLValueBase() || !Value.getLValueOffset().isZero();
return true;
}
-static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
+static bool HandleConversionToBool(const Expr* E, bool& Result,
+ EvalInfo &Info) {
if (E->getType()->isIntegralType()) {
APSInt IntResult;
if (!EvaluateInteger(E, IntResult, Info))
@@ -222,11 +224,11 @@ public:
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
APValue VisitDeclRefExpr(DeclRefExpr *E);
- APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
+ APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
APValue VisitMemberExpr(MemberExpr *E);
- APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
- APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); }
+ APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); }
+ APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); }
APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E);
APValue VisitUnaryDeref(UnaryOperator *E);
APValue VisitUnaryExtension(const UnaryOperator *E)
@@ -254,12 +256,12 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
- return APValue(E, 0);
+ return APValue(E);
} else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
if (!Info.AnyLValue && !VD->hasGlobalStorage())
return APValue();
if (!VD->getType()->isReferenceType())
- return APValue(E, 0);
+ return APValue(E);
// FIXME: Check whether VD might be overridden!
const VarDecl *Def = 0;
if (const Expr *Init = VD->getDefinition(Def))
@@ -272,7 +274,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
if (!Info.AnyLValue && !E->isFileScope())
return APValue();
- return APValue(E, 0);
+ return APValue(E);
}
APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
@@ -309,7 +311,8 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
}
result.setLValue(result.getLValueBase(),
- result.getLValueOffset() + RL.getFieldOffset(i) / 8);
+ result.getLValueOffset() +
+ CharUnits::fromQuantity(RL.getFieldOffset(i) / 8));
return result;
}
@@ -324,9 +327,9 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!EvaluateInteger(E->getIdx(), Index, Info))
return APValue();
- uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8;
+ CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
- uint64_t Offset = Index.getSExtValue() * ElementSize;
+ CharUnits Offset = Index.getSExtValue() * ElementSize;
Result.setLValue(Result.getLValueBase(),
Result.getLValueOffset() + Offset);
return Result;
@@ -363,22 +366,22 @@ public:
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryAddrOf(const UnaryOperator *E);
APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
- { return APValue(E, 0); }
+ { return APValue(E); }
APValue VisitAddrLabelExpr(AddrLabelExpr *E)
- { return APValue(E, 0); }
+ { return APValue(E); }
APValue VisitCallExpr(CallExpr *E);
APValue VisitBlockExpr(BlockExpr *E) {
if (!E->hasBlockDeclRefExprs())
- return APValue(E, 0);
+ return APValue(E);
return APValue();
}
APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
- { return APValue((Expr*)0, 0); }
+ { return APValue((Expr*)0); }
APValue VisitConditionalOperator(ConditionalOperator *E);
APValue VisitChooseExpr(ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
- { return APValue((Expr*)0, 0); }
+ { return APValue((Expr*)0); }
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
@@ -409,15 +412,15 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return APValue();
QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
- uint64_t SizeOfPointee;
+ CharUnits SizeOfPointee;
// Explicitly handle GNU void* and function pointer arithmetic extensions.
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
- SizeOfPointee = 1;
+ SizeOfPointee = CharUnits::One();
else
- SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
+ SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
- uint64_t Offset = ResultLValue.getLValueOffset();
+ CharUnits Offset = ResultLValue.getLValueOffset();
if (E->getOpcode() == BinaryOperator::Add)
Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
@@ -459,7 +462,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
if (Result.isInt()) {
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0, Result.getInt().getZExtValue());
+ return APValue(0,
+ CharUnits::fromQuantity(Result.getInt().getZExtValue()));
}
// Cast is of an lvalue, no need to change value.
@@ -481,7 +485,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
if (Result.isInt()) {
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- return APValue(0, Result.getInt().getZExtValue());
+ return APValue(0,
+ CharUnits::fromQuantity(Result.getInt().getZExtValue()));
}
// Cast is of an lvalue, no need to change value.
@@ -502,7 +507,7 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString)
- return APValue(E, 0);
+ return APValue(E);
return APValue();
}
@@ -976,20 +981,20 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
&& VD->getType()->isObjectType()
&& !VD->getType()->isVariablyModifiedType()
&& !VD->getType()->isDependentType()) {
- uint64_t Size = Info.Ctx.getTypeSize(VD->getType()) / 8;
- uint64_t Offset = Base.Val.getLValueOffset();
- if (Offset <= Size)
- Size -= Base.Val.getLValueOffset();
+ CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType());
+ CharUnits Offset = Base.Val.getLValueOffset();
+ if (!Offset.isNegative() && Offset <= Size)
+ Size -= Offset;
else
- Size = 0;
- return Success(Size, E);
+ Size = CharUnits::Zero();
+ return Success(Size.getQuantity(), E);
}
}
}
// TODO: Perhaps we should let LLVM lower this?
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
- if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0)
+ if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
return Success(0, E);
}
@@ -1151,7 +1156,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (LHSValue.getLValueBase()) {
if (!E->isEqualityOp())
return false;
- if (RHSValue.getLValueBase() || RHSValue.getLValueOffset())
+ if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())
return false;
bool bres;
if (!EvalPointerValueAsBool(LHSValue, bres))
@@ -1160,7 +1165,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else if (RHSValue.getLValueBase()) {
if (!E->isEqualityOp())
return false;
- if (LHSValue.getLValueBase() || LHSValue.getLValueOffset())
+ if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())
return false;
bool bres;
if (!EvalPointerValueAsBool(RHSValue, bres))
@@ -1172,11 +1177,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
const QualType Type = E->getLHS()->getType();
const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
- uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset();
+ CharUnits ElementSize = CharUnits::One();
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
- D /= Info.Ctx.getTypeSize(ElementType) / 8;
+ ElementSize = Info.Ctx.getTypeSizeInChars(ElementType);
- return Success(D, E);
+ CharUnits Diff = LHSValue.getLValueOffset() -
+ RHSValue.getLValueOffset();
+ return Success(Diff / ElementSize, E);
}
bool Result;
if (E->getOpcode() == BinaryOperator::EQ) {
@@ -1204,21 +1211,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
- uint64_t offset = Result.getLValueOffset();
+ CharUnits Offset = Result.getLValueOffset();
+ CharUnits AdditionalOffset = CharUnits::fromQuantity(
+ RHSVal.getInt().getZExtValue());
if (E->getOpcode() == BinaryOperator::Add)
- offset += RHSVal.getInt().getZExtValue();
+ Offset += AdditionalOffset;
else
- offset -= RHSVal.getInt().getZExtValue();
- Result = APValue(Result.getLValueBase(), offset);
+ Offset -= AdditionalOffset;
+ Result = APValue(Result.getLValueBase(), Offset);
return true;
}
// Handle cases like 4 + (unsigned long)&a
if (E->getOpcode() == BinaryOperator::Add &&
RHSVal.isLValue() && Result.isInt()) {
- uint64_t offset = RHSVal.getLValueOffset();
- offset += Result.getInt().getZExtValue();
- Result = APValue(RHSVal.getLValueBase(), offset);
+ CharUnits Offset = RHSVal.getLValueOffset();
+ Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
+ Result = APValue(RHSVal.getLValueBase(), Offset);
return true;
}
@@ -1334,8 +1343,7 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
return false;
// Get information about the size.
- unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy);
- return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E);
+ return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1349,7 +1357,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (LV.getLValueBase())
return false;
- return Success(LV.getLValueOffset(), E);
+ return Success(LV.getLValueOffset().getQuantity(), E);
}
if (E->getOpcode() == UnaryOperator::LNot) {
@@ -1432,7 +1440,8 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
return true;
}
- APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType);
+ APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
+ SrcType);
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
}
@@ -1978,6 +1987,13 @@ bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const {
return true;
}
+bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const {
+ EvalResult Scratch;
+ EvalInfo Info(Ctx, Scratch);
+
+ return HandleConversionToBool(this, Result, Info);
+}
+
bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index c914f3f82e8e..cfd89eaed350 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -719,11 +719,6 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
// If a class isnt' polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
-
- // A class template specialization or instantation does not have a key
- // function.
- if (RD->getTemplateSpecializationKind() != TSK_Undeclared)
- return 0;
// A class inside an anonymous namespace doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
@@ -741,13 +736,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (MD->isPure())
continue;
- if (MD->isInlineSpecified())
- continue;
-
// Ignore implicit member functions, they are always marked as inline, but
// they don't have a body until they're defined.
if (MD->isImplicit())
continue;
+
+ if (MD->isInlineSpecified())
+ continue;
if (MD->hasInlineBody())
continue;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 7c7aeb8d3e1d..104e3361892f 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -337,12 +337,12 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
//===----------------------------------------------------------------------===//
AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
- unsigned numoutputs, unsigned numinputs,
+ bool msasm, unsigned numoutputs, unsigned numinputs,
std::string *names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc)
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
- , IsSimple(issimple), IsVolatile(isvolatile)
+ , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
, NumOutputs(numoutputs), NumInputs(numinputs) {
for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
Names.push_back(names[i]);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a7e42af04d81..bbb904de79b3 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -739,9 +739,10 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
+ if (FD->isAnonymousStructOrUnion())
+ return;
OS << (Node->isArrow() ? "->" : ".");
- // FIXME: Suppress printing references to unnamed objects
- // representing anonymous unions/structs
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
@@ -1120,6 +1121,13 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ // FIXME. For now we just print a trivial constructor call expression,
+ // constructing its first argument object.
+ if (E->getNumArgs() == 1) {
+ CXXConstructorDecl *CD = E->getConstructor();
+ if (CD->isTrivial())
+ PrintExpr(E->getArg(0));
+ }
// Nothing to print.
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 3ccb7a9cc613..0840c52b4c20 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/Expr.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -123,3 +124,14 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
if (TL->getType().hasLocalQualifiers()) return false;
return TSTChecker().Visit(*TL);
}
+
+// Reimplemented to account for GNU/C++ extension
+// typeof unary-expression
+// where there are no parentheses.
+SourceRange TypeOfExprTypeLoc::getSourceRange() const {
+ if (getRParenLoc().isValid())
+ return SourceRange(getTypeofLoc(), getRParenLoc());
+ else
+ return SourceRange(getTypeofLoc(),
+ getUnderlyingExpr()->getSourceRange().getEnd());
+}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 818657c2a763..00b74bc21a14 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -271,6 +271,10 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+
+
if (T->hasExceptionSpec()) {
S += " throw(";
if (T->hasAnyExceptionSpec())
@@ -287,10 +291,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
}
- if (T->getNoReturnAttr())
- S += " __attribute__((noreturn))";
- Print(T->getResultType(), S);
+ AppendTypeQualList(S, T->getTypeQuals());
+ Print(T->getResultType(), S);
}
void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 97e6d914d450..2093b5e23e85 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() {
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getBody();
+ else if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ return FunTmpl->getTemplatedDecl()->getBody();
llvm_unreachable("unknown code decl");
}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index 6c3f7b2245df..6dfc470530a4 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -49,8 +49,9 @@ class BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
- BasicConstraintManager(GRStateManager& statemgr)
- : ISetFactory(statemgr.getAllocator()) {}
+ BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine),
+ ISetFactory(statemgr.getAllocator()) {}
const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
const llvm::APSInt& V);
@@ -88,9 +89,9 @@ public:
} // end anonymous namespace
-ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr)
-{
- return new BasicConstraintManager(StateMgr);
+ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine) {
+ return new BasicConstraintManager(statemgr, subengine);
}
const GRState*
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index e6482698dd43..2a9531df60f1 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
R->getRanges(Beg, End);
Diagnostic& Diag = getDiagnostic();
FullSourceLoc L(R->getLocation(), getSourceManager());
- unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
- R->getShortDescription().c_str());
+
+ // Search the description for '%', as that will be interpretted as a
+ // format character by FormatDiagnostics.
+ llvm::StringRef desc = R->getShortDescription();
+ unsigned ErrorDiag;
+ {
+ llvm::SmallString<512> TmpStr;
+ llvm::raw_svector_ostream Out(TmpStr);
+ for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+ if (*I == '%')
+ Out << "%%";
+ else
+ Out << *I;
+
+ Out.flush();
+ ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
+ }
switch (End-Beg) {
default: assert(0 && "Don't handle this many ranges yet!");
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index a15a8f16c46f..5a15fbfb1f05 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -52,8 +52,8 @@ using namespace clang;
// not release it."
//
-using llvm::CStrInCStrNoCase;
-using llvm::StringsEqualNoCase;
+using llvm::StrInStrNoCase;
+using llvm::StringRef;
enum NamingConvention { NoConvention, CreateRule, InitRule };
@@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) {
break;
case 3:
// Methods starting with 'new' follow the create rule.
- if (AtBeginning && StringsEqualNoCase("new", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("new"))
C = CreateRule;
break;
case 4:
// Methods starting with 'alloc' or contain 'copy' follow the
// create rule
- if (C == NoConvention && StringsEqualNoCase("copy", s, len))
+ if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
C = CreateRule;
else // Methods starting with 'init' follow the init rule.
- if (AtBeginning && StringsEqualNoCase("init", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("init"))
C = InitRule;
break;
case 5:
- if (AtBeginning && StringsEqualNoCase("alloc", s, len))
+ if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
C = CreateRule;
break;
}
@@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
// "AppendValue", or "SetAttribute", then we assume that arguments may
// "escape." This means that something else holds on to the object,
// allowing it be used even after its local retain count drops to 0.
- ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
- CStrInCStrNoCase(FName, "AddValue") ||
- CStrInCStrNoCase(FName, "SetValue") ||
- CStrInCStrNoCase(FName, "AppendValue") ||
- CStrInCStrNoCase(FName, "SetAttribute"))
+ ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
+ StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
+ StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
+ StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
? MayEscape : DoNothing;
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
@@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
if (S.isKeywordSelector()) {
const std::string &str = S.getAsString();
assert(!str.empty());
- if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
+ if (StrInStrNoCase(str, "delegate:") != StringRef::npos)
+ ReceiverEff = StopTracking;
}
// Look for methods that return an owned object.
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index 3214101c6485..f4874a5dfe4c 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/TargetInfo.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
@@ -18,6 +19,12 @@
using namespace clang;
+static bool isArc4RandomAvailable(const ASTContext &Ctx) {
+ const llvm::Triple &T = Ctx.Target.getTriple();
+ return T.getVendor() == llvm::Triple::Apple ||
+ T.getOS() == llvm::Triple::FreeBSD;
+}
+
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
@@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
+
+ const bool CheckRand;
public:
WalkAST(BugReporter &br) : BR(br),
II_gets(0), II_getpw(0), II_mktemp(0),
- II_rand(), II_random(0), II_setid() {}
+ II_rand(), II_random(0), II_setid(),
+ CheckRand(isArc4RandomAvailable(BR.getContext())) {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
CheckCall_gets(CE, FD);
CheckCall_getpw(CE, FD);
CheckCall_mktemp(CE, FD);
- CheckCall_rand(CE, FD);
- CheckCall_random(CE, FD);
+ if (CheckRand) {
+ CheckCall_rand(CE, FD);
+ CheckCall_random(CE, FD);
+ }
}
// Recurse and check children.
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index dd2f08b48f76..f04cf7b05fed 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
}
case Stmt::IntegerLiteralClass: {
- return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
+ // In C++, this expression may have been bound to a temporary object.
+ SVal const *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
}
// Casts where the source and target type are the same
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 2ce8edd1cc46..40c12c9fec84 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Analysis/PathSensitive/Checker.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
}
-static bool CalleeReturnsReference(const CallExpr *CE) {
+static QualType GetCalleeReturnType(const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
QualType T = Callee->getType();
-
if (const PointerType *PT = T->getAs<PointerType>()) {
const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
T = FT->getResultType();
@@ -58,16 +58,35 @@ static bool CalleeReturnsReference(const CallExpr *CE) {
else {
const BlockPointerType *BT = T->getAs<BlockPointerType>();
T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
- }
- return T->isReferenceType();
+ }
+ return T;
+}
+
+static bool CalleeReturnsReference(const CallExpr *CE) {
+ return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
}
static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (!MD)
return false;
- return MD->getResultType()->isReferenceType();
+ return MD->getResultType()->getAs<ReferenceType>();
+}
+
+#ifndef NDEBUG
+static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (!MD)
+ return false;
+ QualType T = MD->getResultType();
+ return T->getAs<RecordType>() || T->getAs<ReferenceType>();
+}
+
+static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) {
+ QualType T = GetCalleeReturnType(CE);
+ return T->getAs<ReferenceType>() || T->getAs<RecordType>();
}
+#endif
//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
@@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
RegisterOSAtomicChecker(Eng);
}
-GRExprEngine::GRExprEngine(AnalysisManager &mgr)
+GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
: AMgr(mgr),
CoreEngine(mgr.getASTContext(), *this),
G(CoreEngine.getGraph()),
Builder(NULL),
StateMgr(G.getContext(), mgr.getStoreManagerCreator(),
- mgr.getConstraintManagerCreator(), G.getAllocator()),
+ mgr.getConstraintManagerCreator(), G.getAllocator(),
+ *this),
SymMgr(StateMgr.getSymbolManager()),
ValMgr(StateMgr.getValueManager()),
SVator(ValMgr.getSValuator()),
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
- BR(mgr, *this)
-{
+ BR(mgr, *this), TF(tf) {
// Register internal checks.
RegisterInternalChecks(*this);
+
+ // FIXME: Eventually remove the TF object entirely.
+ TF->RegisterChecks(*this);
+ TF->RegisterPrinters(getStateManager().Printers);
}
GRExprEngine::~GRExprEngine() {
@@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) {
- StateMgr.TF = tf;
- StateMgr.Checkers = &Checkers;
- tf->RegisterChecks(*this);
- tf->RegisterPrinters(getStateManager().Printers);
-}
-
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
if (!BatchAuditor)
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
@@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
+/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
+/// logic for handling assumptions on symbolic values.
+const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
+ bool assumption) {
+ for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+
+ if (!state)
+ return NULL;
+
+ state = I->second->EvalAssume(state, cond, assumption);
+ }
+
+ if (!state)
+ return NULL;
+
+ return TF->EvalAssume(state, cond, assumption);
+}
+
void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
CurrentStmt = CE.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
@@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr *C = cast<CallExpr>(Ex);
- assert(CalleeReturnsReference(C));
+ assert(CalleeReturnsReferenceOrRecord(C));
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
break;
}
@@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::ObjCMessageExprClass: {
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
- assert(ReceiverReturnsReference(ME));
+ assert(ReceiverReturnsReferenceOrRecord(ME));
VisitObjCMessageExpr(ME, Pred, Dst, true);
return;
}
@@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
case Stmt::UnaryOperatorClass:
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
return;
+
+ // In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::IntegerLiteralClass:
+ CreateCXXTemporaryObject(Ex, Pred, Dst);
+ return;
default:
// Arbitrary subexpressions can return aggregate temporaries that
@@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
do {
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
- DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal);
+ DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
+ CondV, CaseVal);
// Now "assume" that the case matches.
if (const GRState* stateNew = state->Assume(Res, true)) {
@@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
// Now "assume" that the case doesn't match. Add this state
// to the default state (if it is feasible).
- if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
- defaultIsFeasible = true;
- DefaultSt = stateNew;
+ if (DefaultSt) {
+ if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
+ defaultIsFeasible = true;
+ DefaultSt = stateNew;
+ }
+ else {
+ defaultIsFeasible = false;
+ DefaultSt = NULL;
+ }
}
-
+
// Concretize the next value in the range.
if (V1.Val.getInt() == V2.Val.getInt())
break;
@@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
QualType T = Ex->getTypeOfArgument();
- uint64_t amt;
+ CharUnits amt;
if (Ex->isSizeOf()) {
if (T == getContext().VoidTy) {
// sizeof(void) == 1 byte.
- amt = 1;
+ amt = CharUnits::One();
}
else if (!T.getTypePtr()->isConstantSizeType()) {
// FIXME: Add support for VLAs.
@@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
}
else {
// All other cases.
- amt = getContext().getTypeSize(T) / 8;
+ amt = getContext().getTypeSizeInChars(T);
}
}
else // Get alignment of the type.
- amt = getContext().getTypeAlign(T) / 8;
+ amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
+ GetState(Pred)->BindExpr(Ex,
+ ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
@@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet & Dst) {
// Get the this object region from StoreManager.
- Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType());
- MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V));
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
}
void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
@@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ // Bind the temporary object to the value of the expression. Then bind
+ // the expression to the location of the object.
+ SVal V = state->getSVal(Ex);
+
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXObjectRegion(Ex,
+ Pred->getLocationContext());
+
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+ }
+}
+
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 7415fa5f67e4..051d465f41b7 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) {
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
return scan(X->getRegion());
+ if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+ return scan(X->getLoc());
+
if (SymbolRef Sym = val.getAsSymbol())
return visitor.VisitSymbol(Sym);
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 74fe3bf5ee5c..87d60d340934 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -17,6 +17,7 @@
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathSensitive/ValueManager.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/StmtVisitor.h"
using namespace clang;
@@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
ID.AddPointer(superRegion);
}
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sRegion) {
+ ID.AddInteger((unsigned) CXXThisRegionKind);
+ ID.AddPointer(PT);
+ ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+ CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
const MemRegion* superRegion, Kind k) {
ID.AddInteger((unsigned) k);
@@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
}
void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- QualType T,
+ Expr const *Ex,
const MemRegion *sReg) {
- ID.AddPointer(T.getTypePtr());
+ ID.AddPointer(Ex);
ID.AddPointer(sReg);
}
void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, T, getSuperRegion());
+ ProfileRegion(ID, Ex, getSuperRegion());
}
//===----------------------------------------------------------------------===//
@@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "{ " << (void*) CL << " }";
}
+void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
+ os << "this";
+}
+
void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "element{" << superRegion << ','
<< Index << ',' << getElementType().getAsString() << '}';
@@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
}
-const FieldRegion *
+const FieldRegion*
MemRegionManager::getFieldRegion(const FieldDecl* d,
const MemRegion* superRegion){
return getSubRegion<FieldRegion>(d, superRegion);
@@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
return getSubRegion<ObjCIvarRegion>(d, superRegion);
}
-const CXXObjectRegion *
-MemRegionManager::getCXXObjectRegion(QualType T) {
- return getSubRegion<CXXObjectRegion>(T, getUnknownRegion());
+const CXXObjectRegion*
+MemRegionManager::getCXXObjectRegion(Expr const *E,
+ LocationContext const *LC) {
+ const StackFrameContext *SFC = LC->getCurrentStackFrame();
+ assert(SFC);
+ return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC) {
+ const StackFrameContext *STC = LC->getCurrentStackFrame();
+ assert(STC);
+ const PointerType *PT = thisPointerTy->getAs<PointerType>();
+ assert(PT);
+ return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
}
const AllocaRegion*
@@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const {
return isa<StackSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasHeapStorage() const {
- return isa<HeapSpaceRegion>(getMemorySpace());
-}
-
-bool MemRegion::hasHeapOrStackStorage() const {
- const MemSpaceRegion *MS = getMemorySpace();
- return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
-}
-
-bool MemRegion::hasGlobalsStorage() const {
- return isa<GlobalsSpaceRegion>(getMemorySpace());
+bool MemRegion::hasStackNonParametersStorage() const {
+ return isa<StackLocalsSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasParametersStorage() const {
+bool MemRegion::hasStackParametersStorage() const {
return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
@@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
}
RegionRawOffset ElementRegion::getAsRawOffset() const {
- int64_t offset = 0;
+ CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
const MemRegion *superR = NULL;
ASTContext &C = getContext();
@@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
break;
}
- int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
+ CharUnits size = C.getTypeSizeInChars(elemType);
offset += (i * size);
}
@@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
}
assert(superR && "super region cannot be NULL");
- return RegionRawOffset(superR, offset);
+ return RegionRawOffset(superR, offset.getQuantity());
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp
index cf16796b1b14..9d34e9ec5c8b 100644
--- a/lib/Analysis/OSAtomicChecker.cpp
+++ b/lib/Analysis/OSAtomicChecker.cpp
@@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
SVal location = state->getSVal(theValueExpr);
// Here we should use the value type of the region as the load type.
QualType LoadTy;
- if (const MemRegion *R = location.getAsRegion()) {
- // We must be careful, as SymbolicRegions aren't typed.
- const MemRegion *strippedR = R->StripCasts();
- // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m'
- // is giving the wrong result.
- const TypedRegion *typedR =
- isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) :
- dyn_cast<TypedRegion>(strippedR);
-
- if (typedR) {
- LoadTy = typedR->getValueType(Ctx);
- location = loc::MemRegionVal(typedR);
- }
+ if (const TypedRegion *TR =
+ dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+ LoadTy = TR->getValueType(Ctx);
}
Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
state, location, OSAtomicLoadTag, LoadTy);
@@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
E2 = TmpStore.end(); I2 != E2; ++I2) {
ExplodedNode *predNew = *I2;
const GRState *stateNew = predNew->getState();
- SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(true, T);
C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
}
}
// Were they not equal?
if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
- SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
+ // Check for 'void' return type if we have a bogus function prototype.
+ SVal Res = UnknownVal();
+ QualType T = CE->getType();
+ if (!T->isVoidType())
+ Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
}
}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 7330b6261479..2cf3dfb6d0db 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -234,7 +234,8 @@ namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
- RangeConstraintManager() {}
+ RangeConstraintManager(GRSubEngine &subengine)
+ : SimpleConstraintManager(subengine) {}
const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
const llvm::APSInt& V);
@@ -273,8 +274,9 @@ private:
} // end anonymous namespace
-ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) {
- return new RangeConstraintManager();
+ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&,
+ GRSubEngine &subeng) {
+ return new RangeConstraintManager(subeng);
}
const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 3bc9dccda6bf..9b5b44be6427 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -28,9 +28,12 @@
using namespace clang;
-#define HEAP_UNDEFINED 0
#define USE_EXPLICIT_COMPOUND 0
+//===----------------------------------------------------------------------===//
+// Representation of value bindings.
+//===----------------------------------------------------------------------===//
+
namespace {
class BindingVal {
public:
@@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
}
} // end llvm namespace
+//===----------------------------------------------------------------------===//
+// Representation of binding keys.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class BindingKey : public std::pair<const MemRegion*, uint64_t> {
+public:
+ explicit BindingKey(const MemRegion *r, uint64_t offset)
+ : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
+
+ const MemRegion *getRegion() const { return first; }
+ uint64_t getOffset() const { return second; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddPointer(getRegion());
+ ID.AddInteger(getOffset());
+ }
+
+ static BindingKey Make(const MemRegion *R);
+};
+} // end anonymous namespace
+
+namespace llvm {
+ static inline
+ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+ os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
+ return os;
+ }
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
// Actual Store type.
-typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -283,6 +319,16 @@ private:
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
+ RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
+ RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
+
+ const BindingVal *Lookup(RegionBindings B, BindingKey K);
+ const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
+
+ RegionBindings Remove(RegionBindings B, BindingKey K);
+ RegionBindings Remove(RegionBindings B, const MemRegion *R);
+ Store Remove(Store store, BindingKey K);
+
public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
@@ -308,6 +354,7 @@ public:
Store KillStruct(Store store, const TypedRegion* R);
Store Remove(Store store, Loc LV);
+
//===------------------------------------------------------------------===//
// Loading values from regions.
@@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
llvm::SmallVector<const SubRegion*, 10> WL;
for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
- if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey()))
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
M->process(WL, R);
// We also need to record in the subregion map "intermediate" regions that
@@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
RemoveSubRegionBindings(B, *I, M);
-
- B = RBFactory.Remove(B, R);
+
+ B = Remove(B, R);
}
const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
@@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
- Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ Count);
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V =
ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ B = Add(B, R, BindingVal(V, BindingVal::Default));
continue;
}
@@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
// For fields and elements whose super region has also been invalidated,
// only remove the old binding. The super region will get set with a
// default value from which we can lazily derive a new symbolic value.
- B = RBFactory.Remove(B, R);
+ B = Remove(B, R);
continue;
}
// Invalidate the binding.
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
+ B = Add(B, R, BindingVal(V, BindingVal::Direct));
}
// Create a new state with the updated bindings.
@@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
const MemRegion *R) {
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
+ assert(0 && "Cannot get size of 'this' region");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Technically this can happen if people do funny things with casts.
return UnknownVal();
+ case MemRegion::CXXThisRegionKind:
+ assert(0 &&
+ "Cannot perform pointer arithmetic on implicit argument 'this'");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getDirectValue());
return Optional<SVal>();
@@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
if (TR->getValueType(getContext())->isUnionType())
return UnknownVal();
- if (BindingVal const *V = B.lookup(R))
+ if (const BindingVal *V = Lookup(B, R))
return Optional<SVal>::create(V->getDefaultValue());
return Optional<SVal>();
@@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (const BindingVal *BV = B.lookup(R))
+ if (const BindingVal *BV = Lookup(B, R))
return Optional<SVal>::create(BV->getValue());
return Optional<SVal>();
@@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveField(state, FR), FR, T));
-
- if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
+ CastRetrievedVal(RetrieveField(state, FR), FR,
+ T, false));
+
+ if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the element type. Eventually we want to compose these values
+ // more intelligently. For example, an 'element' can encompass multiple
+ // bound regions (e.g., several bound bytes), or could be a subset of
+ // a larger value.
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveElement(state, ER), ER, T));
-
- if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ CastRetrievedVal(RetrieveElement(state, ER),
+ ER, T, false));
+ }
+
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the ivar type. What we should model is stores to ivars
+ // that blow past the extent of the ivar. If the address of the ivar is
+ // reinterpretted, it is possible we stored a different value that could
+ // fit within the ivar. Either we need to cast these when storing them
+ // or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
+ CastRetrievedVal(RetrieveObjCIvar(state, IVR),
+ IVR, T, false));
+ }
- if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ // FIXME: Here we actually perform an implicit conversion from the loaded
+ // value to the variable type. What we should model is stores to variables
+ // that blow past the extent of the variable. If the address of the
+ // variable is reinterpretted, it is possible we stored a different value
+ // that could fit within the variable. Either we need to cast these when
+ // storing them or reinterpret them lazily (as we do here).
return SValuator::CastResult(state,
- CastRetrievedVal(RetrieveVar(state, VR), VR, T));
+ CastRetrievedVal(RetrieveVar(state, VR), VR, T,
+ false));
+ }
RegionBindings B = GetRegionBindings(state->getStore());
- RegionBindings::data_type* V = B.lookup(R);
+ const BindingVal *V = Lookup(B, R);
// Check if the region has a binding.
if (V)
@@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
// function/method. These are either symbolic values or 'undefined'.
-
-#if HEAP_UNDEFINED
- if (R->hasHeapOrStackStorage()) {
-#else
- if (R->hasStackStorage()) {
-#endif
+ if (R->hasStackNonParametersStorage()) {
// All stack variables are considered to have undefined values
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
@@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(state->getStore());
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
// Other cases: give up.
return UnknownVal();
}
-
+
return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
}
@@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
cast<FieldRegion>(lazyBindingRegion));
}
- if (R->hasStackStorage() && !R->hasParametersStorage()) {
-
+ if (R->hasStackNonParametersStorage()) {
if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
@@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
//===----------------------------------------------------------------------===//
Store RegionStoreManager::Remove(Store store, Loc L) {
- const MemRegion* R = 0;
-
if (isa<loc::MemRegionVal>(L))
- R = cast<loc::MemRegionVal>(L).getRegion();
-
- if (R) {
- RegionBindings B = GetRegionBindings(store);
- return RBFactory.Remove(B, R).getRoot();
- }
+ if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
+ return Remove(store, BindingKey::Make(R));
return store;
}
@@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
// Perform the binding.
RegionBindings B = GetRegionBindings(state->getStore());
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
}
const GRState *RegionStoreManager::BindDecl(const GRState *ST,
@@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
else {
return state;
}
-
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
- return state->makeWithStore(B.getRoot());
+
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Default)).getRoot());
}
const GRState *RegionStoreManager::BindArray(const GRState *state,
@@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
if (FI != FE) {
Store store = state->getStore();
RegionBindings B = GetRegionBindings(store);
- B = RBFactory.Add(B, R,
- BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
+ B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
state = state->makeWithStore(B.getRoot());
}
@@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
+ B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
return B.getRoot();
}
@@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
// results in a zero-copy algorithm.
- return state->makeWithStore(
- RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
+ return state->makeWithStore(Add(B, R,
+ BindingVal(V, BindingVal::Direct)).getRoot());
+}
+
+//===----------------------------------------------------------------------===//
+// "Raw" retrievals and bindings.
+//===----------------------------------------------------------------------===//
+
+BindingKey BindingKey::Make(const MemRegion *R) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const RegionRawOffset &O = ER->getAsRawOffset();
+
+ if (O.getRegion())
+ return BindingKey(O.getRegion(), O.getByteOffset());
+
+ // FIXME: There are some ElementRegions for which we cannot compute
+ // raw offsets yet, including regions with symbolic offsets.
+ }
+
+ return BindingKey(R, 0);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
+ BindingVal V) {
+ return RBFactory.Add(B, K, V);
+}
+
+RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
+ BindingVal V) {
+ return Add(B, BindingKey::Make(R), V);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
+ return B.lookup(K);
+}
+
+const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
+ const MemRegion *R) {
+ return Lookup(B, BindingKey::Make(R));
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
+ return RBFactory.Remove(B, K);
+}
+
+RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
+ return Remove(B, BindingKey::Make(R));
+}
+
+Store RegionStoreManager::Remove(Store store, BindingKey K) {
+ RegionBindings B = GetRegionBindings(store);
+ return Remove(B, K).getRoot();
}
//===----------------------------------------------------------------------===//
@@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// Scan the direct bindings for "intermediate" roots.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion *R = I.getKey();
+ const MemRegion *R = I.getKey().getRegion();
IntermediateRoots.push_back(R);
}
@@ -1831,13 +1944,13 @@ tryAgain:
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion* R = I.getKey();
+ const MemRegion* R = I.getKey().getRegion();
// If this region live? Is so, none of its symbols are dead.
if (Visited.count(std::make_pair(&state, R)))
continue;
// Remove this dead region from the store.
- store = Remove(store, ValMgr.makeLoc(R));
+ store = Remove(store, I.getKey());
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
index 3a6d8a41c069..4d7e8ade98f7 100644
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
SourceRange range;
+ // Get the base region, stripping away fields and elements.
+ R = R->getBaseRegion();
+
// Check if the region is a compound literal.
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
const CompoundLiteralExpr* CL = CR->getLiteralExpr();
@@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
<< C.getSourceManager().getInstantiationLineNumber(L)
<< " returned to caller";
}
- else {
+ else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
os << "Address of stack memory associated with local variable '"
- << R->getString() << "' returned.";
+ << VR->getString() << "' returned";
+ range = VR->getDecl()->getSourceRange();
+ }
+ else {
+ assert(false && "Invalid region in ReturnStackAddressChecker.");
+ return;
}
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(RS->getSourceRange());
+ report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index 9163b2725273..fbdb73b0ef2e 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
return X->getRegion();
+ if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+ return X->getLoc().getAsRegion();
+ }
+
return 0;
}
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index 49bc0c4c5988..8392fcf65a2c 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
- if (C.hasSameUnqualifiedType(castTy, originalTy))
- return CastResult(state, val);
+ if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
+ if (C.hasSameUnqualifiedType(castTy, originalTy))
+ return CastResult(state, val);
+
+ if (castTy->isIntegerType() && originalTy->isIntegerType())
+ return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp
index 23c3b4175835..eca20d574db3 100644
--- a/lib/Analysis/SimpleConstraintManager.cpp
+++ b/lib/Analysis/SimpleConstraintManager.cpp
@@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
return Assume(state, cast<Loc>(Cond), Assumption);
}
-const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // EvalAssume is used to call into the GRTransferFunction object to perform
- // any checker-specific update of the state based on this assumption being
- // true or false.
-
- if (!state)
- return 0;
-
- std::vector<std::pair<void *, Checker*> >::iterator
- I = state->checker_begin(), E = state->checker_end();
-
- for (; I != E; ++I) {
- state = I->second->EvalAssume(state, Cond, Assumption);
- }
- return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
+const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
@@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
}
const GRState *SimpleConstraintManager::Assume(const GRState *state,
- NonLoc Cond,
- bool Assumption) {
-
- state = AssumeAux(state, Cond, Assumption);
-
- // EvalAssume is used to call into the GRTransferFunction object to perform
- // any checker-specific update of the state based on this assumption being
- // true or false.
-
- if (!state)
- return 0;
-
- std::vector<std::pair<void *, Checker*> >::iterator
- I = state->checker_begin(), E = state->checker_end();
-
- for (; I != E; ++I) {
- state = I->second->EvalAssume(state, Cond, Assumption);
- }
-
- return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
+ NonLoc cond,
+ bool assumption) {
+ state = AssumeAux(state, cond, assumption);
+ return SU.ProcessAssume(state, cond, assumption);
}
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h
index 0c58440ac0b6..818239831948 100644
--- a/lib/Analysis/SimpleConstraintManager.h
+++ b/lib/Analysis/SimpleConstraintManager.h
@@ -20,8 +20,9 @@
namespace clang {
class SimpleConstraintManager : public ConstraintManager {
+ GRSubEngine &SU;
public:
- SimpleConstraintManager() {}
+ SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 2afcd3e847cd..8f2f5a1b134c 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
if (isLocType)
return LI->getLoc();
+ // FIXME: Correctly support promotions/truncations.
ASTContext &Ctx = ValMgr.getContext();
-
- // FIXME: Support promotions/truncations.
- if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy))
+ unsigned castSize = Ctx.getTypeSize(castTy);
+ if (castSize == LI->getNumBits())
return val;
- return UnknownVal();
+ return ValMgr.makeLocAsInteger(LI->getLoc(), castSize);
}
if (const SymExpr *se = val.getAsSymbolicExpression()) {
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 8d911b844fc0..1724a9250c25 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -13,6 +13,7 @@
#include "clang/Analysis/PathSensitive/Store.h"
#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/AST/CharUnits.h"
using namespace clang;
@@ -77,6 +78,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
+ case MemRegion::CXXThisRegionKind:
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!baseR)
return NULL;
- int64_t off = rawOff.getByteOffset();
+ CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset());
- if (off == 0) {
+ if (off.isZero()) {
// Edge case: we are at 0 bytes off the beginning of baseR. We
// check to see if type we are casting to is the same as the base
// region. If so, just return the base region.
@@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// We can only compute sizeof(PointeeTy) if it is a complete type.
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
- int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8);
+ CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
// Is the offset a multiple of the size? If so, we can layer the
// ElementRegion (with elementType == PointeeTy) directly on top of
@@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (!newSuperR) {
// Create an intermediate ElementRegion to represent the raw byte.
// This will be the super region of the final ElementRegion.
- newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off);
+ newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
}
return MakeElementRegion(newSuperR, PointeeTy, newIndex);
@@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
- QualType castTy) {
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+ QualType castTy, bool performTestOnly) {
-#ifndef NDEBUG
if (castTy.isNull())
return V;
ASTContext &Ctx = ValMgr.getContext();
- QualType T = R->getValueType(Ctx);
-
- // Automatically translate references to pointers.
- if (const ReferenceType *RT = T->getAs<ReferenceType>())
- T = Ctx.getPointerType(RT->getPointeeType());
-
- assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
-#endif
+ if (performTestOnly) {
+ // Automatically translate references to pointers.
+ QualType T = R->getValueType(Ctx);
+ if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ T = Ctx.getPointerType(RT->getPointeeType());
+
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
+ return V;
+ }
+
+ if (const Loc *L = dyn_cast<Loc>(&V))
+ return ValMgr.getSValuator().EvalCastL(*L, castTy);
+ else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
+ return ValMgr.getSValuator().EvalCastNL(*NL, castTy);
+
return V;
}
@@ -240,8 +248,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
const LocationContext *LC) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
}
-
-Loc StoreManager::getThisObject(QualType T) {
- const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T);
- return loc::MemRegionVal(R);
-}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 4351f66be32f..abbf6f9b6e41 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -541,19 +541,46 @@ static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
}
+/// ScanForward - Scans forward, looking for the given character, skipping
+/// nested clauses and escaped characters.
+static const char *ScanFormat(const char *I, const char *E, char Target) {
+ unsigned Depth = 0;
+
+ for ( ; I != E; ++I) {
+ if (Depth == 0 && *I == Target) return I;
+ if (Depth != 0 && *I == '}') Depth--;
+
+ if (*I == '%') {
+ I++;
+ if (I == E) break;
+
+ // Escaped characters get implicitly skipped here.
+
+ // Format specifier.
+ if (!isdigit(*I) && !ispunct(*I)) {
+ for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ;
+ if (I == E) break;
+ if (*I == '{')
+ Depth++;
+ }
+ }
+ }
+ return E;
+}
+
/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
/// like this: %select{foo|bar|baz}2. This means that the integer argument
/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
/// This is very useful for certain classes of variant diagnostics.
-static void HandleSelectModifier(unsigned ValNo,
+static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
llvm::SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument+ArgumentLen;
// Skip over 'ValNo' |'s.
while (ValNo) {
- const char *NextVal = std::find(Argument, ArgumentEnd, '|');
+ const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
" larger than the number of options in the diagnostic string!");
Argument = NextVal+1; // Skip this string.
@@ -561,9 +588,10 @@ static void HandleSelectModifier(unsigned ValNo,
}
// Get the end of the value. This is either the } or the |.
- const char *EndPtr = std::find(Argument, ArgumentEnd, '|');
- // Add the value to the output string.
- OutStr.append(Argument, EndPtr);
+ const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
+
+ // Recursively format the result of the select clause into the output string.
+ DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
}
/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
@@ -575,6 +603,37 @@ static void HandleIntegerSModifier(unsigned ValNo,
OutStr.push_back('s');
}
+/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
+/// prints the ordinal form of the given integer, with 1 corresponding
+/// to the first ordinal. Currently this is hard-coded to use the
+/// English form.
+static void HandleOrdinalModifier(unsigned ValNo,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ assert(ValNo != 0 && "ValNo must be strictly positive!");
+
+ llvm::raw_svector_ostream Out(OutStr);
+
+ // We could use text forms for the first N ordinals, but the numeric
+ // forms are actually nicer in diagnostics because they stand out.
+ Out << ValNo;
+
+ // It is critically important that we do this perfectly for
+ // user-written sequences with over 100 elements.
+ switch (ValNo % 100) {
+ case 11:
+ case 12:
+ case 13:
+ Out << "th"; return;
+ default:
+ switch (ValNo % 10) {
+ case 1: Out << "st"; return;
+ case 2: Out << "nd"; return;
+ case 3: Out << "rd"; return;
+ default: Out << "th"; return;
+ }
+ }
+}
+
/// PluralNumber - Parse an unsigned integer and advance Start.
static unsigned PluralNumber(const char *&Start, const char *End) {
@@ -685,11 +744,11 @@ static void HandlePluralModifier(unsigned ValNo,
}
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
Argument = ExprEnd + 1;
- ExprEnd = std::find(Argument, ArgumentEnd, '|');
+ ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
OutStr.append(Argument, ExprEnd);
return;
}
- Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1;
+ Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
}
}
@@ -702,6 +761,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
const char *DiagStr = getDiags()->getDescription(getID());
const char *DiagEnd = DiagStr+strlen(DiagStr);
+ FormatDiagnostic(DiagStr, DiagEnd, OutStr);
+}
+
+void DiagnosticInfo::
+FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
+ llvm::SmallVectorImpl<char> &OutStr) const {
+
/// FormattedArgs - Keep track of all of the arguments formatted by
/// ConvertArgToString and pass them into subsequent calls to
/// ConvertArgToString, allowing the implementation to avoid redundancies in
@@ -715,8 +781,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
continue;
- } else if (DiagStr[1] == '%') {
- OutStr.push_back('%'); // %% -> %.
+ } else if (ispunct(DiagStr[1])) {
+ OutStr.push_back(DiagStr[1]); // %% -> %.
DiagStr += 2;
continue;
}
@@ -745,8 +811,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
++DiagStr; // Skip {.
Argument = DiagStr;
- for (; DiagStr[0] != '}'; ++DiagStr)
- assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!");
+ DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
+ assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
ArgumentLen = DiagStr-Argument;
++DiagStr; // Skip }.
}
@@ -781,11 +847,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
- HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
+ HandleOrdinalModifier((unsigned)Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
@@ -796,11 +864,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
unsigned Val = getArgUInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
- HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
+ HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
+ HandleOrdinalModifier(Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index b6b5c6c1ef9b..bba2c3ffc41f 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -18,51 +18,38 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/Utils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
+#include <algorithm>
using namespace clang;
//===----------------------------------------------------------------------===//
// Common code shared among targets.
//===----------------------------------------------------------------------===//
-static void Define(std::vector<char> &Buf, const llvm::StringRef &Macro,
- const llvm::StringRef &Val = "1") {
- const char *Def = "#define ";
- Buf.insert(Buf.end(), Def, Def+strlen(Def));
- Buf.insert(Buf.end(), Macro.begin(), Macro.end());
- Buf.push_back(' ');
- Buf.insert(Buf.end(), Val.begin(), Val.end());
- Buf.push_back('\n');
-}
-
/// DefineStd - Define a macro name and standard variants. For example if
/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
/// when in GNU mode.
-static void DefineStd(std::vector<char> &Buf, const char *MacroName,
+static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName,
const LangOptions &Opts) {
assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
// If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier
// in the user's namespace.
if (Opts.GNUMode)
- Define(Buf, MacroName);
+ Builder.defineMacro(MacroName);
// Define __unix.
- llvm::SmallString<20> TmpStr;
- TmpStr = "__";
- TmpStr += MacroName;
- Define(Buf, TmpStr.str());
+ Builder.defineMacro("__" + MacroName);
// Define __unix__.
- TmpStr += "__";
- Define(Buf, TmpStr.str());
+ Builder.defineMacro("__" + MacroName + "__");
}
//===----------------------------------------------------------------------===//
@@ -74,44 +61,44 @@ template<typename TgtInfo>
class OSTargetInfo : public TgtInfo {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const=0;
+ MacroBuilder &Builder) const=0;
public:
OSTargetInfo(const std::string& triple) : TgtInfo(triple) {}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- TgtInfo::getTargetDefines(Opts, Defines);
- getOSDefines(Opts, TgtInfo::getTriple(), Defines);
+ MacroBuilder &Builder) const {
+ TgtInfo::getTargetDefines(Opts, Builder);
+ getOSDefines(Opts, TgtInfo::getTriple(), Builder);
}
};
} // end anonymous namespace
-static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
- Define(Defs, "__APPLE_CC__", "5621");
- Define(Defs, "__APPLE__");
- Define(Defs, "__MACH__");
- Define(Defs, "OBJC_NEW_PROPERTIES");
+static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
+ Builder.defineMacro("__APPLE_CC__", "5621");
+ Builder.defineMacro("__APPLE__");
+ Builder.defineMacro("__MACH__");
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
// __weak is always defined, for use in blocks and with objc pointers.
- Define(Defs, "__weak", "__attribute__((objc_gc(weak)))");
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Darwin defines __strong even in C mode (just to nothing).
if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
- Define(Defs, "__strong", "");
+ Builder.defineMacro("__strong", "");
else
- Define(Defs, "__strong", "__attribute__((objc_gc(strong)))");
+ Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
if (Opts.Static)
- Define(Defs, "__STATIC__");
+ Builder.defineMacro("__STATIC__");
else
- Define(Defs, "__DYNAMIC__");
+ Builder.defineMacro("__DYNAMIC__");
if (Opts.POSIXThreads)
- Define(Defs, "_REENTRANT", "1");
+ Builder.defineMacro("_REENTRANT");
}
-static void getDarwinOSXDefines(std::vector<char> &Defs,
+static void getDarwinOSXDefines(MacroBuilder &Builder,
const llvm::Triple &Triple) {
if (Triple.getOS() != llvm::Triple::Darwin)
return;
@@ -129,10 +116,11 @@ static void getDarwinOSXDefines(std::vector<char> &Defs,
// Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
// Cap 10.4.11 -> darwin8.11 -> "1049"
MacOSXStr[3] = std::min(Min, 9U)+'0';
- Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr);
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
+ MacOSXStr);
}
-static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
+static void getDarwinIPhoneOSDefines(MacroBuilder &Builder,
const llvm::Triple &Triple) {
if (Triple.getOS() != llvm::Triple::Darwin)
return;
@@ -151,8 +139,8 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
// Handle minor version: 2.2 -> darwin9.2.2 -> 20200
iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
- Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- iPhoneOSStr);
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ iPhoneOSStr);
}
namespace {
@@ -160,9 +148,9 @@ template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const {
- getDarwinDefines(Defines, Opts);
- getDarwinOSXDefines(Defines, Triple);
+ MacroBuilder &Builder) const {
+ getDarwinDefines(Builder, Opts);
+ getDarwinOSXDefines(Builder, Triple);
}
public:
@@ -190,14 +178,14 @@ template<typename Target>
class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// DragonFly defines; list based off of gcc output
- Define(Defs, "__DragonFly__");
- Define(Defs, "__DragonFly_cc_version", "100001");
- Define(Defs, "__ELF__");
- Define(Defs, "__KPRINTF_ATTRIBUTE__");
- Define(Defs, "__tune_i386__");
- DefineStd(Defs, "unix", Opts);
+ Builder.defineMacro("__DragonFly__");
+ Builder.defineMacro("__DragonFly_cc_version", "100001");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ Builder.defineMacro("__tune_i386__");
+ DefineStd(Builder, "unix", Opts);
}
public:
DragonFlyBSDTargetInfo(const std::string &triple)
@@ -209,7 +197,7 @@ template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// FreeBSD defines; list based off of gcc output
// FIXME: Move version number handling to llvm::Triple.
@@ -221,11 +209,11 @@ protected:
char version[] = "X00001";
version[0] = FreeBSD[0];
- Define(Defs, "__FreeBSD__", release);
- Define(Defs, "__FreeBSD_cc_version", version);
- Define(Defs, "__KPRINTF_ATTRIBUTE__");
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__FreeBSD__", release);
+ Builder.defineMacro("__FreeBSD_cc_version", version);
+ Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
}
public:
FreeBSDTargetInfo(const std::string &triple)
@@ -239,14 +227,14 @@ template<typename Target>
class LinuxTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Linux defines; list based off of gcc output
- DefineStd(Defs, "unix", Opts);
- DefineStd(Defs, "linux", Opts);
- Define(Defs, "__gnu_linux__");
- Define(Defs, "__ELF__", "1");
+ DefineStd(Builder, "unix", Opts);
+ DefineStd(Builder, "linux", Opts);
+ Builder.defineMacro("__gnu_linux__");
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_REENTRANT", "1");
+ Builder.defineMacro("_REENTRANT");
}
public:
LinuxTargetInfo(const std::string& triple)
@@ -260,13 +248,13 @@ template<typename Target>
class NetBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// NetBSD defines; list based off of gcc output
- Define(Defs, "__NetBSD__", "1");
- Define(Defs, "__unix__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__NetBSD__");
+ Builder.defineMacro("__unix__");
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_POSIX_THREADS", "1");
+ Builder.defineMacro("_POSIX_THREADS");
}
public:
NetBSDTargetInfo(const std::string &triple)
@@ -280,14 +268,14 @@ template<typename Target>
class OpenBSDTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// OpenBSD defines; list based off of gcc output
- Define(Defs, "__OpenBSD__", "1");
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__OpenBSD__");
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
- Define(Defs, "_POSIX_THREADS", "1");
+ Builder.defineMacro("_POSIX_THREADS");
}
public:
OpenBSDTargetInfo(const std::string &triple)
@@ -299,12 +287,12 @@ template<typename Target>
class PSPTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PSP defines; list based on the output of the pspdev gcc toolchain.
- Define(Defs, "PSP", "1");
- Define(Defs, "_PSP", "1");
- Define(Defs, "__psp__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("PSP");
+ Builder.defineMacro("_PSP");
+ Builder.defineMacro("__psp__");
+ Builder.defineMacro("__ELF__");
}
public:
PSPTargetInfo(const std::string& triple)
@@ -318,12 +306,12 @@ template<typename Target>
class PS3PPUTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PS3 PPU defines.
- Define(Defs, "__PPU__", "1");
- Define(Defs, "__CELLOS_LV2__", "1");
- Define(Defs, "__ELF__", "1");
- Define(Defs, "__LP32__", "1");
+ Builder.defineMacro("__PPU__");
+ Builder.defineMacro("__CELLOS_LV2__");
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__LP32__");
}
public:
PS3PPUTargetInfo(const std::string& triple)
@@ -340,10 +328,10 @@ template<typename Target>
class PS3SPUTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// PS3 PPU defines.
- Define(Defs, "__SPU__", "1");
- Define(Defs, "__ELF__", "1");
+ Builder.defineMacro("__SPU__");
+ Builder.defineMacro("__ELF__");
}
public:
PS3SPUTargetInfo(const std::string& triple)
@@ -357,12 +345,12 @@ template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
- DefineStd(Defs, "sun", Opts);
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__");
- Define(Defs, "__svr4__");
- Define(Defs, "__SVR4");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sun", Opts);
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__svr4__");
+ Builder.defineMacro("__SVR4");
}
public:
AuroraUXTargetInfo(const std::string& triple)
@@ -378,12 +366,12 @@ template<typename Target>
class SolarisTargetInfo : public OSTargetInfo<Target> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defs) const {
- DefineStd(Defs, "sun", Opts);
- DefineStd(Defs, "unix", Opts);
- Define(Defs, "__ELF__");
- Define(Defs, "__svr4__");
- Define(Defs, "__SVR4");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sun", Opts);
+ DefineStd(Builder, "unix", Opts);
+ Builder.defineMacro("__ELF__");
+ Builder.defineMacro("__svr4__");
+ Builder.defineMacro("__SVR4");
}
public:
SolarisTargetInfo(const std::string& triple)
@@ -416,7 +404,7 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
virtual const char *getVAListDeclaration() const {
return "typedef char* __builtin_va_list;";
@@ -460,34 +448,34 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
/// #defines that are not tied to a specific subtarget.
void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
- Define(Defs, "__ppc__");
- Define(Defs, "_ARCH_PPC");
- Define(Defs, "__POWERPC__");
+ Builder.defineMacro("__ppc__");
+ Builder.defineMacro("_ARCH_PPC");
+ Builder.defineMacro("__POWERPC__");
if (PointerWidth == 64) {
- Define(Defs, "_ARCH_PPC64");
- Define(Defs, "_LP64");
- Define(Defs, "__LP64__");
- Define(Defs, "__ppc64__");
+ Builder.defineMacro("_ARCH_PPC64");
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ Builder.defineMacro("__ppc64__");
} else {
- Define(Defs, "__ppc__");
+ Builder.defineMacro("__ppc__");
}
// Target properties.
- Define(Defs, "_BIG_ENDIAN");
- Define(Defs, "__BIG_ENDIAN__");
+ Builder.defineMacro("_BIG_ENDIAN");
+ Builder.defineMacro("__BIG_ENDIAN__");
// Subtarget options.
- Define(Defs, "__NATURAL_ALIGNMENT__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__NATURAL_ALIGNMENT__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
// FIXME: Should be controlled by command line option.
- Define(Defs, "__LONG_DOUBLE_128__");
+ Builder.defineMacro("__LONG_DOUBLE_128__");
if (Opts.AltiVec) {
- Define(Defs, "__VEC__", "10206");
- Define(Defs, "__ALTIVEC__", "1");
+ Builder.defineMacro("__VEC__", "10206");
+ Builder.defineMacro("__ALTIVEC__");
}
}
@@ -682,7 +670,7 @@ public:
return "~{dirflag},~{fpsr},~{flags}";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
const std::string &Name,
bool Enabled) const;
@@ -828,51 +816,51 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
/// that are not tied to a specific subtarget.
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
if (PointerWidth == 64) {
- Define(Defs, "_LP64");
- Define(Defs, "__LP64__");
- Define(Defs, "__amd64__");
- Define(Defs, "__amd64");
- Define(Defs, "__x86_64");
- Define(Defs, "__x86_64__");
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+ Builder.defineMacro("__amd64__");
+ Builder.defineMacro("__amd64");
+ Builder.defineMacro("__x86_64");
+ Builder.defineMacro("__x86_64__");
} else {
- DefineStd(Defs, "i386", Opts);
+ DefineStd(Builder, "i386", Opts);
}
// Target properties.
- Define(Defs, "__LITTLE_ENDIAN__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
// Subtarget options.
- Define(Defs, "__nocona");
- Define(Defs, "__nocona__");
- Define(Defs, "__tune_nocona__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__nocona");
+ Builder.defineMacro("__nocona__");
+ Builder.defineMacro("__tune_nocona__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
// Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
// functions in glibc header files that use FP Stack inline asm which the
// backend can't deal with (PR879).
- Define(Defs, "__NO_MATH_INLINES");
+ Builder.defineMacro("__NO_MATH_INLINES");
// Each case falls through to the previous one here.
switch (SSELevel) {
case SSE42:
- Define(Defs, "__SSE4_2__");
+ Builder.defineMacro("__SSE4_2__");
case SSE41:
- Define(Defs, "__SSE4_1__");
+ Builder.defineMacro("__SSE4_1__");
case SSSE3:
- Define(Defs, "__SSSE3__");
+ Builder.defineMacro("__SSSE3__");
case SSE3:
- Define(Defs, "__SSE3__");
+ Builder.defineMacro("__SSE3__");
case SSE2:
- Define(Defs, "__SSE2__");
- Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied.
+ Builder.defineMacro("__SSE2__");
+ Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
case SSE1:
- Define(Defs, "__SSE__");
- Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied.
+ Builder.defineMacro("__SSE__");
+ Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
case MMX:
- Define(Defs, "__MMX__");
+ Builder.defineMacro("__MMX__");
case NoMMXSSE:
break;
}
@@ -999,13 +987,13 @@ public:
"v128:128:128-a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_32TargetInfo::getTargetDefines(Opts, Defines);
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
// This list is based off of the the list of things MingW defines
- Define(Defines, "_WIN32");
- DefineStd(Defines, "WIN32", Opts);
- DefineStd(Defines, "WINNT", Opts);
- Define(Defines, "_X86_");
+ Builder.defineMacro("_WIN32");
+ DefineStd(Builder, "WIN32", Opts);
+ DefineStd(Builder, "WINNT", Opts);
+ Builder.defineMacro("_X86_");
}
};
} // end anonymous namespace
@@ -1019,12 +1007,12 @@ public:
: WindowsX86_32TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
+ MacroBuilder &Builder) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
// The value of the following reflects processor type.
// 300=386, 400=486, 500=Pentium, 600=Blend (default)
// We lost the original triple, so we use the default.
- Define(Defines, "_M_IX86", "600");
+ Builder.defineMacro("_M_IX86", "600");
}
};
} // end anonymous namespace
@@ -1037,11 +1025,11 @@ public:
: WindowsX86_32TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__MSVCRT__");
- Define(Defines, "__MINGW32__");
- Define(Defines, "__declspec", "__declspec");
+ MacroBuilder &Builder) const {
+ WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
+ Builder.defineMacro("__declspec", "__declspec");
}
};
} // end anonymous namespace
@@ -1060,11 +1048,11 @@ public:
"a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_32TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__CYGWIN__");
- Define(Defines, "__CYGWIN32__");
- DefineStd(Defines, "unix", Opts);
+ MacroBuilder &Builder) const {
+ X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__CYGWIN__");
+ Builder.defineMacro("__CYGWIN32__");
+ DefineStd(Builder, "unix", Opts);
}
};
} // end anonymous namespace
@@ -1116,10 +1104,10 @@ public:
DoubleAlign = LongLongAlign = 64;
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- X86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "_WIN64");
- DefineStd(Defines, "WIN64", Opts);
+ MacroBuilder &Builder) const {
+ X86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_WIN64");
+ DefineStd(Builder, "WIN64", Opts);
}
};
} // end anonymous namespace
@@ -1132,9 +1120,9 @@ public:
: WindowsX86_64TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "_M_X64");
+ MacroBuilder &Builder) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_M_X64");
}
virtual const char *getVAListDeclaration() const {
return "typedef char* va_list;";
@@ -1150,11 +1138,11 @@ public:
: WindowsX86_64TargetInfo(triple) {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
- Define(Defines, "__MSVCRT__");
- Define(Defines, "__MINGW64__");
- Define(Defines, "__declspec");
+ MacroBuilder &Builder) const {
+ WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW64__");
+ Builder.defineMacro("__declspec");
}
};
} // end anonymous namespace
@@ -1342,61 +1330,58 @@ public:
return true;
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defs) const {
+ MacroBuilder &Builder) const {
// Target identification.
- Define(Defs, "__arm");
- Define(Defs, "__arm__");
+ Builder.defineMacro("__arm");
+ Builder.defineMacro("__arm__");
// Target properties.
- Define(Defs, "__ARMEL__");
- Define(Defs, "__LITTLE_ENDIAN__");
- Define(Defs, "__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__ARMEL__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
llvm::StringRef CPUArch = getCPUDefineSuffix(CPU);
- std::string ArchName = "__ARM_ARCH_";
- ArchName += CPUArch;
- ArchName += "__";
- Define(Defs, ArchName);
+ Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
// Subtarget options.
// FIXME: It's more complicated than this and we don't really support
// interworking.
if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
- Define(Defs, "__THUMB_INTERWORK__");
+ Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux")
- Define(Defs, "__ARM_EABI__");
+ Builder.defineMacro("__ARM_EABI__");
if (SoftFloat)
- Define(Defs, "__SOFTFP__");
+ Builder.defineMacro("__SOFTFP__");
if (CPU == "xscale")
- Define(Defs, "__XSCALE__");
+ Builder.defineMacro("__XSCALE__");
bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
if (IsThumb) {
- Define(Defs, "__THUMBEL__");
- Define(Defs, "__thumb__");
+ Builder.defineMacro("__THUMBEL__");
+ Builder.defineMacro("__thumb__");
if (IsThumb2)
- Define(Defs, "__thumb2__");
+ Builder.defineMacro("__thumb2__");
}
// Note, this is always on in gcc, even though it doesn't make sense.
- Define(Defs, "__APCS_32__");
+ Builder.defineMacro("__APCS_32__");
if (FPUModeIsVFP((FPUMode) FPU))
- Define(Defs, "__VFP_FP__");
+ Builder.defineMacro("__VFP_FP__");
// This only gets set when Neon instructions are actually available, unlike
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
if (FPU == NeonFPU && !SoftFloat && IsThumb2)
- Define(Defs, "__ARM_NEON__");
+ Builder.defineMacro("__ARM_NEON__");
if (getTriple().getOS() == llvm::Triple::Darwin)
- Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
+ Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1475,9 +1460,9 @@ class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMTargetInfo> {
protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- std::vector<char> &Defines) const {
- getDarwinDefines(Defines, Opts);
- getDarwinIPhoneOSDefines(Defines, Triple);
+ MacroBuilder &Builder) const {
+ getDarwinDefines(Builder, Opts);
+ getDarwinIPhoneOSDefines(Builder, Triple);
}
public:
@@ -1497,10 +1482,10 @@ public:
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "sparc", Opts);
- Define(Defines, "__sparcv8");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "sparc", Opts);
+ Builder.defineMacro("__sparcv8");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1630,18 +1615,18 @@ namespace {
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; }
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- Define(Defines, "__pic16");
- Define(Defines, "rom", "__attribute__((address_space(1)))");
- Define(Defines, "ram", "__attribute__((address_space(0)))");
- Define(Defines, "_section(SectName)",
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__pic16");
+ Builder.defineMacro("rom", "__attribute__((address_space(1)))");
+ Builder.defineMacro("ram", "__attribute__((address_space(0)))");
+ Builder.defineMacro("_section(SectName)",
"__attribute__((section(SectName)))");
- Define(Defines, "near",
+ Builder.defineMacro("near",
"__attribute__((section(\"Address=NEAR\")))");
- Define(Defines, "_address(Addr)",
+ Builder.defineMacro("_address(Addr)",
"__attribute__((section(\"Address=\"#Addr)))");
- Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
- Define(Defines, "_interrupt",
+ Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
+ Builder.defineMacro("_interrupt",
"__attribute__((section(\"interrupt=0x4\"))) \
__attribute__((used))");
}
@@ -1672,7 +1657,8 @@ namespace {
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
TLSSupported = false;
IntWidth = 16;
- LongWidth = LongLongWidth = 32;
+ LongWidth = 32;
+ LongLongWidth = 64;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1686,9 +1672,9 @@ namespace {
DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- Define(Defines, "MSP430");
- Define(Defines, "__MSP430__");
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("MSP430");
+ Builder.defineMacro("__MSP430__");
// FIXME: defines for different 'flavours' of MCU
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -1746,9 +1732,9 @@ namespace {
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- Define(Defines, "__s390__");
- Define(Defines, "__s390x__");
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__s390__");
+ Builder.defineMacro("__s390x__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -1805,12 +1791,12 @@ namespace {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "bfin", Opts);
- DefineStd(Defines, "BFIN", Opts);
- Define(Defines, "__ADSPBLACKFIN__");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "bfin", Opts);
+ DefineStd(Builder, "BFIN", Opts);
+ Builder.defineMacro("__ADSPBLACKFIN__");
// FIXME: This one is really dependent on -mcpu
- Define(Defines, "__ADSPLPBLACKFIN__");
+ Builder.defineMacro("__ADSPLPBLACKFIN__");
// FIXME: Add cpu-dependent defines and __SILICON_REVISION__
}
@@ -1906,10 +1892,10 @@ namespace {
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "tce", Opts);
- Define(Defines, "__TCE__");
- Define(Defines, "__TCE_V1__");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "tce", Opts);
+ Builder.defineMacro("__TCE__");
+ Builder.defineMacro("__TCE_V1__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {}
@@ -1940,12 +1926,12 @@ public:
"i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "mips", Opts);
- Define(Defines, "_mips");
- DefineStd(Defines, "MIPSEB", Opts);
- Define(Defines, "_MIPSEB");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEB", Opts);
+ Builder.defineMacro("_MIPSEB");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
unsigned &NumRecords) const {
@@ -2047,16 +2033,16 @@ public:
}
virtual void getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const;
+ MacroBuilder &Builder) const;
};
void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
- std::vector<char> &Defines) const {
- DefineStd(Defines, "mips", Opts);
- Define(Defines, "_mips");
- DefineStd(Defines, "MIPSEL", Opts);
- Define(Defines, "_MIPSEL");
- Define(Defines, "__REGISTER_PREFIX__", "");
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "mips", Opts);
+ Builder.defineMacro("_mips");
+ DefineStd(Builder, "MIPSEL", Opts);
+ Builder.defineMacro("_MIPSEL");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
}
} // end anonymous namespace.
@@ -2171,6 +2157,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new DarwinX86_64TargetInfo(T);
case llvm::Triple::Linux:
return new LinuxTargetInfo<X86_64TargetInfo>(T);
+ case llvm::Triple::DragonFly:
+ return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::NetBSD:
return new NetBSDTargetInfo<X86_64TargetInfo>(T);
case llvm::Triple::OpenBSD:
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 1bece7fec6fa..1fa422f29e1c 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -24,7 +24,7 @@ using namespace clang;
using namespace CodeGen;
llvm::Constant *CodeGenFunction::
-BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
+BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty,
std::vector<HelperInfo> *NoteForHelper) {
const llvm::Type *UnsignedLongTy
@@ -40,7 +40,7 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
// FIXME: What is the right way to say this doesn't fit? We should give
// a user diagnostic in that case. Better fix would be to change the
// API to size_t.
- C = llvm::ConstantInt::get(UnsignedLongTy, Size);
+ C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
Elts.push_back(C);
if (BlockHasCopyDispose) {
@@ -176,7 +176,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
- uint64_t subBlockSize, subBlockAlign;
+ CharUnits subBlockSize;
+ uint64_t subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::Function *Fn
@@ -321,13 +322,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// compared to gcc by not grabbing the forwarding slot as this must
// be done during Block_copy for us, and we can postpone the work
// until then.
- uint64_t offset = BlockDecls[BDRE->getDecl()];
+ CharUnits offset = BlockDecls[BDRE->getDecl()];
llvm::Value *BlockLiteral = LoadBlockStruct();
Loc = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset),
+ offset.getQuantity()),
"block.literal");
Ty = llvm::PointerType::get(Ty, 0);
Loc = Builder.CreateBitCast(Loc, Ty);
@@ -513,12 +514,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
return EmitCall(FnInfo, Func, ReturnValue, Args);
}
-uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
+CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- uint64_t &offset = BlockDecls[VD];
+ CharUnits &offset = BlockDecls[VD];
// See if we have already allocated an offset for this variable.
- if (offset)
+ if (offset.isPositive())
return offset;
// Don't run the expensive check, unless we have to.
@@ -535,13 +536,13 @@ uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
const ValueDecl *VD = E->getDecl();
- uint64_t offset = AllocateBlockDecl(E);
+ CharUnits offset = AllocateBlockDecl(E);
llvm::Value *BlockLiteral = LoadBlockStruct();
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset),
+ offset.getQuantity()),
"block.literal");
if (E->isByRef()) {
const llvm::Type *PtrStructTy
@@ -594,10 +595,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Block literal size. For global blocks we just use the size of the generic
// block literal struct.
- uint64_t BlockLiteralSize =
- TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
+ CharUnits BlockLiteralSize = CharUnits::fromQuantity(
+ TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8);
DescriptorFields[1] =
- llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
+ llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity());
llvm::Constant *DescriptorStruct =
llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false);
@@ -615,7 +616,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n);
- uint64_t subBlockSize, subBlockAlign;
+ CharUnits subBlockSize;
+ uint64_t subBlockAlign;
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
bool subBlockHasCopyDispose = false;
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -677,7 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- uint64_t &Size,
+ CharUnits &Size,
uint64_t &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose) {
@@ -698,8 +700,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
LocalDeclMap[VD] = i->second;
}
- BlockOffset = CGM.getTargetData()
- .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8;
+ BlockOffset = CharUnits::fromQuantity(
+ CGM.getTargetData()
+ .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8);
BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
@@ -799,7 +802,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
// The runtime needs a minimum alignment of a void *.
uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
- BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign);
+ BlockOffset = CharUnits::fromQuantity(
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign));
Size = BlockOffset;
Align = BlockAlign;
@@ -808,30 +812,32 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
return Fn;
}
-uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
+CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
- uint64_t Size = getContext().getTypeSize(D->getType()) / 8;
+ CharUnits Size = getContext().getTypeSizeInChars(D->getType());
uint64_t Align = getContext().getDeclAlignInBytes(D);
if (BDRE->isByRef()) {
- Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8;
+ Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
}
assert ((Align > 0) && "alignment must be 1 byte or more");
- uint64_t OldOffset = BlockOffset;
+ CharUnits OldOffset = BlockOffset;
// Ensure proper alignment, even if it means we have to have a gap
- BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align);
+ BlockOffset = CharUnits::fromQuantity(
+ llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align));
BlockAlign = std::max(Align, BlockAlign);
- uint64_t Pad = BlockOffset - OldOffset;
- if (Pad) {
- llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad);
+ CharUnits Pad = BlockOffset - OldOffset;
+ if (Pad.isPositive()) {
+ llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity());
QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
- llvm::APInt(32, Pad),
+ llvm::APInt(32,
+ Pad.getQuantity()),
ArrayType::Normal, 0);
ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
0, QualType(PadTy), 0, VarDecl::None);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 38e02a70a4e2..f42244c52e0e 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -175,13 +176,13 @@ public:
/// BlockOffset - The offset in bytes for the next allocation of an
/// imported block variable.
- uint64_t BlockOffset;
+ CharUnits BlockOffset;
/// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
uint64_t BlockAlign;
/// getBlockOffset - Allocate an offset for the ValueDecl from a
/// BlockDeclRefExpr in a block literal (BlockExpr).
- uint64_t getBlockOffset(const BlockDeclRefExpr *E);
+ CharUnits getBlockOffset(const BlockDeclRefExpr *E);
/// BlockHasCopyDispose - True iff the block uses copy/dispose.
bool BlockHasCopyDispose;
@@ -191,7 +192,7 @@ public:
llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
/// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
- std::map<const Decl*, uint64_t> BlockDecls;
+ std::map<const Decl*, CharUnits> BlockDecls;
ImplicitParamDecl *BlockStructDecl;
ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index cc006d9dd6c1..4323f84d9633 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -26,269 +26,7 @@
using namespace clang;
using namespace CodeGen;
-RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
- llvm::Value *Callee,
- ReturnValueSlot ReturnValue,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- MD->getThisType(getContext())));
-
- // And the rest of the call args
- EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
-
- QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValue, Args, MD);
-}
-
-/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
-/// expr can be devirtualized.
-static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- // This is a record decl. We know the type and can devirtualize it.
- return VD->getType()->isRecordType();
- }
-
- return false;
- }
-
- // We can always devirtualize calls on temporary object expressions.
- if (isa<CXXTemporaryObjectExpr>(Base))
- return true;
-
- // And calls on bound temporaries.
- if (isa<CXXBindTemporaryExpr>(Base))
- return true;
-
- // Check if this is a call expr that returns a record type.
- if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
- return CE->getCallReturnType()->isRecordType();
-
- // We can't devirtualize the call.
- return false;
-}
-
-RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
- ReturnValueSlot ReturnValue) {
- if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
- return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
-
- const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
-
- if (MD->isStatic()) {
- // The method is static, emit it as we would a regular call.
- llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
- return EmitCall(getContext().getPointerType(MD->getType()), Callee,
- ReturnValue, CE->arg_begin(), CE->arg_end());
- }
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
-
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *This;
-
- if (ME->isArrow())
- This = EmitScalarExpr(ME->getBase());
- else {
- LValue BaseLV = EmitLValue(ME->getBase());
- 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.
- //
- // We also don't emit a virtual call if the base expression has a record type
- // because then we know what the type is.
- 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);
- } else {
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
- }
- } else if (MD->isVirtual() && !ME->hasQualifier() &&
- !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
- Callee = BuildVirtualCall(MD, This, Ty);
- } else {
- Callee = CGM.GetAddrOfFunction(MD, Ty);
- }
-
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
- CE->arg_begin(), CE->arg_end());
-}
-
-RValue
-CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
- ReturnValueSlot ReturnValue) {
- const BinaryOperator *BO =
- cast<BinaryOperator>(E->getCallee()->IgnoreParens());
- const Expr *BaseExpr = BO->getLHS();
- const Expr *MemFnExpr = BO->getRHS();
-
- const MemberPointerType *MPT =
- MemFnExpr->getType()->getAs<MemberPointerType>();
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
-
- const llvm::FunctionType *FTy =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
- FPT->isVariadic());
-
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
-
- // Get the member function pointer.
- llvm::Value *MemFnPtr =
- CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
- EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
-
- // Emit the 'this' pointer.
- llvm::Value *This;
-
- if (BO->getOpcode() == BinaryOperator::PtrMemI)
- This = EmitScalarExpr(BaseExpr);
- else
- This = EmitLValue(BaseExpr).getAddress();
-
- // Adjust it.
- llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
- Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
-
- llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
- Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
-
- This = Builder.CreateBitCast(Ptr, This->getType(), "this");
-
- llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
-
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
-
- llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
-
- // If the LSB in the function pointer is 1, the function pointer points to
- // a virtual function.
- llvm::Value *IsVirtual
- = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
- "and");
-
- IsVirtual = Builder.CreateTrunc(IsVirtual,
- llvm::Type::getInt1Ty(VMContext));
-
- llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
- llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
- llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
-
- Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
- EmitBlock(FnVirtual);
-
- const llvm::Type *VTableTy =
- FTy->getPointerTo()->getPointerTo()->getPointerTo();
-
- llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
- VTable = Builder.CreateLoad(VTable);
-
- VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
-
- // Since the function pointer is 1 plus the virtual table offset, we
- // subtract 1 by using a GEP.
- VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
-
- llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
-
- EmitBranch(FnEnd);
- EmitBlock(FnNonVirtual);
-
- // If the function is not virtual, just load the pointer.
- llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
- NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
-
- EmitBlock(FnEnd);
-
- llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
- Callee->reserveOperandSpace(2);
- Callee->addIncoming(VirtualFn, FnVirtual);
- Callee->addIncoming(NonVirtualFn, FnNonVirtual);
-
- CallArgList Args;
-
- QualType ThisType =
- getContext().getPointerType(getContext().getTagDeclType(RD));
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This), ThisType));
-
- // And the rest of the call args
- EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
- QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
- return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValue, Args);
-}
-
-RValue
-CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
- const CXXMethodDecl *MD,
- ReturnValueSlot ReturnValue) {
- assert(MD->isInstance() &&
- "Trying to emit a member call expr on a static method!");
-
- if (MD->isCopyAssignment()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
- if (ClassDecl->hasTrivialCopyAssignment()) {
- assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
- "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
- llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
- QualType Ty = E->getType();
- EmitAggregateCopy(This, Src, Ty);
- return RValue::get(This);
- }
- }
-
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
-
- llvm::Value *Callee;
- if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
- Callee = BuildVirtualCall(MD, This, Ty);
- else
- Callee = CGM.GetAddrOfFunction(MD, Ty);
-
- return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
- E->arg_begin() + 1, E->arg_end());
-}
llvm::Value *CodeGenFunction::LoadCXXThis() {
assert(isa<CXXMethodDecl>(CurFuncDecl) &&
@@ -302,320 +40,6 @@ llvm::Value *CodeGenFunction::LoadCXXThis() {
return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this");
}
-/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
-/// for-loop to call the default constructor on individual members of the
-/// array.
-/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
-/// array type and 'ArrayPtr' points to the beginning fo the array.
-/// 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,
- 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, ArgBeg, ArgEnd);
-}
-
-void
-CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- 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);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // Generate: if (loop-index < number-of-elements fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsLess, ForBody, AfterFor);
-
- EmitBlock(ForBody);
-
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
- "arrayidx");
-
- // 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);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
- const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
- assert(CA && "Do we support VLA for destruction ?");
- uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
-
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
- EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
-}
-
-/// EmitCXXAggrDestructorCall - calls the default destructor on array
-/// elements in reverse order of construction.
-void
-CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
- llvm::Value *UpperCount,
- llvm::Value *This) {
- const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
- llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
-
- // Create a temporary for the loop index and initialize it with count of
- // array elements.
- llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
-
- // Store the number of elements in the index pointer.
- Builder.CreateStore(UpperCount, IndexPtr);
-
- // Start the loop with a block that tests the condition.
- llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
- llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
- EmitBlock(CondBlock);
-
- llvm::BasicBlock *ForBody = createBasicBlock("for.body");
-
- // Generate: if (loop-index != 0 fall to the loop body,
- // otherwise, go to the block after the for-loop.
- llvm::Value* zeroConstant =
- llvm::Constant::getNullValue(SizeLTy);
- llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
- llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
- "isne");
- // If the condition is true, execute the body.
- Builder.CreateCondBr(IsNE, ForBody, AfterFor);
-
- EmitBlock(ForBody);
-
- llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
- // Inside the loop body, emit the constructor call on the array element.
- Counter = Builder.CreateLoad(IndexPtr);
- Counter = Builder.CreateSub(Counter, One);
- llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- 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);
-
- // Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
-
- // Emit the fall-through block.
- EmitBlock(AfterFor, true);
-}
-
-/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
-/// invoked, calls the default destructor on array elements in reverse order of
-/// construction.
-llvm::Constant *
-CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
- const ArrayType *Array,
- llvm::Value *This) {
- FunctionArgList Args;
- ImplicitParamDecl *Dst =
- ImplicitParamDecl::Create(getContext(), 0,
- SourceLocation(), 0,
- getContext().getPointerType(getContext().VoidTy));
- Args.push_back(std::make_pair(Dst, Dst->getType()));
-
- llvm::SmallString<16> Name;
- llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
- QualType R = getContext().VoidTy;
- const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
- const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
- llvm::Function *Fn =
- llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
- Name.str(),
- &CGM.getModule());
- IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
- SourceLocation(), II, R, 0,
- FunctionDecl::Static,
- false, true);
- StartFunction(FD, R, Fn, Args, SourceLocation());
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
- FinishFunction();
- llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
- 0);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
-void
-CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
- CXXCtorType Type,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- if (D->isCopyConstructor()) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor()) {
- assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
- "EmitCXXConstructorCall - user declared copy constructor");
- const Expr *E = (*ArgBeg);
- QualType Ty = E->getType();
- llvm::Value *Src = EmitLValue(E).getAddress();
- 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);
-
- EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd);
-}
-
-void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- llvm::Value *This) {
- llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
-
- CallArgList Args;
-
- // Push the this ptr.
- Args.push_back(std::make_pair(RValue::get(This),
- DD->getThisType(getContext())));
-
- // Add a VTT parameter if necessary.
- // FIXME: This should not be a dummy null parameter!
- if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
-
- Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T));
- }
-
- // FIXME: We should try to share this code with EmitCXXMemberCall.
-
- QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
- EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
- ReturnValueSlot(), Args, DD);
-}
-
-void
-CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
- const CXXConstructExpr *E) {
- assert(Dest && "Must have a destination!");
- const CXXConstructorDecl *CD = E->getConstructor();
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(E->getType());
- // For a copy constructor, even if it is trivial, must fall thru so
- // its argument is code-gen'ed.
- if (!CD->isCopyConstructor()) {
- QualType InitType = E->getType();
- if (Array)
- InitType = getContext().getBaseElementType(Array);
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
- if (RD->hasTrivialConstructor())
- return;
- }
- // Code gen optimization to eliminate copy constructor and return
- // its first argument instead.
- if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- const Expr *Arg = E->getArg(0);
-
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
- assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
- ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
- ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
- "Unknown implicit cast kind in constructor elision");
- Arg = ICE->getSubExpr();
- }
-
- if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
- Arg = FCE->getSubExpr();
-
- if (const CXXBindTemporaryExpr *BindExpr =
- dyn_cast<CXXBindTemporaryExpr>(Arg))
- Arg = BindExpr->getSubExpr();
-
- EmitAggExpr(Arg, Dest, false);
- return;
- }
- if (Array) {
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(Dest, BasePtr);
-
- EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
- E->arg_begin(), E->arg_end());
- }
- else
- // Call the constructor.
- EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
- E->arg_begin(), E->arg_end());
-}
-
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
EmitGlobal(GlobalDecl(D, Ctor_Complete));
EmitGlobal(GlobalDecl(D, Ctor_Base));
@@ -1001,33 +425,6 @@ CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
return m;
}
-llvm::Value *
-CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8Ty(VMContext)->getPointerTo();
-
- llvm::Value *VTablePtr = Builder.CreateBitCast(This,
- Int8PtrTy->getPointerTo());
- VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
-
- int64_t VBaseOffsetIndex =
- CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
-
- llvm::Value *VBaseOffsetPtr =
- Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
- const llvm::Type *PtrDiffTy =
- ConvertType(getContext().getPointerDiffType());
-
- VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
- PtrDiffTy->getPointerTo());
-
- llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
-
- return VBaseOffset;
-}
-
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -1058,71 +455,3 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
-
-void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->isDynamicClass())
- return;
-
- llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
- CodeGenModule::AddrSubMap_t& AddressPoints =
- *(*CGM.AddressPoints[ClassDecl])[ClassDecl];
- llvm::Value *ThisPtr = LoadCXXThis();
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
-
- // Store address points for virtual bases
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, Offset);
- }
-
- // Store address points for non-virtual bases and current class
- InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
-}
-
-void CodeGenFunction::InitializeVtablePtrsRecursive(
- const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CodeGenModule::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset) {
- if (!ClassDecl->isDynamicClass())
- return;
-
- // Store address points for non-virtual bases
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- if (Base.isVirtual())
- continue;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, NewOffset);
- }
-
- // Compute the address point
- assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
- "Missing address point for class");
- uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
- llvm::Value *VtableAddressPoint =
- Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
-
- // Compute the address to store the address point
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
- VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
- const llvm::Type *AddressPointPtrTy =
- VtableAddressPoint->getType()->getPointerTo();
- VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
-
- // Store address point
- Builder.CreateStore(VtableAddressPoint, VtableField);
-}
-
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 953b8c89dddd..ab3fece90f50 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -431,6 +431,37 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
EmitBlock(AfterFor, true);
}
+/// GetVTTParameter - Return the VTT parameter that should be passed to a
+/// base constructor/destructor with virtual bases.
+static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
+ if (!CGVtableInfo::needsVTTParameter(GD)) {
+ // This constructor/destructor does not need a VTT parameter.
+ return 0;
+ }
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+ const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ llvm::Value *VTT;
+
+ uint64_t SubVTTIndex =
+ CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+ assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
+
+ if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
+ // A VTT parameter was passed to the constructor, use it.
+ VTT = CGF.LoadCXXVTT();
+ VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+ } else {
+ // We're the complete constructor, so get the VTT by name.
+ VTT = CGF.CGM.getVtableInfo().getVTT(RD);
+ VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+ }
+
+ return VTT;
+}
+
+
/// EmitClassMemberwiseCopy - This routine generates code to copy a class
/// object from SrcValue to DestValue. Copying can be either a bitwise copy
/// or via a copy constructor call.
@@ -438,11 +469,16 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
llvm::Value *Dest, llvm::Value *Src,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
+ CXXCtorType CtorType = Ctor_Complete;
+
if (ClassDecl) {
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
+
+ // We want to call the base constructor.
+ CtorType = Ctor_Base;
}
if (BaseClassDecl->hasTrivialCopyConstructor()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -451,13 +487,19 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
if (CXXConstructorDecl *BaseCopyCtor =
BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
CallArgList CallArgs;
// Push the this (Dest) ptr.
CallArgs.push_back(std::make_pair(RValue::get(Dest),
BaseCopyCtor->getThisType(getContext())));
+ // Push the VTT parameter, if necessary.
+ if (llvm::Value *VTT =
+ GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
// Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType()));
@@ -787,10 +829,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
- // FIXME: This should always use Ctor_Base as the ctor type! (But that
- // causes crashes in tests.)
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
- CtorType, V,
+ Ctor_Base, V,
BaseInit->const_arg_begin(),
BaseInit->const_arg_end());
}
@@ -1044,3 +1084,347 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
+
+/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
+/// for-loop to call the default constructor on individual members of the
+/// array.
+/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
+/// array type and 'ArrayPtr' points to the beginning fo the array.
+/// 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,
+ 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, ArgBeg, ArgEnd);
+}
+
+void
+CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
+ 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);
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // Generate: if (loop-index < number-of-elements fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsLess, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
+ "arrayidx");
+
+ // 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);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
+ assert(CA && "Do we support VLA for destruction ?");
+ uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
+
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
+ EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *UpperCount,
+ llvm::Value *This) {
+ const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
+ llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
+
+ // Create a temporary for the loop index and initialize it with count of
+ // array elements.
+ llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
+
+ // Store the number of elements in the index pointer.
+ Builder.CreateStore(UpperCount, IndexPtr);
+
+ // Start the loop with a block that tests the condition.
+ llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
+ llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
+
+ EmitBlock(CondBlock);
+
+ llvm::BasicBlock *ForBody = createBasicBlock("for.body");
+
+ // Generate: if (loop-index != 0 fall to the loop body,
+ // otherwise, go to the block after the for-loop.
+ llvm::Value* zeroConstant =
+ llvm::Constant::getNullValue(SizeLTy);
+ llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
+ llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
+ "isne");
+ // If the condition is true, execute the body.
+ Builder.CreateCondBr(IsNE, ForBody, AfterFor);
+
+ EmitBlock(ForBody);
+
+ llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
+ // Inside the loop body, emit the constructor call on the array element.
+ Counter = Builder.CreateLoad(IndexPtr);
+ Counter = Builder.CreateSub(Counter, One);
+ llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
+ 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);
+
+ // Finally, branch back up to the condition for the next iteration.
+ EmitBranch(CondBlock);
+
+ // Emit the fall-through block.
+ EmitBlock(AfterFor, true);
+}
+
+/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
+/// invoked, calls the default destructor on array elements in reverse order of
+/// construction.
+llvm::Constant *
+CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ FunctionArgList Args;
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0,
+ SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+
+ llvm::SmallString<16> Name;
+ llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
+ QualType R = getContext().VoidTy;
+ const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ Name.str(),
+ &CGM.getModule());
+ IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ FinishFunction();
+ llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
+ 0);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
+
+void
+CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ if (D->isCopyConstructor()) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
+ if (ClassDecl->hasTrivialCopyConstructor()) {
+ assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
+ "EmitCXXConstructorCall - user declared copy constructor");
+ const Expr *E = (*ArgBeg);
+ QualType Ty = E->getType();
+ llvm::Value *Src = EmitLValue(E).getAddress();
+ 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 *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+ EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
+}
+
+void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ llvm::Value *This) {
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
+ llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+
+ EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
+}
+
+llvm::Value *
+CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ llvm::Value *VTablePtr = Builder.CreateBitCast(This,
+ Int8PtrTy->getPointerTo());
+ VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
+
+ int64_t VBaseOffsetIndex =
+ CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
+
+ llvm::Value *VBaseOffsetPtr =
+ Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
+ const llvm::Type *PtrDiffTy =
+ ConvertType(getContext().getPointerDiffType());
+
+ VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
+ PtrDiffTy->getPointerTo());
+
+ llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+
+ return VBaseOffset;
+}
+
+void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
+ if (!ClassDecl->isDynamicClass())
+ return;
+
+ llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
+ CGVtableInfo::AddrSubMap_t& AddressPoints =
+ *(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl];
+ llvm::Value *ThisPtr = LoadCXXThis();
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+
+ // Store address points for virtual bases
+ for (CXXRecordDecl::base_class_const_iterator I =
+ ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, Offset);
+ }
+
+ // Store address points for non-virtual bases and current class
+ InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
+}
+
+void CodeGenFunction::InitializeVtablePtrsRecursive(
+ const CXXRecordDecl *ClassDecl,
+ llvm::Constant *Vtable,
+ CGVtableInfo::AddrSubMap_t& AddressPoints,
+ llvm::Value *ThisPtr,
+ uint64_t Offset) {
+ if (!ClassDecl->isDynamicClass())
+ return;
+
+ // Store address points for non-virtual bases
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+ for (CXXRecordDecl::base_class_const_iterator I =
+ ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+ if (Base.isVirtual())
+ continue;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
+ InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
+ ThisPtr, NewOffset);
+ }
+
+ // Compute the address point
+ assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
+ "Missing address point for class");
+ uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
+ llvm::Value *VtableAddressPoint =
+ Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
+
+ // Compute the address to store the address point
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
+ VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
+ const llvm::Type *AddressPointPtrTy =
+ VtableAddressPoint->getType()->getPointerTo();
+ VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
+
+ // Store address point
+ Builder.CreateStore(VtableAddressPoint, VtableField);
+}
+
+llvm::Value *CodeGenFunction::LoadCXXVTT() {
+ assert((isa<CXXConstructorDecl>(CurFuncDecl) ||
+ isa<CXXDestructorDecl>(CurFuncDecl)) &&
+ "Must be in a C++ ctor or dtor to load the vtt parameter");
+
+ return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt");
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 19695c87817e..ab8f6637d6ce 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -65,6 +65,25 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
return CompileUnit;
}
+/// getFunctionName - Get function name for the given FunctionDecl. If the
+/// name is constructred on demand (e.g. C++ destructor) then the name
+/// is stored on the side.
+llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
+ assert (FD && "Invalid FunctionDecl!");
+ IdentifierInfo *FII = FD->getIdentifier();
+ if (FII)
+ return FII->getName();
+
+ // Otherwise construct human readable name for debug info.
+ std::string NS = FD->getNameAsString();
+
+ // Copy this name on the side and use its reference.
+ unsigned Length = NS.length() + 1;
+ char *StrPtr = FunctionNames.Allocate<char>(Length);
+ strncpy(StrPtr, NS.c_str(), Length);
+ return llvm::StringRef(StrPtr);
+}
+
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
/// one if necessary. This returns null for invalid source locations.
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
@@ -972,18 +991,32 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
-void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType,
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
- llvm::StringRef LinkageName(Name);
- // Skip the asm prefix if it exists.
- //
- // FIXME: This should probably be the unmangled name?
- if (Name[0] == '\01')
- Name = Name.substr(1);
+ llvm::StringRef Name;
+ llvm::StringRef LinkageName;
+
+ const Decl *D = GD.getDecl();
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ Name = getFunctionName(FD);
+ if (Name[0] == '\01')
+ Name = Name.substr(1);
+ // Use mangled name as linkage name for c/c++ functions.
+ LinkageName = CGM.getMangledName(GD);
+ } else {
+ // Use llvm function name as linkage name.
+ Name = Fn->getName();
+ // Skip the asm prefix if it exists.
+ if (Name[0] == '\01')
+ Name = Name.substr(1);
+ LinkageName = Name;
+ }
- // FIXME: Why is this using CurLoc???
+ // It is expected that CurLoc is set before using EmitFunctionStart.
+ // Usually, CurLoc points to the left bracket location of compound
+ // statement representing function body.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
SourceManager &SM = CGM.getContext().getSourceManager();
unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
@@ -1379,7 +1412,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
else
Unit = llvm::DICompileUnit();
- uint64_t offset = CGF->BlockDecls[Decl];
+ CharUnits offset = CGF->BlockDecls[Decl];
llvm::SmallVector<llvm::Value *, 9> addr;
llvm::LLVMContext &VMContext = CGM.getLLVMContext();
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
@@ -1387,22 +1420,24 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
if (BDRE->isByRef()) {
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpDeref));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
- offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field
+ // offset of __forwarding field
+ offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8);
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpDeref));
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
llvm::DIFactory::OpPlus));
- offset = XOffset/8; // offset of x field
+ // offset of x field
+ offset = CharUnits::fromQuantity(XOffset/8);
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- offset));
+ offset.getQuantity()));
}
// Create the descriptor for the variable.
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 7df2a6247b4c..8e8898805751 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Support/Allocator.h"
#include <map>
#include "CGBuilder.h"
@@ -35,6 +36,7 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
class CodeGenFunction;
+ class GlobalDecl;
/// CGDebugInfo - This class gathers all debug information during compilation
/// and is responsible for emitting to llvm globals or pass directly to
@@ -58,6 +60,10 @@ class CGDebugInfo {
std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
+ /// FunctionNames - This is a storage for function names that are
+ /// constructed on demand. For example, C++ destructors, C++ operators etc..
+ llvm::BumpPtrAllocator FunctionNames;
+
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U);
@@ -93,7 +99,7 @@ public:
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
- void EmitFunctionStart(llvm::StringRef Name, QualType FnType,
+ void EmitFunctionStart(GlobalDecl GD, QualType FnType,
llvm::Function *Fn, CGBuilderTy &Builder);
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
@@ -149,6 +155,11 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit);
+
+ /// getFunctionName - Get function name for the given FunctionDecl. If the
+ /// name is constructred on demand (e.g. C++ destructor) then the name
+ /// is stored on the side.
+ llvm::StringRef getFunctionName(const FunctionDecl *FD);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 602cc9efc7a0..9606a71527a4 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -473,7 +473,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
llvm::Value *SizeVal =
llvm::ConstantInt::get(IntPtr,
- getContext().getTypeSizeInChars(Ty).getRaw());
+ getContext().getTypeSizeInChars(Ty).getQuantity());
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
if (Loc->getType() != BP)
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 0b6ea5a834b1..47773a0d69e3 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -120,6 +120,22 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
}
void
+CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
+ const llvm::FunctionType *FTy
+ = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ false);
+
+ // Create a variable initialization function.
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ "__cxx_global_var_init", &TheModule);
+
+ CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
+
+ CXXGlobalInits.push_back(Fn);
+}
+
+void
CodeGenModule::EmitCXXGlobalInitFunc() {
if (CXXGlobalInits.empty())
return;
@@ -140,18 +156,26 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn);
}
+void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
+ const VarDecl *D) {
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
+ SourceLocation());
+
+ llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
+ EmitCXXGlobalVarDeclInit(*D, DeclPtr);
+
+ FinishFunction();
+}
+
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- const VarDecl **Decls,
+ llvm::Constant **Decls,
unsigned NumDecls) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
- for (unsigned i = 0; i != NumDecls; ++i) {
- const VarDecl *D = Decls[i];
+ for (unsigned i = 0; i != NumDecls; ++i)
+ Builder.CreateCall(Decls[i]);
- llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
- EmitCXXGlobalVarDeclInit(*D, DeclPtr);
- }
FinishFunction();
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ab451cf512e8..2358bb35923a 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -240,6 +240,132 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
EmitBlock(Cont);
}
+
+llvm::Value *CodeGenFunction::
+EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre) {
+ QualType ValTy = E->getSubExpr()->getType();
+ llvm::Value *InVal = EmitLoadOfLValue(LV, ValTy).getScalarVal();
+
+ int AmountVal = isInc ? 1 : -1;
+
+ if (ValTy->isPointerType() &&
+ ValTy->getAs<PointerType>()->isVariableArrayType()) {
+ // The amount of the addition/subtraction needs to account for the VLA size
+ ErrorUnsupported(E, "VLA pointer inc/dec");
+ }
+
+ llvm::Value *NextVal;
+ if (const llvm::PointerType *PT =
+ dyn_cast<llvm::PointerType>(InVal->getType())) {
+ llvm::Constant *Inc =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
+ if (!isa<llvm::FunctionType>(PT->getElementType())) {
+ QualType PTEE = ValTy->getPointeeType();
+ if (const ObjCInterfaceType *OIT =
+ dyn_cast<ObjCInterfaceType>(PTEE)) {
+ // Handle interface types, which are not represented with a concrete
+ // type.
+ int size = getContext().getTypeSize(OIT) / 8;
+ if (!isInc)
+ size = -size;
+ Inc = llvm::ConstantInt::get(Inc->getType(), size);
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ InVal = Builder.CreateBitCast(InVal, i8Ty);
+ NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
+ llvm::Value *lhs = LV.getAddress();
+ lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
+ LV = LValue::MakeAddr(lhs, MakeQualifiers(ValTy));
+ } else
+ NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
+ } else {
+ const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
+ NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
+ NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
+ NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
+ }
+ } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
+ // Bool++ is an interesting case, due to promotion rules, we get:
+ // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
+ // Bool = ((int)Bool+1) != 0
+ // An interesting aspect of this is that increment is always true.
+ // Decrement does not have this property.
+ NextVal = llvm::ConstantInt::getTrue(VMContext);
+ } else if (isa<llvm::IntegerType>(InVal->getType())) {
+ NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
+
+ // Signed integer overflow is undefined behavior.
+ if (ValTy->isSignedIntegerType())
+ NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ else
+ NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ } else {
+ // Add the inc/dec to the real part.
+ if (InVal->getType()->isFloatTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ llvm::APFloat(static_cast<float>(AmountVal)));
+ else if (InVal->getType()->isDoubleTy())
+ NextVal =
+ llvm::ConstantFP::get(VMContext,
+ llvm::APFloat(static_cast<double>(AmountVal)));
+ else {
+ llvm::APFloat F(static_cast<float>(AmountVal));
+ bool ignored;
+ F.convert(Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
+ &ignored);
+ NextVal = llvm::ConstantFP::get(VMContext, F);
+ }
+ NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
+ }
+
+ // Store the updated result through the lvalue.
+ if (LV.isBitfield())
+ EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, &NextVal);
+ else
+ EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? NextVal : InVal;
+}
+
+
+CodeGenFunction::ComplexPairTy CodeGenFunction::
+EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre) {
+ ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
+ LV.isVolatileQualified());
+
+ llvm::Value *NextVal;
+ if (isa<llvm::IntegerType>(InVal.first->getType())) {
+ uint64_t AmountVal = isInc ? 1 : -1;
+ NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
+
+ // Add the inc/dec to the real part.
+ NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
+ } else {
+ QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1);
+ if (!isInc)
+ FVal.changeSign();
+ NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal);
+
+ // Add the inc/dec to the real part.
+ NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
+ }
+
+ ComplexPairTy IncVal(NextVal, InVal.second);
+
+ // Store the updated result through the lvalue.
+ StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
+
+ // If this is a postinc, return the value read from memory, otherwise use the
+ // updated value.
+ return isPre ? IncVal : InVal;
+}
+
+
//===----------------------------------------------------------------------===//
// LValue Expression Emission
//===----------------------------------------------------------------------===//
@@ -994,8 +1120,16 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
MakeQualifiers(ExprTy));
}
case UnaryOperator::PreInc:
- case UnaryOperator::PreDec:
- return EmitUnsupportedLValue(E, "pre-inc/dec expression");
+ case UnaryOperator::PreDec: {
+ LValue LV = EmitLValue(E->getSubExpr());
+ bool isInc = E->getOpcode() == UnaryOperator::PreInc;
+
+ if (E->getType()->isAnyComplexType())
+ EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/);
+ else
+ EmitScalarPrePostIncDec(E, LV, isInc, true/*isPre*/);
+ return LV;
+ }
}
}
@@ -1139,16 +1273,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
QualType BaseType = getContext().getBaseElementType(VAT);
- uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8;
+ CharUnits BaseTypeSize = getContext().getTypeSizeInChars(BaseType);
Idx = Builder.CreateUDiv(Idx,
llvm::ConstantInt::get(Idx->getType(),
- BaseTypeSize));
+ BaseTypeSize.getQuantity()));
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
} else if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(E->getType())) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- getContext().getTypeSize(OIT) / 8);
+ getContext().getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
@@ -1211,8 +1345,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
Base = EmitLValue(E->getBase());
} else {
// Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
- const VectorType *VT = E->getBase()->getType()->getAs<VectorType>();
- assert(VT && "Result must be a vector");
+ assert(E->getBase()->getType()->getAs<VectorType>() &&
+ "Result must be a vector");
llvm::Value *Vec = EmitScalarExpr(E->getBase());
// Store the vector to memory (because LValue wants an address).
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index b95fd799010b..c852d65b859f 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -313,7 +313,8 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
"Unexpected member pointer type!");
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
+ const CXXMethodDecl *MD =
+ cast<CXXMethodDecl>(DRE->getDecl())->getCanonicalDecl();
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 79923221961f..e264109f02f0 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -15,6 +15,334 @@
using namespace clang;
using namespace CodeGen;
+RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
+ llvm::Value *Callee,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
+ llvm::Value *VTT,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This),
+ MD->getThisType(getContext())));
+
+ // If there is a VTT parameter, emit it.
+ if (VTT) {
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ Args.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+
+ QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValue, Args, MD);
+}
+
+/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
+/// expr can be devirtualized.
+static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // This is a record decl. We know the type and can devirtualize it.
+ return VD->getType()->isRecordType();
+ }
+
+ return false;
+ }
+
+ // We can always devirtualize calls on temporary object expressions.
+ if (isa<CXXTemporaryObjectExpr>(Base))
+ return true;
+
+ // And calls on bound temporaries.
+ if (isa<CXXBindTemporaryExpr>(Base))
+ return true;
+
+ // Check if this is a call expr that returns a record type.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
+ return CE->getCallReturnType()->isRecordType();
+
+ // We can't devirtualize the call.
+ return false;
+}
+
+RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
+ ReturnValueSlot ReturnValue) {
+ if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
+ return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
+
+ const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+
+ if (MD->isStatic()) {
+ // The method is static, emit it as we would a regular call.
+ llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
+ return EmitCall(getContext().getPointerType(MD->getType()), Callee,
+ ReturnValue, CE->arg_begin(), CE->arg_end());
+ }
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Value *This;
+
+ if (ME->isArrow())
+ This = EmitScalarExpr(ME->getBase());
+ else {
+ LValue BaseLV = EmitLValue(ME->getBase());
+ 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.
+ //
+ // We also don't emit a virtual call if the base expression has a record type
+ // because then we know what the type is.
+ 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);
+ } else {
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
+ }
+ } else if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(MD, This, Ty);
+ } else {
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+ }
+
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
+ CE->arg_begin(), CE->arg_end());
+}
+
+RValue
+CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
+ ReturnValueSlot ReturnValue) {
+ const BinaryOperator *BO =
+ cast<BinaryOperator>(E->getCallee()->IgnoreParens());
+ const Expr *BaseExpr = BO->getLHS();
+ const Expr *MemFnExpr = BO->getRHS();
+
+ const MemberPointerType *MPT =
+ MemFnExpr->getType()->getAs<MemberPointerType>();
+ const FunctionProtoType *FPT =
+ MPT->getPointeeType()->getAs<FunctionProtoType>();
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+
+ const llvm::FunctionType *FTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
+ FPT->isVariadic());
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ // Get the member function pointer.
+ llvm::Value *MemFnPtr =
+ CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
+ EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
+
+ // Emit the 'this' pointer.
+ llvm::Value *This;
+
+ if (BO->getOpcode() == BinaryOperator::PtrMemI)
+ This = EmitScalarExpr(BaseExpr);
+ else
+ This = EmitLValue(BaseExpr).getAddress();
+
+ // Adjust it.
+ llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
+ Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
+
+ llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
+ Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
+
+ This = Builder.CreateBitCast(Ptr, This->getType(), "this");
+
+ llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
+
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+
+ llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
+
+ // If the LSB in the function pointer is 1, the function pointer points to
+ // a virtual function.
+ llvm::Value *IsVirtual
+ = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
+ "and");
+
+ IsVirtual = Builder.CreateTrunc(IsVirtual,
+ llvm::Type::getInt1Ty(VMContext));
+
+ llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
+ llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
+ llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
+
+ Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
+ EmitBlock(FnVirtual);
+
+ const llvm::Type *VTableTy =
+ FTy->getPointerTo()->getPointerTo()->getPointerTo();
+
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
+ VTable = Builder.CreateLoad(VTable);
+
+ VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+
+ // Since the function pointer is 1 plus the virtual table offset, we
+ // subtract 1 by using a GEP.
+ VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
+
+ llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
+
+ EmitBranch(FnEnd);
+ EmitBlock(FnNonVirtual);
+
+ // If the function is not virtual, just load the pointer.
+ llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
+ NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
+
+ EmitBlock(FnEnd);
+
+ llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
+ Callee->reserveOperandSpace(2);
+ Callee->addIncoming(VirtualFn, FnVirtual);
+ Callee->addIncoming(NonVirtualFn, FnNonVirtual);
+
+ CallArgList Args;
+
+ QualType ThisType =
+ getContext().getPointerType(getContext().getTagDeclType(RD));
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This), ThisType));
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
+ QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
+ ReturnValue, Args);
+}
+
+RValue
+CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ ReturnValueSlot ReturnValue) {
+ assert(MD->isInstance() &&
+ "Trying to emit a member call expr on a static method!");
+
+ if (MD->isCopyAssignment()) {
+ const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
+ if (ClassDecl->hasTrivialCopyAssignment()) {
+ assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
+ "EmitCXXOperatorMemberCallExpr - user declared copy assignment");
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
+ QualType Ty = E->getType();
+ EmitAggregateCopy(This, Src, Ty);
+ return RValue::get(This);
+ }
+ }
+
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+
+ llvm::Value *Callee;
+ if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
+ Callee = BuildVirtualCall(MD, This, Ty);
+ else
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+
+ return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
+ E->arg_begin() + 1, E->arg_end());
+}
+
+void
+CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
+ const CXXConstructExpr *E) {
+ assert(Dest && "Must have a destination!");
+ const CXXConstructorDecl *CD = E->getConstructor();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(E->getType());
+ // For a copy constructor, even if it is trivial, must fall thru so
+ // its argument is code-gen'ed.
+ if (!CD->isCopyConstructor()) {
+ QualType InitType = E->getType();
+ if (Array)
+ InitType = getContext().getBaseElementType(Array);
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
+ if (RD->hasTrivialConstructor())
+ return;
+ }
+ // Code gen optimization to eliminate copy constructor and return
+ // its first argument instead.
+ if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
+ const Expr *Arg = E->getArg(0);
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
+ ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
+ ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
+ "Unknown implicit cast kind in constructor elision");
+ Arg = ICE->getSubExpr();
+ }
+
+ if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
+ Arg = FCE->getSubExpr();
+
+ if (const CXXBindTemporaryExpr *BindExpr =
+ dyn_cast<CXXBindTemporaryExpr>(Arg))
+ Arg = BindExpr->getSubExpr();
+
+ EmitAggExpr(Arg, Dest, false);
+ return;
+ }
+ if (Array) {
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(Dest, BasePtr);
+
+ EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
+ E->arg_begin(), E->arg_end());
+ }
+ else
+ // Call the constructor.
+ EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
+ E->arg_begin(), E->arg_end());
+}
+
static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
const RecordType *RT = ElementType->getAs<RecordType>();
if (!RT)
@@ -405,7 +733,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
/*isVariadic=*/false);
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
- EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0);
+ EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
+ 0, 0);
// The dtor took care of deleting the object.
ShouldCallDelete = false;
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index be2239ffb616..5ec336ce79e9 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -145,7 +145,10 @@ public:
// Operators.
ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre);
+ bool isInc, bool isPre) {
+ LValue LV = CGF.EmitLValue(E->getSubExpr());
+ return CGF.EmitComplexPrePostIncDec(E, LV, isInc, isPre);
+ }
ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, false);
}
@@ -355,40 +358,6 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
}
-ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre) {
- LValue LV = CGF.EmitLValue(E->getSubExpr());
- ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(),
- LV.isVolatileQualified());
-
- llvm::Value *NextVal;
- if (isa<llvm::IntegerType>(InVal.first->getType())) {
- uint64_t AmountVal = isInc ? 1 : -1;
- NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- } else {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
- llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1);
- if (!isInc)
- FVal.changeSign();
- NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal);
-
- // Add the inc/dec to the real part.
- NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
- }
-
- ComplexPairTy IncVal(NextVal, InVal.second);
-
- // Store the updated result through the lvalue.
- EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified());
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? IncVal : InVal;
-}
-
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index d428983f012a..dec06e295338 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -408,6 +408,8 @@ public:
llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) {
assert(MD->isInstance() && "Member function must not be static!");
+ MD = MD->getCanonicalDecl();
+
const llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
@@ -633,32 +635,6 @@ public:
return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
}
- llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) {
- const llvm::VectorType *VType =
- cast<llvm::VectorType>(ConvertType(ILE->getType()));
- const llvm::Type *ElemTy = VType->getElementType();
- std::vector<llvm::Constant*> Elts;
- unsigned NumElements = VType->getNumElements();
- unsigned NumInitElements = ILE->getNumInits();
-
- unsigned NumInitableElts = std::min(NumInitElements, NumElements);
-
- // Copy initializer elements.
- unsigned i = 0;
- for (; i < NumInitableElts; ++i) {
- Expr *Init = ILE->getInit(i);
- llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
- if (!C)
- return 0;
- Elts.push_back(C);
- }
-
- for (; i < NumElements; ++i)
- Elts.push_back(llvm::Constant::getNullValue(ElemTy));
-
- return llvm::ConstantVector::get(VType, Elts);
- }
-
llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) {
return CGM.EmitNullConstant(E->getType());
}
@@ -682,8 +658,9 @@ public:
if (ILE->getType()->isUnionType())
return EmitUnionInitialization(ILE);
+ // If ILE was a constant vector, we would have handled it already.
if (ILE->getType()->isVectorType())
- return EmitVectorInitialization(ILE);
+ return 0;
assert(0 && "Unable to handle InitListExpr");
// Get rid of control reaches end of void function warning.
@@ -833,7 +810,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
llvm::Constant *Offset =
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- Result.Val.getLValueOffset());
+ Result.Val.getLValueOffset().getQuantity());
llvm::Constant *C;
if (const Expr *LVBase = Result.Val.getLValueBase()) {
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 93646d6d3af9..690a7dc2fded 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -181,12 +181,6 @@ public:
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return EmitLoadOfLValue(E);
}
- Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); }
- Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
- return EmitLValue(E).getAddress();
- }
-
- Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
Value *VisitInitListExpr(InitListExpr *E);
@@ -214,7 +208,10 @@ public:
Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
// Unary Operators.
- Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre);
+ Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre) {
+ LValue LV = EmitLValue(E->getSubExpr());
+ return CGF.EmitScalarPrePostIncDec(E, LV, isInc, isPre);
+ }
Value *VisitUnaryPostDec(const UnaryOperator *E) {
return VisitPrePostIncDec(E, false, false);
}
@@ -1009,98 +1006,6 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
// Unary Operators
//===----------------------------------------------------------------------===//
-Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
- bool isInc, bool isPre) {
- LValue LV = EmitLValue(E->getSubExpr());
- QualType ValTy = E->getSubExpr()->getType();
- Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal();
-
- llvm::LLVMContext &VMContext = CGF.getLLVMContext();
-
- int AmountVal = isInc ? 1 : -1;
-
- if (ValTy->isPointerType() &&
- ValTy->getAs<PointerType>()->isVariableArrayType()) {
- // The amount of the addition/subtraction needs to account for the VLA size
- CGF.ErrorUnsupported(E, "VLA pointer inc/dec");
- }
-
- Value *NextVal;
- if (const llvm::PointerType *PT =
- dyn_cast<llvm::PointerType>(InVal->getType())) {
- llvm::Constant *Inc =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
- if (!isa<llvm::FunctionType>(PT->getElementType())) {
- QualType PTEE = ValTy->getPointeeType();
- if (const ObjCInterfaceType *OIT =
- dyn_cast<ObjCInterfaceType>(PTEE)) {
- // Handle interface types, which are not represented with a concrete type.
- int size = CGF.getContext().getTypeSize(OIT) / 8;
- if (!isInc)
- size = -size;
- Inc = llvm::ConstantInt::get(Inc->getType(), size);
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- InVal = Builder.CreateBitCast(InVal, i8Ty);
- NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
- llvm::Value *lhs = LV.getAddress();
- lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
- LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy));
- } else
- NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
- } else {
- const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
- NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
- NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
- NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
- }
- } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
- // Bool++ is an interesting case, due to promotion rules, we get:
- // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
- // Bool = ((int)Bool+1) != 0
- // An interesting aspect of this is that increment is always true.
- // Decrement does not have this property.
- NextVal = llvm::ConstantInt::getTrue(VMContext);
- } else if (isa<llvm::IntegerType>(InVal->getType())) {
- NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
-
- // Signed integer overflow is undefined behavior.
- if (ValTy->isSignedIntegerType())
- NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
- else
- NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
- } else {
- // Add the inc/dec to the real part.
- if (InVal->getType()->isFloatTy())
- NextVal =
- llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<float>(AmountVal)));
- else if (InVal->getType()->isDoubleTy())
- NextVal =
- llvm::ConstantFP::get(VMContext,
- llvm::APFloat(static_cast<double>(AmountVal)));
- else {
- llvm::APFloat F(static_cast<float>(AmountVal));
- bool ignored;
- F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
- &ignored);
- NextVal = llvm::ConstantFP::get(VMContext, F);
- }
- NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
- }
-
- // Store the updated result through the lvalue.
- if (LV.isBitfield())
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy,
- &NextVal);
- else
- CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
-
- // If this is a postinc, return the value read from memory, otherwise use the
- // updated value.
- return isPre ? NextVal : InVal;
-}
-
-
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
Value *Op = Visit(E->getSubExpr());
@@ -1405,7 +1310,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().getTypeSize(OIT) / 8);
+ CGF.getContext().getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
@@ -1469,7 +1374,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
dyn_cast<ObjCInterfaceType>(LHSElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
- CGF.getContext().getTypeSize(OIT) / 8);
+ CGF.getContext().
+ getTypeSizeInChars(OIT).getQuantity());
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
@@ -1493,14 +1399,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Value *LHS = Ops.LHS;
Value *RHS = Ops.RHS;
- uint64_t ElementSize;
+ CharUnits ElementSize;
// Handle GCC extension for pointer arithmetic on void* and function pointer
// types.
if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
- ElementSize = 1;
+ ElementSize = CharUnits::One();
} else {
- ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
+ ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
}
const llvm::Type *ResultType = ConvertType(Ops.Ty);
@@ -1509,13 +1415,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
// Optimize out the shift for element size of 1.
- if (ElementSize == 1)
+ if (ElementSize.isOne())
return BytesBetween;
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
// pointer difference in C is only defined in the case where both operands
// are pointing to elements of an array.
- Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
+ Value *BytesPerElt =
+ llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
}
@@ -1971,47 +1878,6 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
DstTy);
}
-Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) {
- assert(V1->getType() == V2->getType() &&
- "Vector operands must be of the same type");
- unsigned NumElements =
- cast<llvm::VectorType>(V1->getType())->getNumElements();
-
- va_list va;
- va_start(va, V2);
-
- llvm::SmallVector<llvm::Constant*, 16> Args;
- for (unsigned i = 0; i < NumElements; i++) {
- int n = va_arg(va, int);
- assert(n >= 0 && n < (int)NumElements * 2 &&
- "Vector shuffle index out of bounds!");
- Args.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), n));
- }
-
- const char *Name = va_arg(va, const char *);
- va_end(va);
-
- llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
-
- return Builder.CreateShuffleVector(V1, V2, Mask, Name);
-}
-
-llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals,
- unsigned NumVals, bool isSplat) {
- llvm::Value *Vec
- = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals));
-
- for (unsigned i = 0, e = NumVals; i != e; ++i) {
- llvm::Value *Val = isSplat ? Vals[0] : Vals[i];
- llvm::Value *Idx = llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(VMContext), i);
- Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp");
- }
-
- return Vec;
-}
-
LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
llvm::Value *V;
// object->isa or (*object).isa
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 95f67ae36a1e..e7a2093aa2e4 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -114,9 +114,11 @@ private:
llvm::Constant *ExportUniqueString(const std::string &Str, const std::string
prefix);
llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="");
+ std::vector<llvm::Constant*> &V, const std::string &Name="",
+ llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name="");
+ std::vector<llvm::Constant*> &V, const std::string &Name="",
+ llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage);
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
void EmitClassRef(const std::string &className);
@@ -215,8 +217,11 @@ static std::string SymbolNameForClass(const std::string &ClassName) {
static std::string SymbolNameForMethod(const std::string &ClassName, const
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
{
- return "_OBJC_METHOD_" + ClassName + "("+CategoryName+")"+
- (isClassMethod ? "+" : "-") + MethodName;
+ std::string MethodNameColonStripped = MethodName;
+ std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
+ ':', '_');
+ return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
+ CategoryName + "_" + MethodNameColonStripped;
}
CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
@@ -257,6 +262,10 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *OID) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
+ // With the incompatible ABI, this will need to be replaced with a direct
+ // reference to the class symbol. For the compatible nonfragile ABI we are
+ // still performing this lookup at run time but emitting the symbol for the
+ // class externally so that we can make the switch later.
EmitClassRef(OID->getNameAsString());
ClassName = Builder.CreateStructGEP(ClassName, 0);
@@ -323,14 +332,16 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str,
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name) {
+ std::vector<llvm::Constant*> &V, const std::string &Name,
+ llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
llvm::GlobalValue::InternalLinkage, C, Name);
}
llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
- std::vector<llvm::Constant*> &V, const std::string &Name) {
+ std::vector<llvm::Constant*> &V, const std::string &Name,
+ llvm::GlobalValue::LinkageTypes linkage) {
llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
return new llvm::GlobalVariable(TheModule, Ty, false,
llvm::GlobalValue::InternalLinkage, C, Name);
@@ -703,7 +714,10 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Elements.push_back(IvarOffsets);
Elements.push_back(Properties);
// Create an instance of the structure
- return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name));
+ // This is now an externally visible symbol, so that we can speed up class
+ // messages in the next ABI.
+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name),
+ llvm::GlobalValue::ExternalLinkage);
}
llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
@@ -1607,7 +1621,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
Params.push_back(PtrTy);
llvm::Value *RethrowFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false), "objc_exception_throw");
+ Params, false), "_Unwind_Resume");
bool isTry = isa<ObjCAtTryStmt>(S);
llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
@@ -1923,7 +1937,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
if (!IvarOffsetPointer) {
uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar);
llvm::ConstantInt *OffsetGuess =
- llvm::ConstantInt::get(LongTy, Offset, "ivar");
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar");
// Don't emit the guess in non-PIC code because the linker will not be able
// to replace it with the real version for a library. In non-PIC code you
// must compile with the fragile ABI if you want to use ivars from a
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index db6c5075ede4..29552ce4441c 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -360,28 +360,12 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
// If we're in an anonymous namespace, then we always want internal linkage.
if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
return llvm::GlobalVariable::InternalLinkage;
-
+
+ // If this class does not have a vtable, we want weak linkage.
if (!RD->isDynamicClass())
return llvm::GlobalValue::WeakODRLinkage;
- // Get the key function.
- const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD);
- if (!KeyFunction) {
- // There is no key function, the RTTI descriptor is emitted with weak_odr
- // linkage.
- return llvm::GlobalValue::WeakODRLinkage;
- }
-
- // If the key function is defined, but inlined, then the RTTI descriptor is
- // emitted with weak_odr linkage.
- const FunctionDecl* KeyFunctionDefinition;
- KeyFunction->getBody(KeyFunctionDefinition);
-
- if (KeyFunctionDefinition->isInlined())
- return llvm::GlobalValue::WeakODRLinkage;
-
- // Otherwise, the RTTI descriptor is emitted with external linkage.
- return llvm::GlobalValue::ExternalLinkage;
+ return CodeGenModule::getVtableLinkage(RD);
}
case Type::Vector:
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 7930f7186da5..ae900d6ae70e 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -160,17 +160,19 @@ private:
// vtable for use in computing the initializers for the VTT.
llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
+ /// AddressPoints - Address points for this vtable.
+ CGVtableInfo::AddressPointsMapTy& AddressPoints;
+
typedef CXXRecordDecl::method_iterator method_iter;
- const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
static llvm::DenseMap<CtorVtable_t, int64_t>&
AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
const CXXRecordDecl *c) {
- CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l];
+ CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l];
if (oref == 0)
- oref = new CodeGenModule::AddrMap_t;
+ oref = new CGVtableInfo::AddrMap_t;
llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
if (ref == 0)
@@ -193,14 +195,15 @@ private:
public:
VtableBuilder(const CXXRecordDecl *MostDerivedClass,
const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
- bool build)
+ bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
: BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)),
rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm),
PureVirtualFn(0),
subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)),
- Extern(!l->isInAnonymousNamespace()),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ AddressPoints(AddressPoints),
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0))
+ {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
if (BuildVtable) {
QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
@@ -213,7 +216,7 @@ public:
return VtableComponents;
}
- llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex()
{ return VBIndex; }
SavedAdjustmentsVectorTy &getSavedAdjustments()
@@ -463,6 +466,7 @@ public:
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
// Now also add the address point for all our primary bases.
while (1) {
@@ -479,6 +483,7 @@ public:
RD->getNameAsCString(), Class->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
}
}
@@ -827,7 +832,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
MD->getNameAsString().c_str(), (int)-idx-3,
(int)VCalls[idx-1], Class->getNameAsCString()));
}
- VCall[GD] = idx;
int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
int64_t VirtualAdjustment =
-((idx + extra + 2) * LLVMPointerWidth / 8);
@@ -844,6 +848,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
SavedAdjustments.push_back(
std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
}
+ VCall[GD] = idx;
return true;
}
@@ -1090,7 +1095,8 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) {
if (!SavedAdjustmentRecords.insert(RD).second)
return 0;
- VtableBuilder b(RD, RD, 0, CGM, false);
+ AddressPointsMapTy AddressPoints;
+ VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1118,7 +1124,8 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(RD, RD, 0, CGM, false);
+ AddressPointsMapTy AddressPoints;
+ VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -1139,7 +1146,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) {
uint64_t AddressPoint =
- (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
+ (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
return AddressPoint;
}
@@ -1148,7 +1155,8 @@ llvm::GlobalVariable *
CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset) {
+ const CXXRecordDecl *RD, uint64_t Offset,
+ AddressPointsMapTy& AddressPoints) {
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
@@ -1158,8 +1166,10 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV == 0 || CGM.AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) {
- VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition);
+ if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
+ GV->isDeclaration()) {
+ VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
+ AddressPoints);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
@@ -1206,11 +1216,51 @@ class VTTBuilder {
/// BLayout - Layout for the most derived class that this vtable is being
/// built for.
const ASTRecordLayout &BLayout;
- CodeGenModule::AddrMap_t &AddressPoints;
+ CGVtableInfo::AddrMap_t &AddressPoints;
// vtbl - A pointer to the vtable for Class.
llvm::Constant *ClassVtbl;
llvm::LLVMContext &VMContext;
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ bool GenerateDefinition;
+
+ llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
+ llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
+ CtorVtableAddressPoints;
+
+ llvm::Constant *getCtorVtable(const BaseSubobject &Base) {
+ if (!GenerateDefinition)
+ return 0;
+
+ llvm::Constant *&CtorVtable = CtorVtables[Base];
+ if (!CtorVtable) {
+ // Build the vtable.
+ CGVtableInfo::CtorVtableInfo Info
+ = CGM.getVtableInfo().getCtorVtable(Class, Base);
+
+ CtorVtable = Info.Vtable;
+
+ // Add the address points for this base.
+ for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
+ Info.AddressPoints.begin(), E = Info.AddressPoints.end();
+ I != E; ++I) {
+ uint64_t &AddressPoint =
+ CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
+
+ // Check if we already have the address points for this base.
+ if (AddressPoint)
+ break;
+
+ // Otherwise, insert it.
+ AddressPoint = I->second;
+ }
+ }
+
+ return CtorVtable;
+ }
+
+
/// BuildVtablePtr - Build up a referene to the given secondary vtable
llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
const CXXRecordDecl *VtableClass,
@@ -1270,14 +1320,17 @@ class VTTBuilder {
// FIXME: Slightly too many of these for __ZTT8test8_B2
llvm::Constant *init;
if (BaseMorallyVirtual)
- init = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0;
else {
- init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0;
subvtbl = init;
subVtblClass = Base;
- init = BuildVtablePtr(init, Class, Base, BaseOffset);
+ init = GenerateDefinition ?
+ BuildVtablePtr(init, Class, Base, BaseOffset) : 0;
}
Inits.push_back(init);
}
@@ -1296,14 +1349,16 @@ class VTTBuilder {
// First comes the primary virtual table pointer...
if (MorallyVirtual) {
- Vtable = ClassVtbl;
+ Vtable = GenerateDefinition ? ClassVtbl : 0;
VtableClass = Class;
} else {
- Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ Vtable = GenerateDefinition ?
+ getCtorVtable(BaseSubobject(RD, Offset)) : 0;
VtableClass = RD;
}
- llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0;
Inits.push_back(Init);
// then the secondary VTTs....
@@ -1326,6 +1381,10 @@ class VTTBuilder {
continue;
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
BuildVTT(Base, BaseOffset, MorallyVirtual);
}
}
@@ -1338,6 +1397,9 @@ class VTTBuilder {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (i->isVirtual() && !SeenVBase.count(Base)) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[Base] = Inits.size();
+
SeenVBase.insert(Base);
uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
BuildVTT(Base, BaseOffset, true);
@@ -1348,15 +1410,18 @@ class VTTBuilder {
public:
VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm)
+ CodeGenModule &cgm, bool GenerateDefinition)
: Inits(inits), Class(c), CGM(cgm),
BLayout(cgm.getContext().getASTRecordLayout(c)),
- AddressPoints(*cgm.AddressPoints[c]),
- VMContext(cgm.getModule().getContext()) {
+ AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
+ VMContext(cgm.getModule().getContext()),
+ GenerateDefinition(GenerateDefinition) {
// First comes the primary virtual table pointer for the complete class...
ClassVtbl = CGM.getVtableInfo().getVtable(Class);
- Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0));
+ llvm::Constant *Init = GenerateDefinition ?
+ BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0;
+ Inits.push_back(Init);
// then the secondary VTTs...
SecondaryVTTs(Class);
@@ -1367,11 +1432,16 @@ public:
// and last, the virtual VTTs.
VirtualVTTs(Class);
}
+
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
+ return SubVTTIndicies;
+ }
};
}
llvm::GlobalVariable *
CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
@@ -1381,23 +1451,36 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
CGM.getMangleContext().mangleCXXVTT(RD, OutName);
llvm::StringRef Name = OutName.str();
-
D1(printf("vtt %s\n", RD->getNameAsCString()));
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV == 0 || GV->isDeclaration()) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
-
- llvm::Constant *Init = llvm::ConstantArray::get(Type, inits);
-
- llvm::GlobalVariable *VTT =
- new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
- Linkage, Init, Name);
- CGM.setGlobalVisibility(VTT, RD);
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+
+ const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
+ llvm::Constant *Init = 0;
+ if (GenerateDefinition)
+ Init = llvm::ConstantArray::get(Type, inits);
+
+ llvm::GlobalVariable *OldGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
+ Linkage, Init, Name);
+ CGM.setGlobalVisibility(GV, RD);
+
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+ }
- return VTT;
+ return GV;
}
void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
@@ -1408,28 +1491,44 @@ void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
return;
}
- Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0);
- GenerateVTT(Linkage, RD);
+ AddressPointsMapTy AddressPoints;
+ Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0,
+ AddressPoints);
+ GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
}
llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
llvm::GlobalVariable *Vtable = Vtables.lookup(RD);
- if (!Vtable)
+ if (!Vtable) {
+ AddressPointsMapTy AddressPoints;
Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage,
- /*GenerateDefinition=*/false, RD, RD, 0);
+ /*GenerateDefinition=*/false, RD, RD, 0,
+ AddressPoints);
+ }
return Vtable;
}
-llvm::GlobalVariable *
-CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset) {
- return GenerateVtable(llvm::GlobalValue::InternalLinkage,
- /*GenerateDefinition=*/true,
- LayoutClass, RD, Offset);
+CGVtableInfo::CtorVtableInfo
+CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base) {
+ CtorVtableInfo Info;
+
+ Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
+ /*GenerateDefinition=*/true,
+ RD, Base.getBase(), Base.getBaseOffset(),
+ Info.AddressPoints);
+ return Info;
+}
+
+llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+ return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
+ /*GenerateDefinition=*/false, RD);
+
}
+
void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
@@ -1445,28 +1544,10 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
// We don't have the right 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;
- } else {
- // If there is no key function, we only want to emit the vtable if we are
- // emitting a constructor.
- if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete)
- return;
}
- llvm::GlobalVariable::LinkageTypes Linkage;
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
- Linkage = llvm::GlobalVariable::InternalLinkage;
- else if (KeyFunction && !MD->isInlined())
- Linkage = llvm::GlobalVariable::ExternalLinkage;
- else
- Linkage = llvm::GlobalVariable::WeakODRLinkage;
-
// Emit the data.
- GenerateClassData(Linkage, RD);
+ GenerateClassData(CGM.getVtableLinkage(RD), RD);
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end(); i != e; ++i) {
@@ -1481,3 +1562,47 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
}
}
+bool CGVtableInfo::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;
+}
+
+uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
+ ClassPairTy ClassPair(RD, Base);
+
+ SubVTTIndiciesTy::iterator I =
+ SubVTTIndicies.find(ClassPair);
+ if (I != SubVTTIndicies.end())
+ return I->second;
+
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ Builder.getSubVTTIndicies().begin(),
+ E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
+ // Insert all indices.
+ ClassPairTy ClassPair(RD, I->first);
+
+ SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ }
+
+ I = SubVTTIndicies.find(ClassPair);
+ assert(I != SubVTTIndicies.end() && "Did not find index!");
+
+ return I->second;
+}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index eed5b64085b0..471d6384d6b2 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -61,11 +61,83 @@ public:
ThunkAdjustment ReturnAdjustment;
};
+// BaseSubobject - Uniquely identifies a direct or indirect base class.
+// Stores both the base class decl and the offset from the most derived class to
+// the base class.
+class BaseSubobject {
+ /// Base - The base class declaration.
+ const CXXRecordDecl *Base;
+
+ /// BaseOffset - The offset from the most derived class to the base class.
+ uint64_t BaseOffset;
+
+public:
+ BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset)
+ : Base(Base), BaseOffset(BaseOffset) { }
+
+ /// getBase - Returns the base class declaration.
+ const CXXRecordDecl *getBase() const { return Base; }
+
+ /// getBaseOffset - Returns the base class offset.
+ uint64_t getBaseOffset() const { return BaseOffset; }
+
+ friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) {
+ return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> {
+ static clang::CodeGen::BaseSubobject getEmptyKey() {
+ return clang::CodeGen::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(),
+ DenseMapInfo<uint64_t>::getEmptyKey());
+ }
+
+ static clang::CodeGen::BaseSubobject getTombstoneKey() {
+ return clang::CodeGen::BaseSubobject(
+ DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(),
+ DenseMapInfo<uint64_t>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) {
+ return
+ DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^
+ DenseMapInfo<uint64_t>::getHashValue(Base.getBaseOffset());
+ }
+
+ static bool isEqual(const clang::CodeGen::BaseSubobject &LHS,
+ const clang::CodeGen::BaseSubobject &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// It's OK to treat BaseSubobject as a POD type.
+template <> struct isPodLike<clang::CodeGen::BaseSubobject> {
+ static const bool value = true;
+};
+
+}
+
+namespace clang {
+namespace CodeGen {
+
class CGVtableInfo {
public:
typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> >
AdjustmentVectorTy;
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
+ typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t;
+ typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t;
+ llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+
private:
CodeGenModule &CGM;
@@ -93,6 +165,9 @@ private:
SavedAdjustmentsTy SavedAdjustments;
llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+ typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
+ SubVTTIndiciesTy SubVTTIndicies;
+
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
@@ -110,15 +185,26 @@ private:
llvm::GlobalVariable *
GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition, const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset);
+ const CXXRecordDecl *RD, uint64_t Offset,
+ AddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
const CXXRecordDecl *RD);
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
+ /// needsVTTParameter - Return whether the given global decl needs a VTT
+ /// parameter, which it does if it's a base constructor or destructor with
+ /// virtual bases.
+ static bool needsVTTParameter(GlobalDecl GD);
+
+ /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
+ /// given record decl.
+ uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base);
+
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
@@ -140,14 +226,26 @@ public:
uint64_t getVtableAddressPoint(const CXXRecordDecl *RD);
llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD);
- llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD,
- const CXXRecordDecl *Class,
- uint64_t Offset);
+ /// CtorVtableInfo - Information about a constructor vtable.
+ struct CtorVtableInfo {
+ /// Vtable - The vtable itself.
+ llvm::GlobalVariable *Vtable;
+
+ /// AddressPoints - The address points in this constructor vtable.
+ AddressPointsMapTy AddressPoints;
+
+ CtorVtableInfo() : Vtable(0) { }
+ };
+
+ CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base);
+
+ llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
void MaybeEmitVtable(GlobalDecl GD);
};
-}
-}
+} // end namespace CodeGen
+} // end namespace clang
#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 3c264847402e..45469d39e4af 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -29,5 +29,5 @@ add_clang_library(clangCodeGen
CodeGenTypes.cpp
Mangle.cpp
ModuleBuilder.cpp
- TargetABIInfo.cpp
+ TargetInfo.cpp
)
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f904f043caa4..f0a5c64d2fdf 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -190,15 +190,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0);
// Emit subprogram debug descriptor.
- // FIXME: The cast here is a huge hack.
if (CGDebugInfo *DI = getDebugInfo()) {
DI->setLocation(StartLoc);
- if (isa<FunctionDecl>(D)) {
- DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder);
- } else {
- // Just use LLVM function name.
- DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder);
- }
+ DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
// FIXME: Leaked.
@@ -230,26 +224,7 @@ 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) {
+void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
// Check if we should generate debug info for this function.
@@ -271,7 +246,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
// Check if we need a VTT parameter as well.
- if (NeedsVTTParameter(GD)) {
+ if (CGVtableInfo::needsVTTParameter(GD)) {
// FIXME: The comment about using a fake decl above applies here too.
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
CXXVTTDecl =
@@ -597,7 +572,7 @@ llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) {
ElemSize = EmitVLASize(ElemTy);
else
ElemSize = llvm::ConstantInt::get(SizeTy,
- getContext().getTypeSize(ElemTy) / 8);
+ getContext().getTypeSizeInChars(ElemTy).getQuantity());
llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr());
NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp");
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 273ddcac7976..30ad663771be 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -17,6 +17,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/CharUnits.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
@@ -463,7 +464,7 @@ public:
llvm::Value *BuildBlockLiteralTmp(const BlockExpr *);
llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose,
- uint64_t Size,
+ CharUnits Size,
const llvm::StructType *,
std::vector<HelperInfo> *);
@@ -471,14 +472,14 @@ public:
const BlockInfo& Info,
const Decl *OuterFuncDecl,
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
- uint64_t &Size, uint64_t &Align,
+ CharUnits &Size, uint64_t &Align,
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
bool &subBlockHasCopyDispose);
void BlockForwardSelf();
llvm::Value *LoadBlockStruct();
- uint64_t AllocateBlockDecl(const BlockDeclRefExpr *E);
+ CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E);
llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
const llvm::Type *BuildByRefType(const ValueDecl *D);
@@ -517,7 +518,7 @@ public:
void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl,
llvm::Constant *Vtable,
- CodeGenModule::AddrSubMap_t& AddressPoints,
+ CGVtableInfo::AddrSubMap_t& AddressPoints,
llvm::Value *ThisPtr,
uint64_t Offset);
@@ -728,6 +729,10 @@ public:
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
+ /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
+ /// virtual bases.
+ llvm::Value *LoadCXXVTT();
+
/// 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.
@@ -794,7 +799,7 @@ public:
llvm::Value *NumElements,
llvm::Value *This);
- llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ llvm::Constant *GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
const ArrayType *Array,
llvm::Value *This);
@@ -815,6 +820,10 @@ public:
void EmitCheck(llvm::Value *, unsigned Size);
+ llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre);
+ ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
+ bool isInc, bool isPre);
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -1057,6 +1066,7 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
+ llvm::Value *VTT,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
@@ -1081,10 +1091,6 @@ public:
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
- llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...);
- llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals,
- bool isSplat = false);
-
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
@@ -1184,9 +1190,11 @@ public:
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables.
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
- const VarDecl **Decls,
+ llvm::Constant **Decls,
unsigned NumDecls);
+ void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D);
+
void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E);
RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index d497471e4597..5ecc30eb4ea2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -17,6 +17,7 @@
#include "CGCall.h"
#include "CGObjCRuntime.h"
#include "Mangle.h"
+#include "TargetInfo.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -42,8 +43,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Diagnostic &diags)
: BlockModule(C, M, TD, Types, *this), Context(C),
Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
- TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C),
- VtableInfo(*this), Runtime(0),
+ TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()),
+ MangleCtx(C), VtableInfo(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
VMContext(M.getContext()) {
@@ -66,10 +68,8 @@ CodeGenModule::~CodeGenModule() {
}
void CodeGenModule::Release() {
- // We need to call this first because it can add deferred declarations.
- EmitCXXGlobalInitFunc();
-
EmitDeferred();
+ EmitCXXGlobalInitFunc();
if (Runtime)
if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
@@ -378,6 +378,8 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GV->setSection(SA->getName());
+
+ getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -537,7 +539,8 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
const CXXRecordDecl *RD = MD->getParent();
if (MD->isOutOfLine() && RD->isDynamicClass()) {
const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
- if (KeyFunction == MD->getCanonicalDecl())
+ if (KeyFunction &&
+ KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl())
return false;
}
}
@@ -876,6 +879,57 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
+llvm::GlobalVariable::LinkageTypes
+CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
+ if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ return llvm::GlobalVariable::InternalLinkage;
+
+ if (const CXXMethodDecl *KeyFunction
+ = RD->getASTContext().getKeyFunction(RD)) {
+ // If this class has a key function, use that to determine the linkage of
+ // the vtable.
+ const FunctionDecl *Def = 0;
+ if (KeyFunction->getBody(Def))
+ KeyFunction = cast<CXXMethodDecl>(Def);
+
+ switch (KeyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ if (KeyFunction->isInlined())
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ return llvm::GlobalVariable::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ // FIXME: Use available_externally linkage. However, this currently
+ // breaks LLVM's build due to undefined symbols.
+ // return llvm::GlobalVariable::AvailableExternallyLinkage;
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+ }
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ // FIXME: Use available_externally linkage. However, this currently
+ // breaks LLVM's build due to undefined symbols.
+ // return llvm::GlobalVariable::AvailableExternallyLinkage;
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+
+ // Silence GCC warning.
+ return llvm::GlobalVariable::WeakODRLinkage;
+}
+
static CodeGenModule::GVALinkage
GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
// Everything located semantically within an anonymous namespace is
@@ -909,6 +963,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0;
QualType ASTTy = D->getType();
+ bool NonConstInit = false;
if (D->getInit() == 0) {
// This is a tentative definition; tentative definitions are
@@ -928,8 +983,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (!Init) {
QualType T = D->getInit()->getType();
if (getLangOptions().CPlusPlus) {
- CXXGlobalInits.push_back(D);
+ EmitCXXGlobalVarDeclInitFunc(D);
Init = EmitNullConstant(T);
+ NonConstInit = true;
} else {
ErrorUnsupported(D, "static initializer");
Init = llvm::UndefValue::get(getTypes().ConvertType(T));
@@ -990,7 +1046,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(false);
- if (DeclIsConstantGlobal(Context, D))
+ if (!NonConstInit && DeclIsConstantGlobal(Context, D))
GV->setConstant(true);
GV->setAlignment(getContext().getDeclAlignInBytes(D));
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 939c66ca3147..c7aa7a47a836 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -43,6 +43,7 @@ namespace llvm {
}
namespace clang {
+ class TargetCodeGenInfo;
class ASTContext;
class FunctionDecl;
class IdentifierInfo;
@@ -85,6 +86,7 @@ class CodeGenModule : public BlockModule {
const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
+ mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
Diagnostic &Diags;
CodeGenTypes Types;
MangleContext MangleCtx;
@@ -153,7 +155,7 @@ class CodeGenModule : public BlockModule {
/// CXXGlobalInits - Variables with global initializers that need to run
/// before main.
- std::vector<const VarDecl*> CXXGlobalInits;
+ std::vector<llvm::Constant*> CXXGlobalInits;
/// CFConstantStringClassRef - Cached reference to the class for constant
/// strings. This value has type int * but is actually an Obj-C class pointer.
@@ -191,6 +193,7 @@ public:
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
+ const TargetCodeGenInfo &getTargetCodeGenInfo() const;
/// getDeclVisibilityMode - Compute the visibility of the decl \arg D.
LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const;
@@ -232,11 +235,6 @@ public:
BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
const CovariantThunkAdjustment &Adjustment);
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t;
- typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t;
- llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
-
/// GetCXXBaseClassOffset - Returns the offset from a derived class to its
/// base class. Returns null if the offset is 0.
llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
@@ -412,6 +410,11 @@ public:
GVA_TemplateInstantiation
};
+ /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT,
+ /// and type information of the given class.
+ static llvm::GlobalVariable::LinkageTypes
+ getVtableLinkage(const CXXRecordDecl *RD);
+
private:
/// UniqueMangledName - Unique a name by (if necessary) inserting it into the
/// MangledNames string map.
@@ -475,7 +478,9 @@ private:
/// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
-
+
+ void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D);
+
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index cd34e0c064ef..838f62a5cb1d 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -28,9 +28,9 @@ using namespace clang;
using namespace CodeGen;
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
- const llvm::TargetData &TD)
+ const llvm::TargetData &TD, const ABIInfo &Info)
: Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD),
- TheABIInfo(0) {
+ TheABIInfo(Info) {
}
CodeGenTypes::~CodeGenTypes() {
@@ -38,13 +38,10 @@ CodeGenTypes::~CodeGenTypes() {
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
- {
- llvm::FoldingSet<CGFunctionInfo>::iterator
- I = FunctionInfos.begin(), E = FunctionInfos.end();
- while (I != E)
- delete &*I++;
- }
- delete TheABIInfo;
+
+ for (llvm::FoldingSet<CGFunctionInfo>::iterator
+ I = FunctionInfos.begin(), E = FunctionInfos.end(); I != E; )
+ delete &*I++;
}
/// ConvertType - Convert the specified type to its LLVM form.
@@ -56,9 +53,8 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// circular types. Loop through all these defered pointees, if any, and
// resolve them now.
while (!PointersToResolve.empty()) {
- std::pair<QualType, llvm::OpaqueType*> P =
- PointersToResolve.back();
- PointersToResolve.pop_back();
+ std::pair<QualType, llvm::OpaqueType*> P = PointersToResolve.pop_back_val();
+
// We can handle bare pointers here because we know that the only pointers
// to the Opaque type are P.second and from other types. Refining the
// opqaue type away will invalidate P.second, but we don't mind :).
@@ -88,9 +84,10 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) {
const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) {
const llvm::Type *ResultType = ConvertTypeRecursive(T);
- if (ResultType == llvm::Type::getInt1Ty(getLLVMContext()))
+ if (ResultType->isInteger(1))
return llvm::IntegerType::get(getLLVMContext(),
(unsigned)Context.getTypeSize(T));
+ // FIXME: Should assert that the llvm type and AST type has the same size.
return ResultType;
}
@@ -102,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) {
const llvm::Type *R = ConvertType(T);
// If this is a non-bool type, don't map it.
- if (R != llvm::Type::getInt1Ty(getLLVMContext()))
+ if (!R->isInteger(1))
return R;
// Otherwise, return an integer of the target-specified size.
@@ -384,11 +381,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
QualType ETy = cast<MemberPointerType>(Ty).getPointeeType();
const llvm::Type *PtrDiffTy =
ConvertTypeRecursive(Context.getPointerDiffType());
- if (ETy->isFunctionType()) {
+ if (ETy->isFunctionType())
return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy,
NULL);
- } else
- return PtrDiffTy;
+ return PtrDiffTy;
}
case Type::TemplateSpecialization:
@@ -436,10 +432,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
// Okay, this is a definition of a type. Compile the implementation now.
- if (TD->isEnum()) {
- // Don't bother storing enums in TagDeclTypes.
+ if (TD->isEnum()) // Don't bother storing enums in TagDeclTypes.
return ConvertTypeRecursive(cast<EnumDecl>(TD)->getIntegerType());
- }
// This decl could well be recursive. In this case, insert an opaque
// definition of this type, which the recursive uses will get. We will then
@@ -450,15 +444,13 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext());
TagDeclTypes.insert(std::make_pair(Key, ResultHolder));
- const llvm::Type *ResultType;
const RecordDecl *RD = cast<const RecordDecl>(TD);
// Layout fields.
- CGRecordLayout *Layout =
- CGRecordLayoutBuilder::ComputeLayout(*this, RD);
+ CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD);
CGRecordLayouts[Key] = Layout;
- ResultType = Layout->getLLVMType();
+ const llvm::Type *ResultType = Layout->getLLVMType();
// Refine our Opaque type to ResultType. This can invalidate ResultType, so
// make sure to read the result out of the holder.
@@ -500,8 +492,7 @@ void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
/// getCGRecordLayout - Return record layout info for the given llvm::Type.
const CGRecordLayout &
CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
- const Type *Key =
- Context.getTagDeclType(TD).getTypePtr();
+ const Type *Key = Context.getTagDeclType(TD).getTypePtr();
llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I
= CGRecordLayouts.find(Key);
assert (I != CGRecordLayouts.end()
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 2ff602f900fa..7e342526e84b 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -85,7 +85,7 @@ class CodeGenTypes {
const TargetInfo &Target;
llvm::Module& TheModule;
const llvm::TargetData& TheTargetData;
- mutable const ABIInfo* TheABIInfo;
+ const ABIInfo& TheABIInfo;
llvm::SmallVector<std::pair<QualType,
llvm::OpaqueType *>, 8> PointersToResolve;
@@ -140,13 +140,14 @@ private:
/// interface to convert type T into a llvm::Type.
const llvm::Type *ConvertNewType(QualType T);
public:
- CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD);
+ CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
+ const ABIInfo &Info);
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
- const ABIInfo &getABIInfo() const;
+ const ABIInfo &getABIInfo() const { return TheABIInfo; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
/// ConvertType - Convert type T into a llvm::Type.
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 10fd1f57f6be..d873cfec1bd7 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -199,10 +199,13 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
return;
}
- // <mangled-name> ::= _Z <encoding>
+ // <mangled-name> ::= _Z [L] <encoding>
// ::= <data name>
// ::= <special-name>
Out << Prefix;
+ if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior
+ Out << 'L';
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
mangleFunctionEncoding(FD);
else
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
new file mode 100644
index 000000000000..e5fd47ec2d16
--- /dev/null
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -0,0 +1,1904 @@
+//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TargetInfo.h"
+#include "ABIInfo.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/Type.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace CodeGen;
+
+ABIInfo::~ABIInfo() {}
+
+void ABIArgInfo::dump() const {
+ llvm::raw_ostream &OS = llvm::errs();
+ OS << "(ABIArgInfo Kind=";
+ switch (TheKind) {
+ case Direct:
+ OS << "Direct";
+ break;
+ case Extend:
+ OS << "Extend";
+ break;
+ case Ignore:
+ OS << "Ignore";
+ break;
+ case Coerce:
+ OS << "Coerce Type=";
+ getCoerceToType()->print(OS);
+ break;
+ case Indirect:
+ OS << "Indirect Align=" << getIndirectAlign();
+ break;
+ case Expand:
+ OS << "Expand";
+ break;
+ }
+ OS << ")\n";
+}
+
+TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; }
+
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
+
+/// isEmptyField - Return true iff a the field is "empty", that is it
+/// is an unnamed bit-field or an (array of) empty record(s).
+static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
+ bool AllowArrays) {
+ if (FD->isUnnamedBitfield())
+ return true;
+
+ QualType FT = FD->getType();
+
+ // Constant arrays of empty records count as empty, strip them off.
+ if (AllowArrays)
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
+ FT = AT->getElementType();
+
+ return isEmptyRecord(Context, FT, AllowArrays);
+}
+
+/// isEmptyRecord - Return true iff a structure contains only empty
+/// fields. Note that a structure with a flexible array member is not
+/// considered empty.
+static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return 0;
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i)
+ if (!isEmptyField(Context, *i, AllowArrays))
+ return false;
+ return true;
+}
+
+/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either
+/// a non-trivial destructor or a non-trivial copy constructor.
+static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
+ if (!RD)
+ return false;
+
+ return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+}
+
+/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
+/// a record type with either a non-trivial destructor or a non-trivial copy
+/// constructor.
+static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) {
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ return hasNonTrivialDestructorOrCopyConstructor(RT);
+}
+
+/// isSingleElementStruct - Determine if a structure is a "single
+/// element struct", i.e. it has exactly one non-empty field or
+/// exactly one field which is itself a single element
+/// struct. Structures with flexible array members are never
+/// considered single element structs.
+///
+/// \return The field declaration for the single non-empty field, if
+/// it exists.
+static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
+ const RecordType *RT = T->getAsStructureType();
+ if (!RT)
+ return 0;
+
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return 0;
+
+ const Type *Found = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+ QualType FT = FD->getType();
+
+ // Ignore empty fields.
+ if (isEmptyField(Context, FD, true))
+ continue;
+
+ // If we already found an element then this isn't a single-element
+ // struct.
+ if (Found)
+ return 0;
+
+ // Treat single element arrays as the element.
+ while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
+ if (AT->getSize().getZExtValue() != 1)
+ break;
+ FT = AT->getElementType();
+ }
+
+ if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
+ Found = FT.getTypePtr();
+ } else {
+ Found = isSingleElementStruct(FT, Context);
+ if (!Found)
+ return 0;
+ }
+ }
+
+ return Found;
+}
+
+static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+ if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() &&
+ !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
+ !Ty->isBlockPointerType())
+ return false;
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ return Size == 32 || Size == 64;
+}
+
+/// canExpandIndirectArgument - Test whether an argument type which is to be
+/// passed indirectly (on the stack) would have the equivalent layout if it was
+/// expanded into separate arguments. If so, we prefer to do the latter to avoid
+/// inhibiting optimizations.
+///
+// FIXME: This predicate is missing many cases, currently it just follows
+// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We
+// should probably make this smarter, or better yet make the LLVM backend
+// capable of handling it.
+static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
+ // We can only expand structure types.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ // We can only expand (C) structures.
+ //
+ // FIXME: This needs to be generalized to handle classes as well.
+ const RecordDecl *RD = RT->getDecl();
+ if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
+ return false;
+
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ if (!is32Or64BitBasicType(FD->getType(), Context))
+ return false;
+
+ // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
+ // how to expand them yet, and the predicate for telling if a bitfield still
+ // counts as "basic" is more complicated than what we were doing previously.
+ if (FD->isBitField())
+ return false;
+ }
+
+ return true;
+}
+
+static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) {
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ if (FD->getType()->isVectorType() &&
+ Context.getTypeSize(FD->getType()) >= 128)
+ return true;
+
+ if (const RecordType* RT = FD->getType()->getAs<RecordType>())
+ if (typeContainsSSEVector(RT->getDecl(), Context))
+ return true;
+ }
+
+ return false;
+}
+
+namespace {
+/// DefaultABIInfo - The default implementation for ABI specific
+/// details. This implementation provides information which results in
+/// self-consistent and sensible LLVM IR generation, but does not
+/// conform to any particular ABI.
+class DefaultABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+};
+
+llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+/// X86_32ABIInfo - The X86-32 ABI information.
+class X86_32ABIInfo : public ABIInfo {
+ ASTContext &Context;
+ bool IsDarwinVectorABI;
+ bool IsSmallStructInRegABI;
+
+ static bool isRegisterSize(unsigned Size) {
+ return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
+ }
+
+ static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
+
+ static unsigned getIndirectArgumentAlignment(QualType Ty,
+ ASTContext &Context);
+
+public:
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ X86_32ABIInfo(ASTContext &Context, bool d, bool p)
+ : ABIInfo(), Context(Context), IsDarwinVectorABI(d),
+ IsSmallStructInRegABI(p) {}
+};
+
+class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p)
+ :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {};
+};
+
+}
+
+/// shouldReturnTypeInRegister - Determine if the given type should be
+/// passed in a register (for the Darwin ABI).
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
+ ASTContext &Context) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Type must be register sized.
+ if (!isRegisterSize(Size))
+ return false;
+
+ if (Ty->isVectorType()) {
+ // 64- and 128- bit vectors inside structures are not returned in
+ // registers.
+ if (Size == 64 || Size == 128)
+ return false;
+
+ return true;
+ }
+
+ // If this is a builtin, pointer, enum, or complex type, it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() ||
+ Ty->isAnyComplexType() || Ty->isEnumeralType() ||
+ Ty->isBlockPointerType())
+ return true;
+
+ // Arrays are treated like records.
+ if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
+ return shouldReturnTypeInRegister(AT->getElementType(), Context);
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Structure types are passed in register if all fields would be
+ // passed in a register.
+ for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
+ e = RT->getDecl()->field_end(); i != e; ++i) {
+ const FieldDecl *FD = *i;
+
+ // Empty fields are ignored.
+ if (isEmptyField(Context, FD, true))
+ continue;
+
+ // Check fields recursively.
+ if (!shouldReturnTypeInRegister(FD->getType(), Context))
+ return false;
+ }
+
+ return true;
+}
+
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (const VectorType *VT = RetTy->getAs<VectorType>()) {
+ // On Darwin, some vectors are returned in registers.
+ if (IsDarwinVectorABI) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+
+ // 128-bit vectors are a special case; they are returned in
+ // registers and we need to make sure to pick a type the LLVM
+ // backend will like.
+ if (Size == 128)
+ return ABIArgInfo::getCoerce(llvm::VectorType::get(
+ llvm::Type::getInt64Ty(VMContext), 2));
+
+ // Always return in register if it fits in a general purpose
+ // register, or if it is 64 bits and has a single element.
+ if ((Size == 8 || Size == 16 || Size == 32) ||
+ (Size == 64 && VT->getNumElements() == 1))
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ return ABIArgInfo::getDirect();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ if (const RecordType *RT = RetTy->getAsStructureType()) {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+
+ // Structures with flexible arrays are always indirect.
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // If specified, structs and unions are always indirect.
+ if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
+ return ABIArgInfo::getIndirect(0);
+
+ // Classify "single element" structs as their element type.
+ if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) {
+ if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) {
+ if (BT->isIntegerType()) {
+ // We need to use the size of the structure, padding
+ // bit-fields can adjust that to be larger than the single
+ // element type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(
+ llvm::IntegerType::get(VMContext, (unsigned) Size));
+ } else if (BT->getKind() == BuiltinType::Float) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext));
+ } else if (BT->getKind() == BuiltinType::Double) {
+ assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
+ "Unexpect single element structure size!");
+ return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext));
+ }
+ } else if (SeltTy->isPointerType()) {
+ // FIXME: It would be really nice if this could come out as the proper
+ // pointer type.
+ const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return ABIArgInfo::getCoerce(PtrTy);
+ } else if (SeltTy->isVectorType()) {
+ // 64- and 128-bit vectors are never returned in a
+ // register when inside a structure.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size == 64 || Size == 128)
+ return ABIArgInfo::getIndirect(0);
+
+ return classifyReturnType(QualType(SeltTy, 0), Context, VMContext);
+ }
+ }
+
+ // Small structures which are register sized are generally returned
+ // in a register.
+ if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) {
+ uint64_t Size = Context.getTypeSize(RetTy);
+ return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
+ ASTContext &Context) {
+ unsigned Align = Context.getTypeAlign(Ty);
+ if (Align < 128) return 0;
+ if (const RecordType* RT = Ty->getAs<RecordType>())
+ if (typeContainsSSEVector(RT->getDecl(), Context))
+ return 16;
+ return 0;
+}
+
+ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ // FIXME: Set alignment on indirect arguments.
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ // Structures with flexible arrays are always indirect.
+ if (const RecordType *RT = Ty->getAsStructureType())
+ if (RT->getDecl()->hasFlexibleArrayMember())
+ return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
+ Context));
+
+ // Ignore empty structs.
+ if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
+ return ABIArgInfo::getIgnore();
+
+ // Expand small (<= 128-bit) record types when we know that the stack layout
+ // of those arguments will match the struct. This is important because the
+ // LLVM backend isn't smart enough to remove byval, which inhibits many
+ // optimizations.
+ if (Context.getTypeSize(Ty) <= 4*32 &&
+ canExpandIndirectArgument(Ty, Context))
+ return ABIArgInfo::getExpand();
+
+ return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
+ } else {
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
+ "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+namespace {
+/// X86_64ABIInfo - The X86_64 ABI information.
+class X86_64ABIInfo : public ABIInfo {
+ enum Class {
+ Integer = 0,
+ SSE,
+ SSEUp,
+ X87,
+ X87Up,
+ ComplexX87,
+ NoClass,
+ Memory
+ };
+
+ /// merge - Implement the X86_64 ABI merging algorithm.
+ ///
+ /// Merge an accumulating classification \arg Accum with a field
+ /// classification \arg Field.
+ ///
+ /// \param Accum - The accumulating classification. This should
+ /// always be either NoClass or the result of a previous merge
+ /// call. In addition, this should never be Memory (the caller
+ /// should just return Memory for the aggregate).
+ Class merge(Class Accum, Class Field) const;
+
+ /// classify - Determine the x86_64 register classes in which the
+ /// given type T should be passed.
+ ///
+ /// \param Lo - The classification for the parts of the type
+ /// residing in the low word of the containing object.
+ ///
+ /// \param Hi - The classification for the parts of the type
+ /// residing in the high word of the containing object.
+ ///
+ /// \param OffsetBase - The bit offset of this type in the
+ /// containing object. Some parameters are classified different
+ /// depending on whether they straddle an eightbyte boundary.
+ ///
+ /// If a word is unused its result will be NoClass; if a type should
+ /// be passed in Memory then at least the classification of \arg Lo
+ /// will be Memory.
+ ///
+ /// The \arg Lo class will be NoClass iff the argument is ignored.
+ ///
+ /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
+ /// also be ComplexX87.
+ void classify(QualType T, ASTContext &Context, uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const;
+
+ /// getCoerceResult - Given a source type \arg Ty and an LLVM type
+ /// to coerce to, chose the best way to pass Ty in the same place
+ /// that \arg CoerceTo would be passed, but while keeping the
+ /// emitted code as simple as possible.
+ ///
+ /// FIXME: Note, this should be cleaned up to just take an enumeration of all
+ /// the ways we might want to pass things, instead of constructing an LLVM
+ /// type. This makes this code more explicit, and it makes it clearer that we
+ /// are also doing this for correctness in the case of passing scalar types.
+ ABIArgInfo getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const;
+
+ /// getIndirectResult - Give a source type \arg Ty, return a suitable result
+ /// such that the argument will be passed in memory.
+ ABIArgInfo getIndirectResult(QualType Ty,
+ ASTContext &Context) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext,
+ unsigned &neededInt,
+ unsigned &neededSSE) const;
+
+public:
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {};
+};
+
+}
+
+X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum,
+ Class Field) const {
+ // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
+ // classified recursively so that always two fields are
+ // considered. The resulting class is calculated according to
+ // the classes of the fields in the eightbyte:
+ //
+ // (a) If both classes are equal, this is the resulting class.
+ //
+ // (b) If one of the classes is NO_CLASS, the resulting class is
+ // the other class.
+ //
+ // (c) If one of the classes is MEMORY, the result is the MEMORY
+ // class.
+ //
+ // (d) If one of the classes is INTEGER, the result is the
+ // INTEGER.
+ //
+ // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ // MEMORY is used as class.
+ //
+ // (f) Otherwise class SSE is used.
+
+ // Accum should never be memory (we should have returned) or
+ // ComplexX87 (because this cannot be passed in a structure).
+ assert((Accum != Memory && Accum != ComplexX87) &&
+ "Invalid accumulated classification during merge.");
+ if (Accum == Field || Field == NoClass)
+ return Accum;
+ else if (Field == Memory)
+ return Memory;
+ else if (Accum == NoClass)
+ return Field;
+ else if (Accum == Integer || Field == Integer)
+ return Integer;
+ else if (Field == X87 || Field == X87Up || Field == ComplexX87 ||
+ Accum == X87 || Accum == X87Up)
+ return Memory;
+ else
+ return SSE;
+}
+
+void X86_64ABIInfo::classify(QualType Ty,
+ ASTContext &Context,
+ uint64_t OffsetBase,
+ Class &Lo, Class &Hi) const {
+ // FIXME: This code can be simplified by introducing a simple value class for
+ // Class pairs with appropriate constructor methods for the various
+ // situations.
+
+ // FIXME: Some of the split computations are wrong; unaligned vectors
+ // shouldn't be passed in registers for example, so there is no chance they
+ // can straddle an eightbyte. Verify & simplify.
+
+ Lo = Hi = NoClass;
+
+ Class &Current = OffsetBase < 64 ? Lo : Hi;
+ Current = Memory;
+
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ BuiltinType::Kind k = BT->getKind();
+
+ if (k == BuiltinType::Void) {
+ Current = NoClass;
+ } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
+ Lo = Integer;
+ Hi = Integer;
+ } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
+ Current = Integer;
+ } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
+ Current = SSE;
+ } else if (k == BuiltinType::LongDouble) {
+ Lo = X87;
+ Hi = X87Up;
+ }
+ // FIXME: _Decimal32 and _Decimal64 are SSE.
+ // FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
+ } else if (const EnumType *ET = Ty->getAs<EnumType>()) {
+ // Classify the underlying integer type.
+ classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
+ } else if (Ty->hasPointerRepresentation()) {
+ Current = Integer;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ uint64_t Size = Context.getTypeSize(VT);
+ if (Size == 32) {
+ // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x
+ // float> as integer.
+ Current = Integer;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Size - 1) / 64;
+ if (EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (Size == 64) {
+ // gcc passes <1 x double> in memory. :(
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double))
+ return;
+
+ // gcc passes <1 x long long> as INTEGER.
+ if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong))
+ Current = Integer;
+ else
+ Current = SSE;
+
+ // If this type crosses an eightbyte boundary, it should be
+ // split.
+ if (OffsetBase && OffsetBase != 64)
+ Hi = Lo;
+ } else if (Size == 128) {
+ Lo = SSE;
+ Hi = SSEUp;
+ }
+ } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ QualType ET = Context.getCanonicalType(CT->getElementType());
+
+ uint64_t Size = Context.getTypeSize(Ty);
+ if (ET->isIntegralType()) {
+ if (Size <= 64)
+ Current = Integer;
+ else if (Size <= 128)
+ Lo = Hi = Integer;
+ } else if (ET == Context.FloatTy)
+ Current = SSE;
+ else if (ET == Context.DoubleTy)
+ Lo = Hi = SSE;
+ else if (ET == Context.LongDoubleTy)
+ Current = ComplexX87;
+
+ // If this complex type crosses an eightbyte boundary then it
+ // should be split.
+ uint64_t EB_Real = (OffsetBase) / 64;
+ uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64;
+ if (Hi == NoClass && EB_Real != EB_Imag)
+ Hi = Lo;
+ } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
+ // Arrays are treated like structures.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Only need to check alignment of array base.
+ if (OffsetBase % Context.getTypeAlign(AT->getElementType()))
+ return;
+
+ // Otherwise implement simplified merge. We could be smarter about
+ // this, but it isn't worth it and would be harder to verify.
+ Current = NoClass;
+ uint64_t EltSize = Context.getTypeSize(AT->getElementType());
+ uint64_t ArraySize = AT->getSize().getZExtValue();
+ for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
+ Class FieldLo, FieldHi;
+ classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // Do post merger cleanup (see below). Only case we worry about is Memory.
+ if (Hi == Memory)
+ Lo = Memory;
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
+ } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
+ // than two eightbytes, ..., it has class MEMORY.
+ if (Size > 128)
+ return;
+
+ // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
+ // copy constructor or a non-trivial destructor, it is passed by invisible
+ // reference.
+ if (hasNonTrivialDestructorOrCopyConstructor(RT))
+ return;
+
+ const RecordDecl *RD = RT->getDecl();
+
+ // Assume variable sized types are passed in memory.
+ if (RD->hasFlexibleArrayMember())
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // 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;
+ }
+
+ // If this record has no fields but isn't empty, classify as INTEGER.
+ if (RD->field_empty() && Size)
+ Current = Integer;
+ }
+
+ // 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) {
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ bool BitField = i->isBitField();
+
+ // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
+ // fields, it has class MEMORY.
+ //
+ // Note, skip this test for bit-fields, see below.
+ if (!BitField && Offset % Context.getTypeAlign(i->getType())) {
+ Lo = Memory;
+ return;
+ }
+
+ // 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;
+
+ // Bit-fields require special handling, they do not force the
+ // structure to be passed in memory even if unaligned, and
+ // therefore they can straddle an eightbyte.
+ if (BitField) {
+ // Ignore padding bit-fields.
+ if (i->isUnnamedBitfield())
+ continue;
+
+ uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
+ uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+
+ uint64_t EB_Lo = Offset / 64;
+ uint64_t EB_Hi = (Offset + Size - 1) / 64;
+ FieldLo = FieldHi = NoClass;
+ if (EB_Lo) {
+ assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
+ FieldLo = NoClass;
+ FieldHi = Integer;
+ } else {
+ FieldLo = Integer;
+ FieldHi = EB_Hi ? Integer : NoClass;
+ }
+ } else
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+
+ // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
+ //
+ // (a) If one of the classes is MEMORY, the whole argument is
+ // passed in memory.
+ //
+ // (b) If SSEUP is not preceeded by SSE, it is converted to SSE.
+
+ // The first of these conditions is guaranteed by how we implement
+ // the merge (just bail).
+ //
+ // The second condition occurs in the case of unions; for example
+ // union { _Complex double; unsigned; }.
+ if (Hi == Memory)
+ Lo = Memory;
+ if (Hi == SSEUp && Lo != SSE)
+ Hi = SSE;
+ }
+}
+
+ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
+ const llvm::Type *CoerceTo,
+ ASTContext &Context) const {
+ if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
+ // Integer and pointer types will end up in a general purpose
+ // register.
+ if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) {
+ // FIXME: It would probably be better to make CGFunctionInfo only map using
+ // canonical types than to canonize here.
+ QualType CTy = Context.getCanonicalType(Ty);
+
+ // Float and double end up in a single SSE reg.
+ if (CTy == Context.FloatTy || CTy == Context.DoubleTy)
+ return ABIArgInfo::getDirect();
+
+ }
+
+ return ABIArgInfo::getCoerce(CoerceTo);
+}
+
+ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
+ ASTContext &Context) const {
+ // If this is a scalar LLVM value then assume LLVM will pass it in the right
+ // place naturally.
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
+
+ // FIXME: Set alignment correctly.
+ return ABIArgInfo::getIndirect(0, ByVal);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
+ // classification algorithm.
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(RetTy, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
+ // hidden argument.
+ case Memory:
+ return getIndirectResult(RetTy, Context);
+
+ // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
+ // available register of the sequence %rax, %rdx is used.
+ case Integer:
+ ResType = llvm::Type::getInt64Ty(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
+ // available SSE register of the sequence %xmm0, %xmm1 is used.
+ case SSE:
+ ResType = llvm::Type::getDoubleTy(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
+ // returned on the X87 stack in %st0 as 80-bit x87 number.
+ case X87:
+ ResType = llvm::Type::getX86_FP80Ty(VMContext); break;
+
+ // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
+ // part of the value is returned in %st0 and the imaginary part in
+ // %st1.
+ case ComplexX87:
+ assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
+ ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
+ llvm::Type::getX86_FP80Ty(VMContext),
+ NULL);
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously and X87 should
+ // never occur as a hi class.
+ case Memory:
+ case X87:
+ assert(0 && "Invalid classification for hi word.");
+
+ case ComplexX87: // Previously handled.
+ case NoClass: break;
+
+ case Integer:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
+ break;
+ case SSE:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
+ // is passed in the upper half of the last used SSE register.
+ //
+ // SSEUP should always be preceeded by SSE, just widen.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
+ break;
+
+ // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
+ // returned together with the previous X87 value in %st0.
+ case X87Up:
+ // If X87Up is preceeded by X87, we don't need to do
+ // anything. However, in some cases with unions it may not be
+ // preceeded by X87. In such situations we follow gcc and pass the
+ // extra bits in an SSE reg.
+ if (Lo != X87)
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ break;
+ }
+
+ return getCoerceResult(RetTy, ResType, Context);
+}
+
+ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
+ llvm::LLVMContext &VMContext,
+ unsigned &neededInt,
+ unsigned &neededSSE) const {
+ X86_64ABIInfo::Class Lo, Hi;
+ classify(Ty, Context, 0, Lo, Hi);
+
+ // Check some invariants.
+ // FIXME: Enforce these by construction.
+ assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
+ assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
+ assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
+
+ neededInt = 0;
+ neededSSE = 0;
+ const llvm::Type *ResType = 0;
+ switch (Lo) {
+ case NoClass:
+ return ABIArgInfo::getIgnore();
+
+ // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
+ // on the stack.
+ case Memory:
+
+ // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
+ // COMPLEX_X87, it is passed in memory.
+ case X87:
+ case ComplexX87:
+ return getIndirectResult(Ty, Context);
+
+ case SSEUp:
+ case X87Up:
+ assert(0 && "Invalid classification for lo word.");
+
+ // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
+ // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
+ // and %r9 is used.
+ case Integer:
+ ++neededInt;
+ ResType = llvm::Type::getInt64Ty(VMContext);
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
+ // available SSE register is used, the registers are taken in the
+ // order from %xmm0 to %xmm7.
+ case SSE:
+ ++neededSSE;
+ ResType = llvm::Type::getDoubleTy(VMContext);
+ break;
+ }
+
+ switch (Hi) {
+ // Memory was handled previously, ComplexX87 and X87 should
+ // never occur as hi classes, and X87Up must be preceed by X87,
+ // which is passed in memory.
+ case Memory:
+ case X87:
+ case ComplexX87:
+ assert(0 && "Invalid classification for hi word.");
+ break;
+
+ case NoClass: break;
+ case Integer:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getInt64Ty(VMContext), NULL);
+ ++neededInt;
+ break;
+
+ // X87Up generally doesn't occur here (long double is passed in
+ // memory), except in situations involving unions.
+ case X87Up:
+ case SSE:
+ ResType = llvm::StructType::get(VMContext, ResType,
+ llvm::Type::getDoubleTy(VMContext), NULL);
+ ++neededSSE;
+ break;
+
+ // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
+ // eightbyte is passed in the upper half of the last used SSE
+ // register.
+ case SSEUp:
+ assert(Lo == SSE && "Unexpected SSEUp classification.");
+ ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
+ break;
+ }
+
+ return getCoerceResult(Ty, ResType, Context);
+}
+
+void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
+
+ // Keep track of the number of assigned registers.
+ unsigned freeIntRegs = 6, freeSSERegs = 8;
+
+ // If the return value is indirect, then the hidden argument is consuming one
+ // integer register.
+ if (FI.getReturnInfo().isIndirect())
+ --freeIntRegs;
+
+ // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
+ // get assigned (in left-to-right order) for passing as follows...
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ unsigned neededInt, neededSSE;
+ it->info = classifyArgumentType(it->type, Context, VMContext,
+ neededInt, neededSSE);
+
+ // AMD64-ABI 3.2.3p3: If there are no registers available for any
+ // eightbyte of an argument, the whole argument is passed on the
+ // stack. If registers have already been assigned for some
+ // eightbytes of such an argument, the assignments get reverted.
+ if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) {
+ freeIntRegs -= neededInt;
+ freeSSERegs -= neededSSE;
+ } else {
+ it->info = getIndirectResult(it->type, Context);
+ }
+ }
+}
+
+static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
+ QualType Ty,
+ CodeGenFunction &CGF) {
+ llvm::Value *overflow_arg_area_p =
+ CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p");
+ llvm::Value *overflow_arg_area =
+ CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
+
+ // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
+ // byte boundary if alignment needed by type exceeds 8 byte boundary.
+ uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
+ if (Align > 8) {
+ // Note that we follow the ABI & gcc here, even though the type
+ // could in theory have an alignment greater than 16. This case
+ // shouldn't ever matter in practice.
+
+ // overflow_arg_area = (overflow_arg_area + 15) & ~15;
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
+ llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()));
+ llvm::Value *Mask = llvm::ConstantInt::get(
+ llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL);
+ overflow_arg_area =
+ CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
+ overflow_arg_area->getType(),
+ "overflow_arg_area.align");
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
+ const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *Res =
+ CGF.Builder.CreateBitCast(overflow_arg_area,
+ llvm::PointerType::getUnqual(LTy));
+
+ // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to:
+ // l->overflow_arg_area + sizeof(type).
+ // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to
+ // an 8 byte boundary.
+
+ uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
+ llvm::Value *Offset =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
+ (SizeInBytes + 7) & ~7);
+ overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
+ "overflow_arg_area.next");
+ CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
+
+ // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
+ return Res;
+}
+
+llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ llvm::LLVMContext &VMContext = CGF.getLLVMContext();
+ const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext);
+ const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
+
+ // Assume that va_list type is correct; should be pointer to LLVM type:
+ // struct {
+ // i32 gp_offset;
+ // i32 fp_offset;
+ // i8* overflow_arg_area;
+ // i8* reg_save_area;
+ // };
+ unsigned neededInt, neededSSE;
+ ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
+ neededInt, neededSSE);
+
+ // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
+ // in the registers. If not go to step 7.
+ if (!neededInt && !neededSSE)
+ return EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of
+ // general purpose registers needed to pass type and num_fp to hold
+ // the number of floating point registers needed.
+
+ // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into
+ // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
+ // l->fp_offset > 304 - num_fp * 16 go to step 7.
+ //
+ // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
+ // register save space).
+
+ llvm::Value *InRegs = 0;
+ llvm::Value *gp_offset_p = 0, *gp_offset = 0;
+ llvm::Value *fp_offset_p = 0, *fp_offset = 0;
+ if (neededInt) {
+ gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
+ gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
+ InRegs =
+ CGF.Builder.CreateICmpULE(gp_offset,
+ llvm::ConstantInt::get(i32Ty,
+ 48 - neededInt * 8),
+ "fits_in_gp");
+ }
+
+ if (neededSSE) {
+ fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p");
+ fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
+ llvm::Value *FitsInFP =
+ CGF.Builder.CreateICmpULE(fp_offset,
+ llvm::ConstantInt::get(i32Ty,
+ 176 - neededSSE * 16),
+ "fits_in_fp");
+ InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
+ }
+
+ llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+ llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+ CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
+
+ // Emit code to load the value if it was passed in registers.
+
+ CGF.EmitBlock(InRegBlock);
+
+ // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with
+ // an offset of l->gp_offset and/or l->fp_offset. This may require
+ // copying to a temporary location in case the parameter is passed
+ // in different register classes or requires an alignment greater
+ // than 8 for general purpose registers and 16 for XMM registers.
+ //
+ // FIXME: This really results in shameful code when we end up needing to
+ // collect arguments from different places; often what should result in a
+ // simple assembling of a structure from scattered addresses has many more
+ // loads than necessary. Can we clean this up?
+ const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *RegAddr =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
+ "reg_save_area");
+ if (neededInt && neededSSE) {
+ // FIXME: Cleanup.
+ assert(AI.isCoerce() && "Unexpected ABI info for mixed regs");
+ const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
+ llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
+ assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
+ const llvm::Type *TyLo = ST->getElementType(0);
+ const llvm::Type *TyHi = ST->getElementType(1);
+ assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
+ "Unexpected ABI info for mixed regs");
+ const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
+ const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
+ llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
+ llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
+ llvm::Value *V =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
+ } else if (neededInt) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ if (neededSSE == 1) {
+ RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ RegAddr = CGF.Builder.CreateBitCast(RegAddr,
+ llvm::PointerType::getUnqual(LTy));
+ } else {
+ assert(neededSSE == 2 && "Invalid number of needed registers!");
+ // SSE registers are spaced 16 bytes apart in the register save
+ // area, we need to collect the two eightbytes together.
+ llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
+ llvm::Value *RegAddrHi =
+ CGF.Builder.CreateGEP(RegAddrLo,
+ llvm::ConstantInt::get(i32Ty, 16));
+ const llvm::Type *DblPtrTy =
+ llvm::PointerType::getUnqual(DoubleTy);
+ const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy,
+ DoubleTy, NULL);
+ llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
+ V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi,
+ DblPtrTy));
+ CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
+ RegAddr = CGF.Builder.CreateBitCast(Tmp,
+ llvm::PointerType::getUnqual(LTy));
+ }
+ }
+
+ // AMD64-ABI 3.5.7p5: Step 5. Set:
+ // l->gp_offset = l->gp_offset + num_gp * 8
+ // l->fp_offset = l->fp_offset + num_fp * 16.
+ if (neededInt) {
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset),
+ gp_offset_p);
+ }
+ if (neededSSE) {
+ llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16);
+ CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
+ fp_offset_p);
+ }
+ CGF.EmitBranch(ContBlock);
+
+ // Emit code to load the value if it was passed in memory.
+
+ CGF.EmitBlock(InMemBlock);
+ llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF);
+
+ // Return the appropriate result.
+
+ CGF.EmitBlock(ContBlock);
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(),
+ "vaarg.addr");
+ ResAddr->reserveOperandSpace(2);
+ ResAddr->addIncoming(RegAddr, InRegBlock);
+ ResAddr->addIncoming(MemAddr, InMemBlock);
+
+ return ResAddr;
+}
+
+// PIC16 ABI Implementation
+
+namespace {
+
+class PIC16ABIInfo : public ABIInfo {
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class PIC16TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {};
+};
+
+}
+
+ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else {
+ return ABIArgInfo::getDirect();
+ }
+}
+
+ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ return ABIArgInfo::getDirect();
+}
+
+llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
+// ARM ABI Implementation
+
+namespace {
+
+class ARMABIInfo : public ABIInfo {
+public:
+ enum ABIKind {
+ APCS = 0,
+ AAPCS = 1,
+ AAPCS_VFP
+ };
+
+private:
+ ABIKind Kind;
+
+public:
+ ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {}
+
+private:
+ ABIKind getABIKind() const { return Kind; }
+
+ ABIArgInfo classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMCOntext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K)
+ :TargetCodeGenInfo(new ARMABIInfo(K)) {};
+};
+
+}
+
+void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
+ VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ // ARM always overrides the calling convention.
+ switch (getABIKind()) {
+ case APCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
+ break;
+
+ case AAPCS:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
+ break;
+
+ case AAPCS_VFP:
+ FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
+ break;
+ }
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (!CodeGenFunction::hasAggregateLLVMType(Ty))
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Ignore empty records.
+ if (isEmptyRecord(Context, Ty, true))
+ return ABIArgInfo::getIgnore();
+
+ // FIXME: This is kind of nasty... but there isn't much choice because the ARM
+ // backend doesn't support byval.
+ // FIXME: This doesn't handle alignment > 64 bits.
+ const llvm::Type* ElemTy;
+ unsigned SizeRegs;
+ if (Context.getTypeAlign(Ty) > 32) {
+ ElemTy = llvm::Type::getInt64Ty(VMContext);
+ SizeRegs = (Context.getTypeSize(Ty) + 63) / 64;
+ } else {
+ ElemTy = llvm::Type::getInt32Ty(VMContext);
+ SizeRegs = (Context.getTypeSize(Ty) + 31) / 32;
+ }
+ std::vector<const llvm::Type*> LLVMFields;
+ LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
+ const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true);
+ return ABIArgInfo::getCoerce(STy);
+}
+
+static bool isIntegerLikeType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) {
+ // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
+ // is called integer-like if its size is less than or equal to one word, and
+ // the offset of each of its addressable sub-fields is zero.
+
+ uint64_t Size = Context.getTypeSize(Ty);
+
+ // Check that the type fits in a word.
+ if (Size > 32)
+ return false;
+
+ // FIXME: Handle vector types!
+ if (Ty->isVectorType())
+ return false;
+
+ // Float types are never treated as "integer like".
+ if (Ty->isRealFloatingType())
+ return false;
+
+ // If this is a builtin or pointer type then it is ok.
+ if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
+ return true;
+
+ // Complex types "should" be ok by the definition above, but they are not.
+ if (Ty->isAnyComplexType())
+ return false;
+
+ // Single element and zero sized arrays should be allowed, by the definition
+ // above, but they are not.
+
+ // Otherwise, it must be a record type.
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (!RT) return false;
+
+ // Ignore records with flexible arrays.
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ // Check that all sub-fields are at offset 0, and are themselves "integer
+ // like".
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ bool HadField = false;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
+ i != e; ++i, ++idx) {
+ const FieldDecl *FD = *i;
+
+ // Check if this field is at offset 0.
+ uint64_t Offset = Layout.getFieldOffset(idx);
+ if (Offset != 0) {
+ // Allow padding bit-fields, but only if they are all at the end of the
+ // structure (despite the wording above, this matches gcc).
+ if (FD->isBitField() &&
+ !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ for (; i != e; ++i)
+ if (!i->isBitField() ||
+ i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
+ return false;
+
+ // All remaining fields are padding, allow this.
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!isIntegerLikeType(FD->getType(), Context, VMContext))
+ return false;
+
+ // Only allow at most one field in a structure. Again this doesn't match the
+ // wording above, but follows gcc.
+ if (!RD->isUnion()) {
+ if (HadField)
+ return false;
+
+ HadField = true;
+ }
+ }
+
+ return true;
+}
+
+ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+
+ // Are we following APCS?
+ if (getABIKind() == APCS) {
+ if (isEmptyRecord(Context, RetTy, false))
+ return ABIArgInfo::getIgnore();
+
+ // Integer like structures are returned in r0.
+ if (isIntegerLikeType(RetTy, Context, VMContext)) {
+ // Return in the smallest viable integer type.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ // Otherwise return in memory.
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Otherwise this is an AAPCS variant.
+
+ if (isEmptyRecord(Context, RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ // Aggregates <= 4 bytes are returned in r0; other aggregates
+ // are returned indirectly.
+ uint64_t Size = Context.getTypeSize(RetTy);
+ if (Size <= 32) {
+ // Return in the smallest viable integer type.
+ if (Size <= 8)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
+ if (Size <= 16)
+ return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
+ return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+}
+
+llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Need to handle alignment
+ const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
+ "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
+ "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
+ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+// SystemZ ABI Implementation
+
+namespace {
+
+class SystemZABIInfo : public ABIInfo {
+ bool isPromotableIntegerType(QualType Ty) const;
+
+ ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
+ Context, VMContext);
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type, Context, VMContext);
+ }
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {};
+};
+
+}
+
+bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
+ // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // FIXME: Implement
+ return 0;
+}
+
+
+ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (RetTy->isVoidType()) {
+ return ABIArgInfo::getIgnore();
+ } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(RetTy) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty,
+ ASTContext &Context,
+ llvm::LLVMContext &VMContext) const {
+ if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ return ABIArgInfo::getIndirect(0);
+ } else {
+ return (isPromotableIntegerType(Ty) ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+ }
+}
+
+// MSP430 ABI Implementation
+
+namespace {
+
+class MSP430TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const;
+};
+
+}
+
+void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
+ llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) {
+ // Handle 'interrupt' attribute:
+ llvm::Function *F = cast<llvm::Function>(GV);
+
+ // Step 1: Set ISR calling convention.
+ F->setCallingConv(llvm::CallingConv::MSP430_INTR);
+
+ // Step 2: Add attributes goodness.
+ F->addFnAttr(llvm::Attribute::NoInline);
+
+ // Step 3: Emit ISR vector alias.
+ unsigned Num = attr->getNumber() + 0xffe0;
+ new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
+ "vector_" +
+ llvm::LowercaseString(llvm::utohexstr(Num)),
+ GV, &M.getModule());
+ }
+ }
+}
+
+const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
+ if (TheTargetCodeGenInfo)
+ return *TheTargetCodeGenInfo;
+
+ // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't
+ // free it.
+
+ const llvm::Triple &Triple(getContext().Target.getTriple());
+ switch (Triple.getArch()) {
+ default:
+ return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo);
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ // FIXME: We want to know the float calling convention as well.
+ if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(ARMABIInfo::APCS));
+
+ return *(TheTargetCodeGenInfo =
+ new ARMTargetCodeGenInfo(ARMABIInfo::AAPCS));
+
+ case llvm::Triple::pic16:
+ return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo());
+
+ case llvm::Triple::systemz:
+ return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo());
+
+ case llvm::Triple::msp430:
+ return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo());
+
+ case llvm::Triple::x86:
+ switch (Triple.getOS()) {
+ case llvm::Triple::Darwin:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, true, true));
+ case llvm::Triple::Cygwin:
+ case llvm::Triple::MinGW32:
+ case llvm::Triple::MinGW64:
+ case llvm::Triple::AuroraUX:
+ case llvm::Triple::DragonFly:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::OpenBSD:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, false, true));
+
+ default:
+ return *(TheTargetCodeGenInfo =
+ new X86_32TargetCodeGenInfo(Context, false, false));
+ }
+
+ case llvm::Triple::x86_64:
+ return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo());
+ }
+}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
new file mode 100644
index 000000000000..495b22fc284a
--- /dev/null
+++ b/lib/CodeGen/TargetInfo.h
@@ -0,0 +1,50 @@
+//===---- TargetInfo.h - Encapsulate target details -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes wrap the information about a call or function
+// definition used to handle ABI compliancy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_TARGETINFO_H
+#define CLANG_CODEGEN_TARGETINFO_H
+
+namespace llvm {
+ class GlobalValue;
+}
+
+namespace clang {
+ class ABIInfo;
+ class Decl;
+
+ namespace CodeGen {
+ class CodeGenModule;
+ }
+
+ /// TargetCodeGenInfo - This class organizes various target-specific
+ /// codegeneration issues, like target-specific attributes, builtins and so
+ /// on.
+ class TargetCodeGenInfo {
+ ABIInfo *Info;
+ public:
+ // WARNING: Acquires the ownership of ABIInfo.
+ TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { };
+ virtual ~TargetCodeGenInfo();
+
+ /// getABIInfo() - Returns ABI info helper for the target.
+ const ABIInfo& getABIInfo() const { return *Info; }
+
+ /// SetTargetAttributes - Provides a convenient hook to handle extra
+ /// target-specific attributes for the given global.
+ virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const { };
+ };
+}
+
+#endif // CLANG_CODEGEN_TARGETINFO_H
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index cc3febfd5b21..42657d939a9b 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -203,8 +203,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lgcc_s.10.5");
}
} else if (Args.hasArg(options::OPT_shared_libgcc) ||
- // FIXME: -fexceptions -fno-exceptions means no exceptions
- Args.hasArg(options::OPT_fexceptions) ||
+ Args.hasFlag(options::OPT_fexceptions,
+ options::OPT_fno_exceptions) ||
Args.hasArg(options::OPT_fgnu_runtime)) {
// FIXME: This is probably broken on 10.3?
if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
@@ -516,10 +516,6 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args,
return DAL;
}
-bool Darwin::IsMathErrnoDefault() const {
- return false;
-}
-
bool Darwin::IsUnwindTablesDefault() const {
// FIXME: Gross; we should probably have some separate target
// definition, possibly even reusing the one in clang.
@@ -599,10 +595,6 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
return *T;
}
-bool Generic_GCC::IsMathErrnoDefault() const {
- return true;
-}
-
bool Generic_GCC::IsUnwindTablesDefault() const {
// FIXME: Gross; we should probably have some separate target
// definition, possibly even reusing the one in clang.
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index be36344f0cca..374ad8c6bb81 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -38,7 +38,6 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
- virtual bool IsMathErrnoDefault() const;
virtual bool IsUnwindTablesDefault() const;
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
@@ -136,7 +135,6 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
- virtual bool IsMathErrnoDefault() const;
virtual bool IsBlocksDefault() const {
// Blocks default to on for 10.6 (darwin10) and beyond.
return (DarwinVersion[0] > 9);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8f0af21335c1..010953df5e0e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -837,11 +837,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
}
- // -fmath-errno is default.
- if (!Args.hasFlag(options::OPT_fmath_errno,
+ // -fno-math-errno is default.
+ if (Args.hasFlag(options::OPT_fmath_errno,
options::OPT_fno_math_errno,
- getToolChain().IsMathErrnoDefault()))
- CmdArgs.push_back("-fno-math-errno");
+ false))
+ CmdArgs.push_back("-fmath-errno");
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
@@ -935,6 +935,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
+ CmdArgs.push_back("-ftabstop");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -2069,13 +2074,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
Args.AddAllArgs(CmdArgs, options::OPT_undefined);
Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
-
Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
- if (!Args.hasArg(options::OPT_weak__reference__mismatches)) {
- CmdArgs.push_back("-weak_reference_mismatches");
- CmdArgs.push_back("non-weak");
- }
-
Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_y);
Args.AddLastArg(CmdArgs, options::OPT_w);
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 433af03237cd..60d86a62a3a0 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -77,6 +77,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_Asm:
case TY_C: case TY_PP_C:
+ case TY_CL:
case TY_ObjC: case TY_PP_ObjC:
case TY_CXX: case TY_PP_CXX:
case TY_ObjCXX: case TY_PP_ObjCXX:
@@ -133,6 +134,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("mm", TY_ObjCXX)
.Case("cc", TY_CXX)
.Case("CC", TY_CXX)
+ .Case("cl", TY_CL)
.Case("cp", TY_CXX)
.Case("hh", TY_CXXHeader)
.Case("hpp", TY_CXXHeader)
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index f1a666646ff9..52b597e8d273 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -408,6 +408,19 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<function template> " << FTD->getNameAsString() << "\n";
break;
}
+ case Decl::FileScopeAsm: {
+ Out << "<file-scope asm>\n";
+ break;
+ }
+ case Decl::UsingDirective: {
+ Out << "<using directive>\n";
+ break;
+ }
+ case Decl::NamespaceAlias: {
+ NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
+ Out << "<namespace alias> " << NAD->getNameAsString() << "\n";
+ break;
+ }
default:
Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
assert(0 && "decl unhandled");
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index 6824d8f4eb40..ad152d33bcb2 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -363,7 +363,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
if (!mgr.getLiveVariables(D))
return;
- GRExprEngine Eng(mgr);
+ GRExprEngine Eng(mgr, TF.take());
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -373,8 +373,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
- Eng.setTransferFunctionsAndCheckers(tf);
-
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
if (mgr.shouldVisualizeUbigraph()) {
@@ -494,7 +492,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
// Display progress.
C.DisplayFunction(D);
- GRExprEngine Eng(mgr);
+ // FIXME: Make a fake transfer function. The GRTransferFunc interface
+ // eventually will be removed.
+ GRExprEngine Eng(mgr, new GRTransferFuncs());
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -503,10 +503,6 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
-
- // Make a fake transfer function. The GRTransferFunc interface will be
- // removed.
- Eng.setTransferFunctionsAndCheckers(new GRTransferFuncs());
// Register call inliner as the last checker.
RegisterCallInliner(Eng);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 2a6a8a8750d2..19c740d17a83 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -14,10 +14,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -28,6 +30,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
using namespace clang;
@@ -155,7 +158,8 @@ void CompilerInstance::createPreprocessor() {
PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
getPreprocessorOpts(), getHeaderSearchOpts(),
getDependencyOutputOpts(), getTarget(),
- getSourceManager(), getFileManager()));
+ getFrontendOpts(), getSourceManager(),
+ getFileManager()));
}
Preprocessor *
@@ -165,6 +169,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
const HeaderSearchOptions &HSOpts,
const DependencyOutputOptions &DepOpts,
const TargetInfo &Target,
+ const FrontendOptions &FEOpts,
SourceManager &SourceMgr,
FileManager &FileMgr) {
// Create a PTH manager if we are using some form of a token cache.
@@ -186,7 +191,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
PP->setPTHManager(PTHMgr);
}
- InitializePreprocessor(*PP, PPOpts, HSOpts);
+ InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.
if (!DepOpts.OutputFile.empty())
@@ -409,3 +414,87 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
return true;
}
+
+// High-Level Operations
+
+bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
+ assert(hasDiagnostics() && "Diagnostics engine is not initialized!");
+ assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
+ assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
+
+ // FIXME: Take this as an argument, once all the APIs we used have moved to
+ // taking it as an input instead of hard-coding llvm::errs.
+ llvm::raw_ostream &OS = llvm::errs();
+
+ // Create the target instance.
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
+ if (!hasTarget())
+ return false;
+
+ // 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.
+ getTarget().setForcedLangOptions(getLangOpts());
+
+ // Validate/process some options.
+ if (getHeaderSearchOpts().Verbose)
+ OS << "clang -cc1 version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
+ if (getFrontendOpts().ShowTimers)
+ createFrontendTimer();
+
+ for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
+ const std::string &InFile = getFrontendOpts().Inputs[i].second;
+
+ // If we aren't using an AST file, setup the file and source managers and
+ // the preprocessor.
+ bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST;
+ if (!IsAST) {
+ if (!i) {
+ // Create a file manager object to provide access to and cache the
+ // filesystem.
+ createFileManager();
+
+ // Create the source manager.
+ createSourceManager();
+ } else {
+ // Reset the ID tables if we are reusing the SourceManager.
+ getSourceManager().clearIDTables();
+ }
+
+ // Create the preprocessor.
+ createPreprocessor();
+ }
+
+ if (Act.BeginSourceFile(*this, InFile, IsAST)) {
+ Act.Execute();
+ Act.EndSourceFile();
+ }
+ }
+
+ if (getDiagnosticOpts().ShowCarets)
+ if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics())
+ OS << NumDiagnostics << " diagnostic"
+ << (NumDiagnostics == 1 ? "" : "s")
+ << " generated.\n";
+
+ if (getFrontendOpts().ShowStats) {
+ getFileManager().PrintStats();
+ OS << "\n";
+ }
+
+ // Return the appropriate status when verifying diagnostics.
+ //
+ // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
+ // this.
+ if (getDiagnosticOpts().VerifyDiagnostics)
+ return !static_cast<VerifyDiagnosticsClient&>(
+ getDiagnosticClient()).HadErrors();
+
+ return !getDiagnostics().getNumErrors();
+}
+
+
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 63f66fa54487..0bca4754ec11 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -222,6 +222,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-verify");
if (Opts.ShowOptionNames)
Res.push_back("-fdiagnostics-show-option");
+ if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
+ Res.push_back("-ftabstop");
+ Res.push_back(llvm::utostr(Opts.TabStop));
+ }
if (Opts.MessageLength) {
Res.push_back("-fmessage-length");
Res.push_back(llvm::utostr(Opts.MessageLength));
@@ -479,8 +483,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fblocks");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
- if (!Opts.MathErrno)
- Res.push_back("-fno-math-errno");
+ if (Opts.MathErrno)
+ Res.push_back("-fmath-errno");
if (Opts.OverflowChecking)
Res.push_back("-ftrapv");
if (Opts.HeinousExtensions)
@@ -804,6 +808,13 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
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.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
+ DiagnosticOptions::DefaultTabStop, Diags);
+ if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
+ Diags.Report(diag::warn_ignoring_ftabstop_value)
+ << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
+ Opts.TabStop = DiagnosticOptions::DefaultTabStop;
+ }
Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information);
Opts.Warnings = getAllArgValues(Args, OPT_W);
@@ -1147,7 +1158,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args,
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.MathErrno = Args.hasArg(OPT_fmath_errno);
Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
Diags);
Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 4fa2b3c51eb5..0b04cf2b44d3 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -115,6 +115,9 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
if (!AcceptableLocation)
return;
+ } else if (DiagLevel == Diagnostic::Note) {
+ // Don't apply fix-it modifications in notes.
+ return;
}
// Make sure that we can perform all of the modifications we
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 4c647fda2b6d..0baba3f4673a 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -280,7 +280,9 @@ void PrintParseAction::ExecuteAction() {
void PrintPreprocessedAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
- llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ // Output file needs to be set to 'Binary', to avoid converting Unix style
+ // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
if (!OS) return;
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 95551252002a..6fceb98567b0 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -477,6 +477,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
"i686-apple-darwin8", "", "", triple);
break;
+ case llvm::Triple::DragonFly:
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+ break;
case llvm::Triple::Linux:
// Exherbo (2009-10-26)
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2",
@@ -553,9 +556,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
"i686-pc-linux-gnu", "", "", triple);
break;
case llvm::Triple::FreeBSD:
- // DragonFly
- AddPath("/usr/include/c++/4.1", System, true, false, false);
- // FreeBSD
AddPath("/usr/include/c++/4.2", System, true, false, false);
break;
case llvm::Triple::Solaris:
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index c1fc92d3b0c9..e4c380ae0edd 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -14,13 +14,12 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Path.h"
using namespace clang;
@@ -28,43 +27,22 @@ using namespace clang;
// Append a #define line to Buf for Macro. Macro should be of the form XXX,
// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
// "#define XXX Y z W". To get a #define with no value, use "XXX=".
-static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro,
- Diagnostic *Diags = 0) {
- const char *Command = "#define ";
- Buf.insert(Buf.end(), Command, Command+strlen(Command));
- if (const char *Equal = strchr(Macro, '=')) {
- // Turn the = into ' '.
- Buf.insert(Buf.end(), Macro, Equal);
- Buf.push_back(' ');
-
+static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro,
+ Diagnostic &Diags) {
+ std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('=');
+ llvm::StringRef MacroName = MacroPair.first;
+ llvm::StringRef MacroBody = MacroPair.second;
+ if (MacroName.size() != Macro.size()) {
// Per GCC -D semantics, the macro ends at \n if it exists.
- const char *End = strpbrk(Equal, "\n\r");
- if (End) {
- assert(Diags && "Unexpected macro with embedded newline!");
- Diags->Report(diag::warn_fe_macro_contains_embedded_newline)
- << std::string(Macro, Equal);
- } else {
- End = Equal+strlen(Equal);
- }
-
- Buf.insert(Buf.end(), Equal+1, End);
+ llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r");
+ if (End != llvm::StringRef::npos)
+ Diags.Report(diag::warn_fe_macro_contains_embedded_newline)
+ << MacroName;
+ Builder.defineMacro(MacroName, MacroBody.substr(0, End));
} else {
// Push "macroname 1".
- Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
- Buf.push_back(' ');
- Buf.push_back('1');
+ Builder.defineMacro(Macro);
}
- Buf.push_back('\n');
-}
-
-// Append a #undef line to Buf for Macro. Macro should be of the form XXX
-// and we emit "#undef XXX".
-static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
- // Push "macroname".
- const char *Command = "#undef ";
- Buf.insert(Buf.end(), Command, Command+strlen(Command));
- Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
- Buf.push_back('\n');
}
std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
@@ -83,42 +61,25 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) {
return Lexer::Stringify(Path.str());
}
-/// Add the quoted name of an implicit include file.
-static void AddQuotedIncludePath(std::vector<char> &Buf,
- const std::string &File) {
-
- // Escape double quotes etc.
- Buf.push_back('"');
- std::string EscapedFile = NormalizeDashIncludePath(File);
- Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end());
- Buf.push_back('"');
-}
-
/// AddImplicitInclude - Add an implicit #include of the specified file to the
/// predefines buffer.
-static void AddImplicitInclude(std::vector<char> &Buf,
- const std::string &File) {
- const char *Inc = "#include ";
- Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
- AddQuotedIncludePath(Buf, File);
- Buf.push_back('\n');
+static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) {
+ Builder.append("#include \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
}
-static void AddImplicitIncludeMacros(std::vector<char> &Buf,
- const std::string &File) {
- const char *Inc = "#__include_macros ";
- Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
- AddQuotedIncludePath(Buf, File);
- Buf.push_back('\n');
+static void AddImplicitIncludeMacros(MacroBuilder &Builder,
+ llvm::StringRef File) {
+ Builder.append("#__include_macros \"" +
+ llvm::Twine(NormalizeDashIncludePath(File)) + "\"");
// Marker token to stop the __include_macros fetch loop.
- const char *Marker = "##\n"; // ##?
- Buf.insert(Buf.end(), Marker, Marker+strlen(Marker));
+ Builder.append("##"); // ##?
}
/// AddImplicitIncludePTH - Add an implicit #include using the original file
/// used to generate a PTH cache.
-static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
- const std::string& ImplicitIncludePTH) {
+static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
+ llvm::StringRef ImplicitIncludePTH) {
PTHManager *P = PP.getPTHManager();
assert(P && "No PTHManager.");
const char *OriginalFile = P->getOriginalSourceFile();
@@ -129,7 +90,7 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
return;
}
- AddImplicitInclude(Buf, OriginalFile);
+ AddImplicitInclude(Builder, OriginalFile);
}
/// PickFP - This is used to pick a value based on the FP semantics of the
@@ -150,7 +111,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal,
return IEEEQuadVal;
}
-static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
+static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
const llvm::fltSemantics *Sem) {
const char *DenormMin, *Epsilon, *Max, *Min;
DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324",
@@ -162,7 +123,6 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
"1.08420217248550443401e-19L",
"4.94065645841246544176568792868221e-324L",
"1.92592994438723585305597794258492732e-34L");
- int HasInifinity = 1, HasQuietNaN = 1;
int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113);
int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931);
int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932);
@@ -177,312 +137,281 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix,
"1.79769313486231580793728971405301e+308L",
"1.18973149535723176508575932662800702e+4932L");
- char MacroBuf[100];
- sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_DIG__=%d", Prefix, Digits);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_EPSILON__=%s", Prefix, Epsilon);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_INFINITY__=%d", Prefix, HasInifinity);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_QUIET_NAN__=%d", Prefix, HasQuietNaN);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MANT_DIG__=%d", Prefix, MantissaDigits);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX_10_EXP__=%d", Prefix, Max10Exp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX_EXP__=%d", Prefix, MaxExp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MAX__=%s", Prefix, Max);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN_10_EXP__=(%d)", Prefix, Min10Exp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN_EXP__=(%d)", Prefix, MinExp);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_MIN__=%s", Prefix, Min);
- DefineBuiltinMacro(Buf, MacroBuf);
- sprintf(MacroBuf, "__%s_HAS_DENORM__=1", Prefix);
- DefineBuiltinMacro(Buf, MacroBuf);
+ llvm::Twine DefPrefix = "__" + Prefix + "_";
+
+ Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
+ Builder.defineMacro(DefPrefix + "HAS_DENORM__");
+ Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits));
+ Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon));
+ Builder.defineMacro(DefPrefix + "HAS_INFINITY__");
+ Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__");
+ Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits));
+
+ Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp));
+ Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp));
+ Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max));
+
+ Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")");
+ Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")");
+ Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min));
}
/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro
/// named MacroName with the max value for a type with width 'TypeWidth' a
/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
-static void DefineTypeSize(const char *MacroName, unsigned TypeWidth,
- const char *ValSuffix, bool isSigned,
- std::vector<char> &Buf) {
- char MacroBuf[60];
+static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth,
+ llvm::StringRef ValSuffix, bool isSigned,
+ MacroBuilder& Builder) {
long long MaxVal;
if (isSigned)
MaxVal = (1LL << (TypeWidth - 1)) - 1;
else
MaxVal = ~0LL >> (64-TypeWidth);
- // FIXME: Switch to using raw_ostream and avoid utostr().
- sprintf(MacroBuf, "%s=%s%s", MacroName, llvm::utostr(MaxVal).c_str(),
- ValSuffix);
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix);
}
/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
/// the width, suffix, and signedness of the given type
-static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
+static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
- TI.isTypeSigned(Ty), Buf);
+ TI.isTypeSigned(Ty), Builder);
}
-static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
- std::vector<char> &Buf) {
- char MacroBuf[60];
- sprintf(MacroBuf, "%s=%s", MacroName, TargetInfo::getTypeName(Ty));
- DefineBuiltinMacro(Buf, MacroBuf);
+static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty,
+ MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
}
-static void DefineTypeWidth(const char *MacroName, TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
- char MacroBuf[60];
- sprintf(MacroBuf, "%s=%d", MacroName, TI.getTypeWidth(Ty));
- DefineBuiltinMacro(Buf, MacroBuf);
+static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty)));
}
static void DefineExactWidthIntType(TargetInfo::IntType Ty,
- const TargetInfo &TI, std::vector<char> &Buf) {
- char MacroBuf[60];
+ const TargetInfo &TI, MacroBuilder &Builder) {
int TypeWidth = TI.getTypeWidth(Ty);
- sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth);
- DefineType(MacroBuf, Ty, Buf);
+ DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder);
-
- const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty);
- if (strlen(ConstSuffix) > 0) {
- sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix);
- DefineBuiltinMacro(Buf, MacroBuf);
- }
+ llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
+ if (!ConstSuffix.empty())
+ Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__",
+ ConstSuffix);
}
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
- std::vector<char> &Buf) {
- char MacroBuf[60];
+ const FrontendOptions &FEOpts,
+ MacroBuilder &Builder) {
// Compiler version introspection macros.
- DefineBuiltinMacro(Buf, "__llvm__=1"); // LLVM Backend
- DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend
+ Builder.defineMacro("__llvm__"); // LLVM Backend
+ Builder.defineMacro("__clang__"); // Clang Frontend
// Currently claim to be compatible with GCC 4.2.1-5621.
- DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
- DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
- DefineBuiltinMacro(Buf, "__GNUC__=4");
- DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
- DefineBuiltinMacro(Buf, "__VERSION__=\"4.2.1 Compatible Clang Compiler\"");
-
+ Builder.defineMacro("__GNUC_MINOR__", "2");
+ Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
+ Builder.defineMacro("__GNUC__", "4");
+ Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+ Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\"");
// Initialize language-specific preprocessor defines.
// These should all be defined in the preprocessor according to the
// current language configuration.
if (!LangOpts.Microsoft)
- DefineBuiltinMacro(Buf, "__STDC__=1");
+ Builder.defineMacro("__STDC__");
if (LangOpts.AsmPreprocessor)
- DefineBuiltinMacro(Buf, "__ASSEMBLER__=1");
+ Builder.defineMacro("__ASSEMBLER__");
if (!LangOpts.CPlusPlus) {
if (LangOpts.C99)
- DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
+ Builder.defineMacro("__STDC_VERSION__", "199901L");
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
- DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
+ Builder.defineMacro("__STDC_VERSION__", "199409L");
}
// Standard conforming mode?
if (!LangOpts.GNUMode)
- DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1");
+ Builder.defineMacro("__STRICT_ANSI__");
if (LangOpts.CPlusPlus0x)
- DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__");
+ Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.Freestanding)
- DefineBuiltinMacro(Buf, "__STDC_HOSTED__=0");
+ Builder.defineMacro("__STDC_HOSTED__", "0");
else
- DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
+ Builder.defineMacro("__STDC_HOSTED__");
if (LangOpts.ObjC1) {
- DefineBuiltinMacro(Buf, "__OBJC__=1");
+ Builder.defineMacro("__OBJC__");
if (LangOpts.ObjCNonFragileABI) {
- DefineBuiltinMacro(Buf, "__OBJC2__=1");
- DefineBuiltinMacro(Buf, "OBJC_ZEROCOST_EXCEPTIONS=1");
+ Builder.defineMacro("__OBJC2__");
+ Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
}
if (LangOpts.getGCMode() != LangOptions::NonGC)
- DefineBuiltinMacro(Buf, "__OBJC_GC__=1");
+ Builder.defineMacro("__OBJC_GC__");
if (LangOpts.NeXTRuntime)
- DefineBuiltinMacro(Buf, "__NEXT_RUNTIME__=1");
+ Builder.defineMacro("__NEXT_RUNTIME__");
}
// darwin_constant_cfstrings controls this. This is also dependent
// on other things like the runtime I believe. This is set even for C code.
- DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1");
+ Builder.defineMacro("__CONSTANT_CFSTRINGS__");
if (LangOpts.ObjC2)
- DefineBuiltinMacro(Buf, "OBJC_NEW_PROPERTIES");
+ Builder.defineMacro("OBJC_NEW_PROPERTIES");
if (LangOpts.PascalStrings)
- DefineBuiltinMacro(Buf, "__PASCAL_STRINGS__");
+ Builder.defineMacro("__PASCAL_STRINGS__");
if (LangOpts.Blocks) {
- DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))");
- DefineBuiltinMacro(Buf, "__BLOCKS__=1");
+ Builder.defineMacro("__block", "__attribute__((__blocks__(byref)))");
+ Builder.defineMacro("__BLOCKS__");
}
if (LangOpts.Exceptions)
- DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ Builder.defineMacro("__EXCEPTIONS");
if (LangOpts.CPlusPlus) {
- DefineBuiltinMacro(Buf, "__DEPRECATED=1");
- DefineBuiltinMacro(Buf, "__GNUG__=4");
- DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
+ Builder.defineMacro("__DEPRECATED");
+ Builder.defineMacro("__GNUG__", "4");
+ Builder.defineMacro("__GXX_WEAK__");
if (LangOpts.GNUMode)
- DefineBuiltinMacro(Buf, "__cplusplus=1");
+ Builder.defineMacro("__cplusplus");
else
// C++ [cpp.predefined]p1:
// The name_ _cplusplusis defined to the value199711Lwhen compiling a
// C++ translation unit.
- DefineBuiltinMacro(Buf, "__cplusplus=199711L");
- DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ Builder.defineMacro("__cplusplus", "199711L");
+ Builder.defineMacro("__private_extern__", "extern");
// Ugly hack to work with GNU libstdc++.
- DefineBuiltinMacro(Buf, "_GNU_SOURCE=1");
+ Builder.defineMacro("_GNU_SOURCE");
}
if (LangOpts.Microsoft) {
// Filter out some microsoft extensions when trying to parse in ms-compat
// mode.
- DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__");
- DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__");
- DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__");
- DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__");
+ Builder.defineMacro("__int8", "__INT8_TYPE__");
+ Builder.defineMacro("__int16", "__INT16_TYPE__");
+ Builder.defineMacro("__int32", "__INT32_TYPE__");
+ Builder.defineMacro("__int64", "__INT64_TYPE__");
// Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
// VC++ appears to only like __FUNCTION__.
- DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__");
+ Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
// Work around some issues with Visual C++ headerws.
if (LangOpts.CPlusPlus) {
// Since we define wchar_t in C++ mode.
- DefineBuiltinMacro(Buf, "_WCHAR_T_DEFINED=1");
- DefineBuiltinMacro(Buf, "_NATIVE_WCHAR_T_DEFINED=1");
+ Builder.defineMacro("_WCHAR_T_DEFINED");
+ Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
// FIXME: This should be temporary until we have a __pragma
// solution, to avoid some errors flagged in VC++ headers.
- DefineBuiltinMacro(Buf, "_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=0");
+ Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0");
}
}
if (LangOpts.Optimize)
- DefineBuiltinMacro(Buf, "__OPTIMIZE__=1");
+ Builder.defineMacro("__OPTIMIZE__");
if (LangOpts.OptimizeSize)
- DefineBuiltinMacro(Buf, "__OPTIMIZE_SIZE__=1");
+ Builder.defineMacro("__OPTIMIZE_SIZE__");
// Initialize target-specific preprocessor defines.
// Define type sizing macros based on the target properties.
assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
- DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
-
- DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf);
- DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf);
- DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf);
- DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf);
- DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf);
- 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());
- DefineFloatMacros(Buf, "LDBL", &TI.getLongDoubleFormat());
+ Builder.defineMacro("__CHAR_BIT__", "8");
+
+ DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder);
+ DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder);
+ DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder);
+ DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder);
+ DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
+ DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
+
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
+ DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
+ DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder);
+ DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
+ DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder);
+ DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
+ DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder);
+ DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder);
+ DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder);
+ DefineType("__WINT_TYPE__", TI.getWIntType(), Builder);
+ DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder);
+ DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder);
+
+ DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat());
+ DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat());
+ DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat());
// Define a __POINTER_WIDTH__ macro for stdint.h.
- sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0));
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__POINTER_WIDTH__",
+ llvm::Twine((int)TI.getPointerWidth(0)));
if (!LangOpts.CharIsSigned)
- DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
+ Builder.defineMacro("__CHAR_UNSIGNED__");
// Define exact-width integer types for stdint.h
- sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth());
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__",
+ "char");
if (TI.getShortWidth() > TI.getCharWidth())
- DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder);
+
if (TI.getIntWidth() > TI.getShortWidth())
- DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedInt, TI, Builder);
+
if (TI.getLongWidth() > TI.getIntWidth())
- DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedLong, TI, Builder);
+
if (TI.getLongLongWidth() > TI.getLongWidth())
- DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf);
-
+ DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder);
+
// Add __builtin_va_list typedef.
- {
- const char *VAList = TI.getVAListDeclaration();
- Buf.insert(Buf.end(), VAList, VAList+strlen(VAList));
- Buf.push_back('\n');
- }
+ Builder.append(TI.getVAListDeclaration());
- if (const char *Prefix = TI.getUserLabelPrefix()) {
- sprintf(MacroBuf, "__USER_LABEL_PREFIX__=%s", Prefix);
- DefineBuiltinMacro(Buf, MacroBuf);
- }
+ if (const char *Prefix = TI.getUserLabelPrefix())
+ Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix);
// Build configuration options. FIXME: these should be controlled by
// command line options or something.
- DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
+ Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
if (LangOpts.GNUInline)
- DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1");
+ Builder.defineMacro("__GNUC_GNU_INLINE__");
else
- DefineBuiltinMacro(Buf, "__GNUC_STDC_INLINE__=1");
+ Builder.defineMacro("__GNUC_STDC_INLINE__");
if (LangOpts.NoInline)
- DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
+ Builder.defineMacro("__NO_INLINE__");
if (unsigned PICLevel = LangOpts.PICLevel) {
- sprintf(MacroBuf, "__PIC__=%d", PICLevel);
- DefineBuiltinMacro(Buf, MacroBuf);
-
- sprintf(MacroBuf, "__pic__=%d", PICLevel);
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__PIC__", llvm::Twine(PICLevel));
+ Builder.defineMacro("__pic__", llvm::Twine(PICLevel));
}
// Macros to control C99 numerics and <float.h>
- DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0");
- DefineBuiltinMacro(Buf, "__FLT_RADIX__=2");
- sprintf(MacroBuf, "__DECIMAL_DIG__=%d",
- PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36));
- DefineBuiltinMacro(Buf, MacroBuf);
+ Builder.defineMacro("__FLT_EVAL_METHOD__", "0");
+ Builder.defineMacro("__FLT_RADIX__", "2");
+ int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36);
+ Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig));
if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn)
- DefineBuiltinMacro(Buf, "__SSP__=1");
+ Builder.defineMacro("__SSP__");
else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq)
- DefineBuiltinMacro(Buf, "__SSP_ALL__=2");
+ Builder.defineMacro("__SSP_ALL__", "2");
+ if (FEOpts.ProgramAction == frontend::RewriteObjC)
+ Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Get other target #defines.
- TI.getTargetDefines(LangOpts, Buf);
+ TI.getTargetDefines(LangOpts, Builder);
}
// Initialize the remapping of files to alternative contents, e.g.,
@@ -536,58 +465,55 @@ static void InitializeFileRemapping(Diagnostic &Diags,
///
void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
- const HeaderSearchOptions &HSOpts) {
- std::vector<char> PredefineBuffer;
+ const HeaderSearchOptions &HSOpts,
+ const FrontendOptions &FEOpts) {
+ std::string PredefineBuffer;
+ PredefineBuffer.reserve(4080);
+ llvm::raw_string_ostream Predefines(PredefineBuffer);
+ MacroBuilder Builder(Predefines);
InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
PP.getFileManager(), InitOpts);
- const char *LineDirective = "# 1 \"<built-in>\" 3\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines)
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
- PredefineBuffer);
+ FEOpts, Builder);
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
- LineDirective = "# 1 \"<command line>\" 1\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<command line>\" 1");
// Process #define's and #undef's in the order they are given.
for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) {
if (InitOpts.Macros[i].second) // isUndef
- UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str());
+ Builder.undefineMacro(InitOpts.Macros[i].first);
else
- DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(),
- &PP.getDiagnostics());
+ DefineBuiltinMacro(Builder, InitOpts.Macros[i].first,
+ PP.getDiagnostics());
}
// If -imacros are specified, include them now. These are processed before
// any -include directives.
for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
- AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]);
+ AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]);
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
const std::string &Path = InitOpts.Includes[i];
if (Path == InitOpts.ImplicitPTHInclude)
- AddImplicitIncludePTH(PredefineBuffer, PP, Path);
+ AddImplicitIncludePTH(Builder, PP, Path);
else
- AddImplicitInclude(PredefineBuffer, Path);
+ AddImplicitInclude(Builder, Path);
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
- LineDirective = "# 1 \"<built-in>\" 2\n";
- PredefineBuffer.insert(PredefineBuffer.end(),
- LineDirective, LineDirective+strlen(LineDirective));
+ Builder.append("# 1 \"<built-in>\" 2");
- // Null terminate PredefinedBuffer and add it.
- PredefineBuffer.push_back(0);
- PP.setPredefines(&PredefineBuffer[0]);
+ // Copy PredefinedBuffer into the Preprocessor.
+ PP.setPredefines(Predefines.str());
// Initialize the header search object.
ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index d8fd791b1905..07d5a78beaeb 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1079,6 +1079,61 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
}
}
+void PCHReader::ReadDefinedMacros() {
+ // If there was no preprocessor block, do nothing.
+ if (!MacroCursor.getBitStreamReader())
+ return;
+
+ llvm::BitstreamCursor Cursor = MacroCursor;
+ if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) {
+ Error("malformed preprocessor block record in PCH file");
+ return;
+ }
+
+ RecordData Record;
+ while (true) {
+ unsigned Code = Cursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Cursor.ReadBlockEnd())
+ Error("error at end of preprocessor block in PCH file");
+ return;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Cursor.ReadSubBlockID();
+ if (Cursor.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Cursor.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case pch::PP_MACRO_OBJECT_LIKE:
+ case pch::PP_MACRO_FUNCTION_LIKE:
+ DecodeIdentifierInfo(Record[0]);
+ break;
+
+ case pch::PP_TOKEN:
+ // Ignore tokens.
+ break;
+ }
+ }
+}
+
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@@ -1140,6 +1195,10 @@ PCHReader::ReadPCHBlock() {
break;
case pch::PREPROCESSOR_BLOCK_ID:
+ MacroCursor = Stream;
+ if (PP)
+ PP->setExternalSource(this);
+
if (Stream.SkipBlock()) {
Error("malformed block record in PCH file");
return Failure;
@@ -1494,7 +1553,8 @@ void PCHReader::InitializeContext(ASTContext &Ctx) {
assert(PP && "Forgot to set Preprocessor ?");
PP->getIdentifierTable().setExternalIdentifierLookup(this);
PP->getHeaderSearchInfo().SetExternalLookup(this);
-
+ PP->setExternalSource(this);
+
// Load the translation unit declaration
ReadDeclRecord(DeclOffsets[0], 0);
@@ -2051,10 +2111,15 @@ void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx));
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 01e1a4191a99..69343ed48c4b 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -208,7 +208,9 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
VisitNamedDecl(CD);
- CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]);
+ CD->setAtEndRange(SourceRange(A, B));
}
void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
@@ -436,6 +438,9 @@ Attr *PCHReader::ReadAttributes() {
bool IsInherited = Record[Idx++];
switch (Kind) {
+ default:
+ assert(0 && "Unknown attribute!");
+ break;
STRING_ATTR(Alias);
UNSIGNED_ATTR(Aligned);
SIMPLE_ATTR(AlwaysInline);
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index ba82d2601026..138f1e141b09 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -304,6 +304,7 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) {
S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setVolatile(Record[Idx++]);
S->setSimple(Record[Idx++]);
+ S->setMSAsm(Record[Idx++]);
unsigned StackIdx
= StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1);
@@ -615,7 +616,8 @@ unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
}
}
}
- E->setDesignators(Designators.data(), Designators.size());
+ E->setDesignators(*Reader.getContext(),
+ Designators.data(), Designators.size());
return NumSubExprs;
}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 2875f0930c42..3f6841b54576 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -344,10 +344,15 @@ void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getTypeofLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
@@ -1148,7 +1153,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
// Loop over all the macro definitions that are live at the end of the file,
// emitting each to the PP section.
- // FIXME: Make sure that this sees macros defined in included PCH files.
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
// FIXME: This emits macros in hash table order, we should do it in a stable
@@ -1160,7 +1164,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
if (MI->isBuiltinMacro())
continue;
- // FIXME: Remove this identifier reference?
AddIdentifierRef(I->first, Record);
MacroOffsets[I->first] = Stream.GetCurrentBitNo();
Record.push_back(MI->getDefinitionLoc().getRawEncoding());
@@ -1741,9 +1744,12 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
RecordData Record;
for (; Attr; Attr = Attr->getNext()) {
- Record.push_back(Attr->getKind()); // FIXME: stable encoding
+ Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs
Record.push_back(Attr->isInherited());
switch (Attr->getKind()) {
+ default:
+ assert(0 && "Does not support PCH writing for this attribute yet!");
+ break;
case Attr::Alias:
AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
break;
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 049cdb03ea3b..2dbcc27f95ba 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -208,7 +208,9 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
VisitNamedDecl(D);
- Writer.AddSourceLocation(D->getAtEndLoc(), Record);
+ SourceRange R = D->getAtEndRange();
+ Writer.AddSourceLocation(R.getBegin(), Record);
+ Writer.AddSourceLocation(R.getEnd(), Record);
// Abstract class (no need to define a stable pch::DECL code).
}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index abf4eaa0f8aa..4be9b817ed82 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -277,6 +277,7 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) {
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Record.push_back(S->isVolatile());
Record.push_back(S->isSimple());
+ Record.push_back(S->isMSAsm());
Writer.WriteSubStmt(S->getAsmString());
// Outputs
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index c5dc979f654b..95afb908dfa1 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -394,7 +394,8 @@ namespace {
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool MSAsm) {
Out << __FUNCTION__ << "\n";
return StmtEmpty();
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index c3474728a6ed..fc9401d29001 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/DenseSet.h"
using namespace clang;
using llvm::utostr;
@@ -75,7 +76,9 @@ namespace {
llvm::SmallVector<int, 8> ObjCBcLabelNo;
// Remember all the @protocol(<expr>) expressions.
llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls;
-
+
+ llvm::DenseSet<uint64_t> CopyDestroyCache;
+
unsigned NumObjCStringLiterals;
FunctionDecl *MsgSendFunctionDecl;
@@ -111,6 +114,7 @@ namespace {
llvm::raw_ostream* OutFile;
bool SilenceRewriteMacroWarning;
+ bool objc_impl_method;
std::string Preamble;
@@ -122,6 +126,7 @@ namespace {
// Block related declarations.
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo;
llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
@@ -138,6 +143,7 @@ namespace {
llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes;
FunctionDecl *CurFunctionDef;
+ FunctionDecl *CurFunctionDeclToDeclareForBlock;
VarDecl *GlobalVarDecl;
bool DisableReplaceStmt;
@@ -247,12 +253,15 @@ namespace {
void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl);
void RewriteImplementationDecl(Decl *Dcl);
void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr);
+ void RewriteByRefString(std::string &ResultStr, const std::string &Name,
+ ValueDecl *VD);
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
+ void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD);
void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
void RewriteObjCQualifiedInterfaceTypes(Expr *E);
bool needToScanForQualifiers(QualType T);
@@ -347,7 +356,8 @@ namespace {
void RewriteBlockCall(CallExpr *Exp);
void RewriteBlockPointerDecl(NamedDecl *VD);
void RewriteByRefVar(VarDecl *VD);
- Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag);
+ Stmt *RewriteBlockDeclRefExpr(Expr *VD);
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
@@ -362,7 +372,7 @@ namespace {
unsigned hasCopy);
Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp);
void SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName);
+ const char *FunName);
void RewriteRecordBody(RecordDecl *RD);
void CollectBlockDeclRefInfo(BlockExpr *Exp);
@@ -483,6 +493,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
NSStringRecord = 0;
CurMethodDef = 0;
CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
GlobalVarDecl = 0;
SuperStructDecl = 0;
ProtocolTypeDecl = 0;
@@ -493,6 +504,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
PropParentMap = 0;
CurrentBody = 0;
DisableReplaceStmt = false;
+ objc_impl_method = false;
// Get the ID and start/end of the main file.
MainFileID = SM->getMainFileID();
@@ -588,8 +600,8 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n";
Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n";
Preamble += "#else\n";
- Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_assign(void *, const void *, const int);\n";
- Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n";
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n";
Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n";
Preamble += "#endif\n";
@@ -599,8 +611,10 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
Preamble += "#define __attribute__(X)\n";
}
- else
+ else {
Preamble += "#define __block\n";
+ Preamble += "#define __weak\n";
+ }
}
@@ -779,9 +793,17 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
// as the class. As a convenience, we include the original declaration
// as a comment.
std::string typedefString;
- typedefString += "// ";
- typedefString.append(startBuf, semiPtr-startBuf+1);
- typedefString += "\n";
+ typedefString += "// @class ";
+ for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
+ I != E; ++I) {
+ ObjCInterfaceDecl *ForwardDecl = I->getInterface();
+ typedefString += ForwardDecl->getNameAsString();
+ if (I+1 != E)
+ typedefString += ", ";
+ else
+ typedefString += ";\n";
+ }
+
for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
I != E; ++I) {
ObjCInterfaceDecl *ForwardDecl = I->getInterface();
@@ -838,7 +860,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
+ ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3);
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -859,7 +881,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- SourceLocation LocEnd = PDecl->getAtEndLoc();
+ SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
ReplaceText(LocEnd, 0, "// ", 3);
// Must comment out @optional/@required
@@ -1096,7 +1118,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
RewriteMethodDeclaration(*I);
// Lastly, comment out the @end.
- ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
+ ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3);
}
Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt,
@@ -1177,10 +1199,12 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) {
Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation OrigStart) {
ObjCIvarDecl *D = IV->getDecl();
+ const Expr *BaseExpr = IV->getBase();
if (CurMethodDef) {
- if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
+ if (BaseExpr->getType()->isObjCObjectPointerType() &&
+ isa<DeclRefExpr>(BaseExpr)) {
ObjCInterfaceType *iFaceDecl =
- dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1226,8 +1250,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
// Explicit ivar refs need to have a cast inserted.
// FIXME: consider sharing some of this code with the code above.
- if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) {
- ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ if (BaseExpr->getType()->isObjCObjectPointerType()) {
+ ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
// lookup which class implements the instance variable.
ObjCInterfaceDecl *clsDeclared = 0;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
@@ -1474,14 +1499,18 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
SynthCountByEnumWithState(buf);
buf += ");\n\t";
buf += elementName;
- buf += " = ((id)0);\n\t";
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
buf += "__break_label_";
buf += utostr(ObjCBcLabelNo.back());
buf += ": ;\n\t";
buf += "}\n\t";
buf += "else\n\t\t";
buf += elementName;
- buf += " = ((id)0);\n";
+ buf += " = ((";
+ buf += elementTypeAsString;
+ buf += ")0);\n\t";
buf += "}\n";
// Insert all these *after* the statement body.
@@ -1735,10 +1764,10 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "1) { ";
ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
sawIdTypedCatch = true;
- } else if (const PointerType *pType = t->getAs<PointerType>()) {
- ObjCInterfaceType *cls; // Should be a pointer to a class.
-
- cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
+ } else if (t->isObjCObjectPointerType()) {
+ QualType InterfaceTy = t->getPointeeType();
+ const ObjCInterfaceType *cls = // Should be a pointer to a class.
+ InterfaceTy->getAs<ObjCInterfaceType>();
if (cls) {
buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
buf += cls->getDecl()->getNameAsString();
@@ -2092,6 +2121,30 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
RewriteObjCQualifiedInterfaceTypes(FD);
}
+void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
+ const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType);
+ if (!proto)
+ return;
+ QualType Type = proto->getResultType();
+ std::string FdStr = Type.getAsString();
+ FdStr += " ";
+ FdStr += FD->getNameAsCString();
+ FdStr += "(";
+ unsigned numArgs = proto->getNumArgs();
+ for (unsigned i = 0; i < numArgs; i++) {
+ QualType ArgType = proto->getArgType(i);
+ FdStr += ArgType.getAsString();
+
+ if (i+1 < numArgs)
+ FdStr += ", ";
+ }
+ FdStr += ");\n";
+ InsertText(FunLocStart, FdStr.c_str(), FdStr.size());
+ CurFunctionDeclToDeclareForBlock = 0;
+}
+
// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super);
void RewriteObjC::SynthSuperContructorFunctionDecl() {
if (SuperContructorFunctionDecl)
@@ -2946,7 +2999,6 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
std::string &Result) {
if (MethodBegin == MethodEnd) return;
- static bool objc_impl_method = false;
if (!objc_impl_method) {
/* struct _objc_method {
SEL _cmd;
@@ -3617,7 +3669,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
int CatDefCount = CategoryImplementation.size();
// This is needed for determining instance variable offsets.
- Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n";
+ Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)\n";
// For each implemented class, write out all its meta data.
for (int i = 0; i < ClsDefCount; i++)
RewriteObjCClassMetaData(ClassImplementation[i], Result);
@@ -3711,6 +3763,15 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
}
}
+void RewriteObjC::RewriteByRefString(std::string &ResultStr,
+ const std::string &Name,
+ ValueDecl *VD) {
+ assert(BlockByRefDeclNo.count(VD) &&
+ "RewriteByRefString: ByRef decl missing");
+ ResultStr += "struct __Block_byref_" + Name +
+ "_" + utostr(BlockByRefDeclNo[VD]) ;
+}
+
std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
const char *funcName,
std::string Tag) {
@@ -3756,7 +3817,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
E = BlockByRefDecls.end(); I != E; ++I) {
S += " ";
std::string Name = (*I)->getNameAsString();
- std::string TypeString = "struct __Block_byref_" + Name + " *";
+ std::string TypeString;
+ RewriteByRefString(TypeString, Name, (*I));
+ TypeString += " *";
Name = TypeString + Name;
S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
}
@@ -3891,7 +3954,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
S += "struct __block_impl *";
Constructor += ", void *" + ArgName;
} else {
- std::string TypeString = "struct __Block_byref_" + FieldName;
+ std::string TypeString;
+ RewriteByRefString(TypeString, FieldName, (*I));
TypeString += " *";
FieldName = TypeString + FieldName;
ArgName = TypeString + ArgName;
@@ -3977,7 +4041,10 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
}
void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
- const char *FunName) {
+ const char *FunName) {
+ // Insert declaration for the function in which block literal is used.
+ if (CurFunctionDeclToDeclareForBlock)
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
// Insert closures that were part of the function.
for (unsigned i = 0; i < Blocks.size(); i++) {
@@ -4192,29 +4259,40 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) {
// i = 77;
// };
//}
-Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
- // for each BDRE where BYREFVAR is name of the variable.
+ // for each DeclRefExp where BYREFVAR is name of the variable.
+ ValueDecl *VD;
+ bool isArrow = true;
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
+ VD = BDRE->getDecl();
+ else {
+ VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
+ isArrow = false;
+ }
+
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
- MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(),
+ MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
+ FD, SourceLocation(),
FD->getType());
- const char *Name = BDRE->getDecl()->getNameAsCString();
+
+ const char *Name = VD->getNameAsCString();
FD = FieldDecl::Create(*Context, 0, SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
- BDRE->getType());
+ DeclRefExp->getType());
// Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
ME);
- ReplaceStmt(BDRE, PE);
+ ReplaceStmt(DeclRefExp, PE);
return PE;
}
@@ -4369,6 +4447,64 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
return;
}
+
+/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes:
+/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst,
+/// struct Block_byref_id_object *src) {
+/// _Block_object_assign (&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_assign(&_dest->object, _src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+/// And:
+/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) {
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT
+/// [|BLOCK_FIELD_IS_WEAK]) // object
+/// _Block_object_dispose(_src->object,
+/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK
+/// [|BLOCK_FIELD_IS_WEAK]) // block
+/// }
+
+std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD,
+ int flag) {
+ std::string S;
+ if (CopyDestroyCache.count(flag))
+ return S;
+ CopyDestroyCache.insert(flag);
+ S = "static void __Block_byref_id_object_copy_";
+ S += utostr(flag);
+ S += "(void *dst, void *src) {\n";
+
+ // offset into the object pointer is computed as:
+ // void * + void* + int + int + void* + void *
+ unsigned IntSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->IntTy));
+ unsigned VoidPtrSize =
+ static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy));
+
+ unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8;
+ S += " _Block_object_assign((char*)dst + ";
+ S += utostr(offset);
+ S += ", *(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+
+ S += "static void __Block_byref_id_object_dispose_";
+ S += utostr(flag);
+ S += "(void *src) {\n";
+ S += " _Block_object_dispose(*(void * *) ((char*)src + ";
+ S += utostr(offset);
+ S += "), ";
+ S += utostr(flag);
+ S += ");\n}\n";
+ return S;
+}
+
/// RewriteByRefVar - For each __block typex ND variable this routine transforms
/// the declaration into:
/// struct __Block_byref_ND {
@@ -4376,8 +4512,8 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
/// struct __Block_byref_ND *__forwarding;
/// int32_t __flags;
/// int32_t __size;
-/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object
-/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object
+/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object
+/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object
/// typex ND;
/// };
///
@@ -4388,54 +4524,110 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) {
///
///
void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
+ // Insert declaration for the function in which block literal is
+ // used.
+ if (CurFunctionDeclToDeclareForBlock)
+ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
+ int flag = 0;
+ int isa = 0;
SourceLocation DeclLoc = ND->getTypeSpecStartLoc();
const char *startBuf = SM->getCharacterData(DeclLoc);
SourceLocation X = ND->getLocEnd();
X = SM->getInstantiationLoc(X);
const char *endBuf = SM->getCharacterData(X);
std::string Name(ND->getNameAsString());
- std::string ByrefType = "struct __Block_byref_";
- ByrefType += Name;
+ std::string ByrefType;
+ RewriteByRefString(ByrefType, Name, ND);
ByrefType += " {\n";
ByrefType += " void *__isa;\n";
- ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += " *__forwarding;\n";
ByrefType += " int __flags;\n";
ByrefType += " int __size;\n";
- // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr;
- // if needed.
- ND->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ // Add void *__Block_byref_id_object_copy;
+ // void *__Block_byref_id_object_dispose; if needed.
+ QualType Ty = ND->getType();
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
+ ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
+ }
+
+ Ty.getAsStringInternal(Name, Context->PrintingPolicy);
ByrefType += " " + Name + ";\n";
ByrefType += "};\n";
// Insert this type in global scope. It is needed by helper function.
assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null");
SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size());
+ if (Ty.isObjCGCWeak()) {
+ flag |= BLOCK_FIELD_IS_WEAK;
+ isa = 1;
+ }
+
+ if (HasCopyAndDispose) {
+ flag = BLOCK_BYREF_CALLER;
+ QualType Ty = ND->getType();
+ // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well.
+ if (Ty->isBlockPointerType())
+ flag |= BLOCK_FIELD_IS_BLOCK;
+ else
+ flag |= BLOCK_FIELD_IS_OBJECT;
+ std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
+ if (!HF.empty())
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
// struct __Block_byref_ND ND =
// {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
// initializer-if-any};
bool hasInit = (ND->getInit() != 0);
+ unsigned flags = 0;
+ if (HasCopyAndDispose)
+ flags |= BLOCK_HAS_COPY_DISPOSE;
Name = ND->getNameAsString();
- ByrefType = "struct __Block_byref_" + Name;
+ ByrefType.clear();
+ RewriteByRefString(ByrefType, Name, ND);
if (!hasInit) {
- ByrefType += " " + Name + " = ";
- ByrefType += "{0, &" + Name + ", ";
- // FIXME. Compute the flag.
- ByrefType += "0, ";
- ByrefType += "sizeof(struct __Block_byref_" + Name + ")";
+ ByrefType += " " + Name + " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += ", &" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += ")";
+ if (HasCopyAndDispose) {
+ ByrefType += ", __Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ }
ByrefType += "};\n";
ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
ByrefType.c_str(), ByrefType.size());
}
else {
SourceLocation startLoc = ND->getInit()->getLocStart();
+ startLoc = SM->getInstantiationLoc(startLoc);
ByrefType += " " + Name;
ReplaceText(DeclLoc, endBuf-startBuf,
ByrefType.c_str(), ByrefType.size());
- ByrefType = " = {0, &" + Name + ", ";
- // FIXME. Compute the flag.
- ByrefType += "0, ";
- ByrefType += "sizeof(struct __Block_byref_" + Name + "), ";
+ ByrefType = " = {(void*)";
+ ByrefType += utostr(isa);
+ ByrefType += ", &" + Name + ", ";
+ ByrefType += utostr(flags);
+ ByrefType += ", ";
+ ByrefType += "sizeof(";
+ RewriteByRefString(ByrefType, Name, ND);
+ ByrefType += "), ";
+ if (HasCopyAndDispose) {
+ ByrefType += "__Block_byref_id_object_copy_";
+ ByrefType += utostr(flag);
+ ByrefType += ", __Block_byref_id_object_dispose_";
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
+ }
InsertText(startLoc, ByrefType.c_str(), ByrefType.size());
// Complete the newly synthesized compound expression by inserting a right
@@ -4638,8 +4830,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
Stmts.push_back(S);
else if (isa<ObjCForCollectionStmt>(S)) {
Stmts.push_back(S);
- ++BcLabelCount;
- ObjCBcLabelNo.push_back(BcLabelCount);
+ ObjCBcLabelNo.push_back(++BcLabelCount);
}
SourceRange OrigStmtRange = S->getSourceRange();
@@ -4658,7 +4849,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
// Now we snarf the rewritten text and stash it away for later use.
- std::string Str = Rewrite.getRewritenText(BE->getSourceRange());
+ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
RewrittenBlockExprs[BE] = Str;
Stmt *blockTranscribed = SynthBlockInitExpr(BE);
@@ -4801,8 +4992,13 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
if (VarDecl *VD = dyn_cast<VarDecl>(SD))
- if (VD->hasAttr<BlocksAttr>())
+ if (VD->hasAttr<BlocksAttr>()) {
+ static unsigned uniqueByrefDeclCount = 0;
+ assert(!BlockByRefDeclNo.count(ND) &&
+ "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl");
+ BlockByRefDeclNo[ND] = uniqueByrefDeclCount++;
RewriteByRefVar(VD);
+ }
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -4829,6 +5025,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (BDRE->isByRef())
return RewriteBlockDeclRefExpr(BDRE);
}
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<BlocksAttr>())
+ return RewriteBlockDeclRefExpr(DRE);
+ }
+
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());
@@ -4885,6 +5087,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
// FIXME: If this should support Obj-C++, support CXXTryStmt
if (CompoundStmt *Body = FD->getCompoundBody()) {
CurFunctionDef = FD;
+ CurFunctionDeclToDeclareForBlock = FD;
CollectPropertySetters(Body);
CurrentBody = Body;
Body =
@@ -4899,6 +5102,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
+ CurFunctionDeclToDeclareForBlock = 0;
}
return;
}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 61f8a70fffff..fcefd4e35822 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -371,7 +371,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
CaretLine.push_back('^');
// Scan the source line, looking for tabs. If we find any, manually expand
- // them to 8 characters and update the CaretLine to match.
+ // them to spaces and update the CaretLine to match.
for (unsigned i = 0; i != SourceLine.size(); ++i) {
if (SourceLine[i] != '\t') continue;
@@ -379,8 +379,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceLine[i] = ' ';
// Compute the number of spaces we need to insert.
- unsigned NumSpaces = ((i+8)&~7) - (i+1);
- assert(NumSpaces < 8 && "Invalid computation of space amt");
+ unsigned TabStop = DiagOpts->TabStop;
+ assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
+ "Invalid -ftabstop value");
+ unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
+ assert(NumSpaces < TabStop && "Invalid computation of space amt");
// Insert spaces into the SourceLine.
SourceLine.insert(i+1, NumSpaces, ' ');
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 5d2bcbb98ca0..e27060295a81 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -172,7 +172,7 @@ static inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b)
{
typedef int __v4si __attribute__((__vector_size__(16)));
- return (__m128)((__v4si)a ^ ~(__v4si)b);
+ return (__m128)((__v4si)a ^ (__v4si)b);
}
static inline __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index df712760bb25..4010d613ac24 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -56,8 +56,9 @@ struct HMapHeader {
/// HashHMapKey - This is the 'well known' hash function required by the file
/// format, used to look up keys in the hash table. The hash table uses simple
/// linear probing based on this function.
-static inline unsigned HashHMapKey(const char *S, const char *End) {
+static inline unsigned HashHMapKey(llvm::StringRef Str) {
unsigned Result = 0;
+ const char *S = Str.begin(), *End = Str.end();
for (; S != End; S++)
Result += tolower(*S) * 13;
@@ -172,17 +173,6 @@ const char *HeaderMap::getString(unsigned StrTabIdx) const {
return FileBuffer->getBufferStart()+StrTabIdx;
}
-/// StringsEqualWithoutCase - Compare the specified two strings for case-
-/// insensitive equality, returning true if they are equal. Both strings are
-/// known to have the same length.
-static bool StringsEqualWithoutCase(const char *S1, const char *S2,
- unsigned Len) {
- for (; Len; ++S1, ++S2, --Len)
- if (tolower(*S1) != tolower(*S2))
- return false;
- return true;
-}
-
//===----------------------------------------------------------------------===//
// The Main Drivers
//===----------------------------------------------------------------------===//
@@ -209,8 +199,7 @@ void HeaderMap::dump() const {
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
FileManager &FM) const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
@@ -221,18 +210,12 @@ const FileEntry *HeaderMap::LookupFile(const char *FilenameStart,
return 0;
// Linearly probe the hash table.
- for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) {
+ for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
HMapBucket B = getBucket(Bucket & (NumBuckets-1));
if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
// See if the key matches. If not, probe on.
- const char *Key = getString(B.Key);
- unsigned BucketKeyLen = strlen(Key);
- if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart))
- continue;
-
- // See if the actual strings equal.
- if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen))
+ if (!Filename.equals_lower(getString(B.Key)))
continue;
// If so, we have a match in the hash table. Construct the destination
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 2b9b7c977ceb..4554ababf76d 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -109,8 +109,7 @@ const char *DirectoryLookup::getName() const {
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
HeaderSearch &HS) const {
llvm::SmallString<1024> TmpDir;
if (isNormalDir()) {
@@ -118,33 +117,32 @@ const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart,
// FIXME: Portability. Filename concatenation should be in sys::Path.
TmpDir += getDir()->getName();
TmpDir.push_back('/');
- TmpDir.append(FilenameStart, FilenameEnd);
+ TmpDir.append(Filename.begin(), Filename.end());
return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
}
if (isFramework())
- return DoFrameworkLookup(FilenameStart, FilenameEnd, HS);
+ return DoFrameworkLookup(Filename, HS);
assert(isHeaderMap() && "Unknown directory lookup");
- return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr());
+ return getHeaderMap()->LookupFile(Filename, HS.getFileMgr());
}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
HeaderSearch &HS) const {
FileManager &FileMgr = HS.getFileMgr();
// Framework names must have a '/' in the filename.
- const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
- if (SlashPos == FilenameEnd) return 0;
+ size_t SlashPos = Filename.find('/');
+ if (SlashPos == llvm::StringRef::npos) return 0;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answer are yes/no and unknown.
const DirectoryEntry *&FrameworkDirCache =
- HS.LookupFrameworkCache(FilenameStart, SlashPos);
+ HS.LookupFrameworkCache(Filename.substr(0, SlashPos));
// If it is known and in some other directory, fail.
if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir())
@@ -159,7 +157,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
FrameworkName.push_back('/');
// FrameworkName = "/System/Library/Frameworks/Cocoa"
- FrameworkName.append(FilenameStart, SlashPos);
+ FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
// FrameworkName = "/System/Library/Frameworks/Cocoa.framework/"
FrameworkName += ".framework/";
@@ -184,7 +182,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
unsigned OrigSize = FrameworkName.size();
FrameworkName += "Headers/";
- FrameworkName.append(SlashPos+1, FilenameEnd);
+ FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
FrameworkName.end())) {
return FE;
@@ -208,21 +206,20 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart,
/// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if
/// non-null, indicates where the #including file is, in case a relative search
/// is needed.
-const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir,
const FileEntry *CurFileEnt) {
// If 'Filename' is absolute, check to see if it exists and no searching.
- if (llvm::sys::Path::isAbsolute(FilenameStart, FilenameEnd-FilenameStart)) {
+ if (llvm::sys::Path::isAbsolute(Filename.begin(), Filename.size())) {
CurDir = 0;
// If this was an #include_next "/absolute/file", fail.
if (FromDir) return 0;
// Otherwise, just return the file.
- return FileMgr.getFile(FilenameStart, FilenameEnd);
+ return FileMgr.getFile(Filename);
}
// Step #0, unless disabled, check to see if the file is in the #includer's
@@ -236,8 +233,8 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// FIXME: Portability. Filename concatenation should be in sys::Path.
TmpDir += CurFileEnt->getDir()->getName();
TmpDir.push_back('/');
- TmpDir.append(FilenameStart, FilenameEnd);
- if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) {
+ TmpDir.append(Filename.begin(), Filename.end());
+ if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) {
// Leave CurDir unset.
// This file is a system header or C++ unfriendly if the old file is.
//
@@ -265,7 +262,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// being relex/pp'd, but they would still have to search through a
// (potentially huge) series of SearchDirs to find it.
std::pair<unsigned, unsigned> &CacheLookup =
- LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue();
+ LookupFileCache.GetOrCreateValue(Filename).getValue();
// If the entry has been previously looked up, the first value will be
// non-zero. If the value is equal to i (the start point of our search), then
@@ -283,7 +280,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
const FileEntry *FE =
- SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this);
+ SearchDirs[i].LookupFile(Filename, *this);
if (!FE) continue;
CurDir = &SearchDirs[i];
@@ -307,14 +304,13 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart,
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(const char *FilenameStart,
- const char *FilenameEnd,
+LookupSubframeworkHeader(llvm::StringRef Filename,
const FileEntry *ContextFileEnt) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
- const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/');
- if (SlashPos == FilenameEnd) return 0;
+ size_t SlashPos = Filename.find('/');
+ if (SlashPos == llvm::StringRef::npos) return 0;
// Look up the base framework name of the ContextFileEnt.
const char *ContextName = ContextFileEnt->getName();
@@ -329,11 +325,11 @@ LookupSubframeworkHeader(const char *FilenameStart,
// Append Frameworks/HIToolbox.framework/
FrameworkName += "Frameworks/";
- FrameworkName.append(FilenameStart, SlashPos);
+ FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos);
FrameworkName += ".framework/";
llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup =
- FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos);
+ FrameworkMap.GetOrCreateValue(Filename.begin(), Filename.begin()+SlashPos);
// Some other location?
if (CacheLookup.getValue() &&
@@ -361,14 +357,14 @@ LookupSubframeworkHeader(const char *FilenameStart,
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
llvm::SmallString<1024> HeadersFilename(FrameworkName);
HeadersFilename += "Headers/";
- HeadersFilename.append(SlashPos+1, FilenameEnd);
+ HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
HeadersFilename.end()))) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
- HeadersFilename.append(SlashPos+1, FilenameEnd);
+ HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
return 0;
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index d5a46433c36a..0a74b26482e5 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -643,14 +643,17 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
unsigned char C = *CurPtr++;
- while (isIdentifierBody(C)) {
+ while (isIdentifierBody(C))
C = *CurPtr++;
- }
+
--CurPtr; // Back up over the skipped character.
// Fast path, no $,\,? in identifier found. '\' might be an escaped newline
// or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
// FIXME: UCNs.
+ //
+ // TODO: Could merge these checks into a CharInfo flag to make the comparison
+ // cheaper
if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
@@ -724,7 +727,8 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
// If we have a hex FP constant, continue.
- if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p'))
+ if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') &&
+ (!PP || !PP->getLangOptions().CPlusPlus0x))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
// Update the location of token as well as BufferPtr.
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 9aaa82d6263c..5cd54975055d 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -458,7 +458,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
- if (*s == 'p' || *s == 'P') {
+ if ((*s == 'p' || *s == 'P') && !PP.getLangOptions().CPlusPlus0x) {
const char *Exponent = s;
s++;
saw_exponent = true;
@@ -472,7 +472,12 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
}
s = first_non_digit;
- if (!PP.getLangOptions().HexFloats)
+ // In C++0x, we cannot support hexadecmial floating literals because
+ // they conflict with user-defined literals, so we warn in previous
+ // versions of C++ by default.
+ if (PP.getLangOptions().CPlusPlus)
+ PP.Diag(TokLoc, diag::ext_hexconstant_cplusplus);
+ else if (!PP.getLangOptions().HexFloats)
PP.Diag(TokLoc, diag::ext_hexconstant_invalid);
} else if (saw_period) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 9e3d283d8886..aa807f800d3e 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -404,8 +404,8 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
-const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
- const char *FilenameEnd,
+const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
+ SourceLocation FilenameTokLoc,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir) {
@@ -431,17 +431,24 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
// Do a standard file entry lookup.
CurDir = CurDirLookup;
const FileEntry *FE =
- HeaderInfo.LookupFile(FilenameStart, FilenameEnd,
- isAngled, FromDir, CurDir, CurFileEnt);
- if (FE) return FE;
+ HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt);
+ if (FE) {
+ // Warn about normal quoted #include from framework headers. Since
+ // framework headers are published (both public and private ones) they
+ // should not do relative searches, they should do an include with the
+ // framework path included.
+ if (!isAngled && CurDir && FilenameTokLoc.isValid() &&
+ CurDir->isFramework() && CurDir == CurDirLookup)
+ Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework);
+ return FE;
+ }
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd,
- CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
return FE;
}
@@ -450,8 +457,7 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart,
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt =
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
- if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart,
- FilenameEnd, CurFileEnt)))
+ if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt)))
return FE;
}
}
@@ -922,43 +928,41 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
/// spelling of the filename, but is also expected to handle the case when
/// this method decides to use a different buffer.
bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
- const char *&BufStart,
- const char *&BufEnd) {
+ llvm::StringRef &Buffer) {
// Get the text form of the filename.
- assert(BufStart != BufEnd && "Can't have tokens with empty spellings!");
+ assert(!Buffer.empty() && "Can't have tokens with empty spellings!");
// Make sure the filename is <x> or "x".
bool isAngled;
- if (BufStart[0] == '<') {
- if (BufEnd[-1] != '>') {
+ if (Buffer[0] == '<') {
+ if (Buffer.back() != '>') {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
isAngled = true;
- } else if (BufStart[0] == '"') {
- if (BufEnd[-1] != '"') {
+ } else if (Buffer[0] == '"') {
+ if (Buffer.back() != '"') {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
isAngled = false;
} else {
Diag(Loc, diag::err_pp_expects_filename);
- BufStart = 0;
+ Buffer = llvm::StringRef();
return true;
}
// Diagnose #include "" as invalid.
- if (BufEnd-BufStart <= 2) {
+ if (Buffer.size() <= 2) {
Diag(Loc, diag::err_pp_empty_filename);
- BufStart = 0;
- return "";
+ Buffer = llvm::StringRef();
+ return true;
}
// Skip the brackets.
- ++BufStart;
- --BufEnd;
+ Buffer = Buffer.substr(1, Buffer.size()-2);
return isAngled;
}
@@ -1024,8 +1028,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
CurPPLexer->LexIncludeFilename(FilenameTok);
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
- const char *FilenameStart, *FilenameEnd;
+ llvm::SmallString<128> FilenameBuffer;
+ llvm::StringRef Filename;
switch (FilenameTok.getKind()) {
case tok::eom:
@@ -1035,9 +1039,9 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
case tok::angle_string_literal:
case tok::string_literal: {
FilenameBuffer.resize(FilenameTok.getLength());
- FilenameStart = &FilenameBuffer[0];
+ const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = getSpelling(FilenameTok, FilenameStart);
- FilenameEnd = FilenameStart+Len;
+ Filename = llvm::StringRef(FilenameStart, Len);
break;
}
@@ -1047,8 +1051,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
FilenameBuffer.push_back('<');
if (ConcatenateIncludeName(FilenameBuffer))
return; // Found <eom> but no ">"? Diagnostic already emitted.
- FilenameStart = FilenameBuffer.data();
- FilenameEnd = FilenameStart + FilenameBuffer.size();
+ Filename = FilenameBuffer.str();
break;
default:
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
@@ -1056,11 +1059,11 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
return;
}
- bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
- FilenameStart, FilenameEnd);
+ bool isAngled =
+ GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0) {
+ if (Filename.empty()) {
DiscardUntilEndOfDirective();
return;
}
@@ -1079,14 +1082,13 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
isAngled, LookupFrom, CurDir);
if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
-
+
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport))
@@ -1103,8 +1105,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(),
FileCharacter);
if (FID.isInvalid()) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index ce1b19ca7c10..0b26ccbecbab 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -249,7 +249,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// diagnostic is enabled, look for macros that have not been used.
if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) !=
Diagnostic::Ignored) {
- for (macro_iterator I = macro_begin(), E = macro_end(); I != E; ++I)
+ for (macro_iterator I = macro_begin(false), E = macro_end(false);
+ I != E; ++I)
if (!I->second->isUsed())
Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index dfb14ff06f1f..37927827a8b2 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/ADT/StringSwitch.h"
#include <cstdio>
#include <ctime>
using namespace clang;
@@ -481,34 +482,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
- switch (II->getLength()) {
- default: return false;
- case 6:
- if (II->isStr("blocks")) return LangOpts.Blocks;
- return false;
- case 8:
- if (II->isStr("cxx_rtti")) return LangOpts.RTTI;
- return false;
- case 14:
- if (II->isStr("cxx_exceptions")) return LangOpts.Exceptions;
- return false;
- case 19:
- if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI;
- return false;
- case 22:
- if (II->isStr("attribute_overloadable")) return true;
- return false;
- case 25:
- if (II->isStr("attribute_ext_vector_type")) return true;
- return false;
- case 27:
- if (II->isStr("attribute_analyzer_noreturn")) return true;
- return false;
- case 29:
- if (II->isStr("attribute_ns_returns_retained")) return true;
- if (II->isStr("attribute_cf_returns_retained")) return true;
- return false;
- }
+ return llvm::StringSwitch<bool>(II->getName())
+ .Case("blocks", LangOpts.Blocks)
+ .Case("cxx_rtti", LangOpts.RTTI)
+ //.Case("cxx_lambdas", false)
+ //.Case("cxx_nullptr", false)
+ //.Case("cxx_concepts", false)
+ .Case("cxx_decltype", LangOpts.CPlusPlus0x)
+ .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
+ .Case("cxx_exceptions", LangOpts.Exceptions)
+ .Case("cxx_attributes", LangOpts.CPlusPlus0x)
+ .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
+ .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
+ //.Case("cxx_rvalue_references", false)
+ .Case("attribute_overloadable", true)
+ //.Case("cxx_variadic_templates", false)
+ .Case("attribute_ext_vector_type", true)
+ .Case("attribute_analyzer_noreturn", true)
+ .Case("attribute_ns_returns_retained", true)
+ .Case("attribute_cf_returns_retained", true)
+ .Default(false);
}
/// EvaluateHasIncludeCommon - Process a '__has_include("path")'
@@ -535,8 +529,8 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
PP.getCurrentLexer()->LexIncludeFilename(Tok);
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
- const char *FilenameStart, *FilenameEnd;
+ llvm::SmallString<128> FilenameBuffer;
+ llvm::StringRef Filename;
switch (Tok.getKind()) {
case tok::eom:
@@ -546,9 +540,9 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
case tok::angle_string_literal:
case tok::string_literal: {
FilenameBuffer.resize(Tok.getLength());
- FilenameStart = &FilenameBuffer[0];
+ const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = PP.getSpelling(Tok, FilenameStart);
- FilenameEnd = FilenameStart+Len;
+ Filename = llvm::StringRef(FilenameStart, Len);
break;
}
@@ -558,26 +552,24 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
FilenameBuffer.push_back('<');
if (PP.ConcatenateIncludeName(FilenameBuffer))
return false; // Found <eom> but no ">"? Diagnostic already emitted.
- FilenameStart = FilenameBuffer.data();
- FilenameEnd = FilenameStart + FilenameBuffer.size();
+ Filename = FilenameBuffer.str();
break;
default:
PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename);
return false;
}
- bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(),
- FilenameStart, FilenameEnd);
+ bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0) {
+ if (Filename.empty())
return false;
- }
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd,
- isAngled, LookupFrom, CurDir);
+ const FileEntry *File = PP.LookupFile(Filename,
+ SourceLocation(),// produce no warnings.
+ isAngled, LookupFrom, CurDir);
// Get the result value. Result = true means the file exists.
Result = File != 0;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 8b46f716910c..856b3bd76d80 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -286,26 +286,25 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
return;
// Reserve a buffer to get the spelling.
- llvm::SmallVector<char, 128> FilenameBuffer;
+ llvm::SmallString<128> FilenameBuffer;
FilenameBuffer.resize(FilenameTok.getLength());
const char *FilenameStart = &FilenameBuffer[0];
unsigned Len = getSpelling(FilenameTok, FilenameStart);
- const char *FilenameEnd = FilenameStart+Len;
- bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(),
- FilenameStart, FilenameEnd);
+ llvm::StringRef Filename(FilenameStart, Len);
+ bool isAngled =
+ GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (FilenameStart == 0)
+ if (Filename.empty())
return;
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(FilenameStart, FilenameEnd,
+ const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
isAngled, 0, CurDir);
if (File == 0) {
- Diag(FilenameTok, diag::err_pp_file_not_found)
- << std::string(FilenameStart, FilenameEnd);
+ Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 81966cb2b918..26bb3a90dac0 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -27,6 +27,7 @@
#include "clang/Lex/Preprocessor.h"
#include "MacroArgs.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Pragma.h"
@@ -43,6 +44,7 @@
using namespace clang;
//===----------------------------------------------------------------------===//
+ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
const TargetInfo &target, SourceManager &SM,
@@ -50,9 +52,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
- SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup),
- BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0),
- Callbacks(0), MacroArgCache(0) {
+ SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
+ Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
+ CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -77,6 +79,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
CachedLexPos = 0;
+ // We haven't read anything from the external source.
+ ReadMacrosFromExternalSource = false;
+
// "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
// This gets unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
@@ -194,6 +199,28 @@ void Preprocessor::PrintStats() {
<< NumFastTokenPaste << " on the fast path.\n";
}
+Preprocessor::macro_iterator
+Preprocessor::macro_begin(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
+ !ReadMacrosFromExternalSource) {
+ ReadMacrosFromExternalSource = true;
+ ExternalSource->ReadDefinedMacros();
+ }
+
+ return Macros.begin();
+}
+
+Preprocessor::macro_iterator
+Preprocessor::macro_end(bool IncludeExternalMacros) const {
+ if (IncludeExternalMacros && ExternalSource &&
+ !ReadMacrosFromExternalSource) {
+ ReadMacrosFromExternalSource = true;
+ ExternalSource->ReadDefinedMacros();
+ }
+
+ return Macros.end();
+}
+
bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
unsigned TruncateAtLine,
unsigned TruncateAtColumn) {
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 4cd8fe887bb1..f52d8b98567a 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -36,6 +36,14 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
EndLocation = TemplateId->RAngleLoc;
}
+void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
+ assert(TemplateId && "NULL template-id annotation?");
+ Kind = IK_ConstructorTemplateId;
+ this->TemplateId = TemplateId;
+ StartLocation = TemplateId->TemplateNameLoc;
+ EndLocation = TemplateId->RAngleLoc;
+}
+
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index f429ac991d83..b5ba8acafc8d 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -356,7 +356,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
ParsingDeclSpec DS(*this);
if (Attr)
DS.AddAttributes(Attr);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
+ getDeclSpecContextFromDeclaratorContext(Context));
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
@@ -786,6 +787,20 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
return false;
}
+/// \brief Determine the declaration specifier context from the declarator
+/// context.
+///
+/// \param Context the declarator context, which is one of the
+/// Declarator::TheContext enumerator values.
+Parser::DeclSpecContext
+Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
+ if (Context == Declarator::MemberContext)
+ return DSC_class;
+ if (Context == Declarator::FileContext)
+ return DSC_top_level;
+ return DSC_normal;
+}
+
/// ParseDeclarationSpecifiers
/// declaration-specifiers: [C99 6.7]
/// storage-class-specifier declaration-specifiers[opt]
@@ -814,7 +829,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
AccessSpecifier AS,
DeclSpecContext DSContext) {
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Action::CodeCompletionContext CCC = Action::CCC_Namespace;
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
+ CCC = DSContext == DSC_class? Action::CCC_MemberTemplate
+ : Action::CCC_Template;
+ else if (DSContext == DSC_class)
+ CCC = Action::CCC_Class;
+ else if (ObjCImpDecl)
+ CCC = Action::CCC_ObjCImplementation;
+
+ Actions.CodeCompleteOrdinaryName(CurScope, CCC);
ConsumeToken();
}
@@ -854,6 +878,47 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
+
+ // C++ [class.qual]p2:
+ // In a lookup in which the constructor is an acceptable lookup
+ // result and the nested-name-specifier nominates a class C:
+ //
+ // - if the name specified after the
+ // nested-name-specifier, when looked up in C, is the
+ // injected-class-name of C (Clause 9), or
+ //
+ // - if the name specified after the nested-name-specifier
+ // is the same as the identifier or the
+ // simple-template-id's template-name in the last
+ // component of the nested-name-specifier,
+ //
+ // the name is instead considered to name the constructor of
+ // class C.
+ //
+ // Thus, if the template-name is actually the constructor
+ // name, then the code is ill-formed; this interpretation is
+ // reinforced by the NAD status of core issue 635.
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue());
+ if (DSContext == DSC_top_level && TemplateId->Name &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
+ if (isConstructorDeclarator()) {
+ // The user meant this to be an out-of-line constructor
+ // definition, but template arguments are not allowed
+ // there. Just allow this as a constructor; we'll
+ // complain about it later.
+ goto DoneWithDeclSpec;
+ }
+
+ // The user meant this to name a type, but it actually names
+ // a constructor with some extraneous template
+ // arguments. Complain, then parse it as a type as the user
+ // intended.
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_out_of_line_template_id_names_constructor)
+ << TemplateId->Name;
+ }
+
DS.getTypeSpecScope() = SS;
ConsumeToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
@@ -878,13 +943,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
- // If the next token is the name of the class type that the C++ scope
- // denotes, followed by a '(', then this is a constructor declaration.
- // We're done with the decl-specifiers.
- if (Actions.isCurrentClassName(*Next.getIdentifierInfo(),
- CurScope, &SS) &&
- GetLookAheadToken(2).is(tok::l_paren))
- goto DoneWithDeclSpec;
+ // If we're in a context where the identifier could be a class name,
+ // check whether this is a constructor declaration.
+ if (DSContext == DSC_top_level &&
+ Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope,
+ &SS)) {
+ if (isConstructorDeclarator())
+ goto DoneWithDeclSpec;
+
+ // As noted in C++ [class.qual]p2 (cited above), when the name
+ // of the class is qualified in a context where it could name
+ // a constructor, its a constructor name. However, we've
+ // looked at the declarator, and the user probably meant this
+ // to be a type. Complain that it isn't supposed to be treated
+ // as a type, then proceed to parse it as a type.
+ Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor)
+ << Next.getIdentifierInfo();
+ }
TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(), CurScope, &SS);
@@ -965,16 +1040,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
}
- // C++: If the identifier is actually the name of the class type
- // being defined and the next token is a '(', then this is a
- // constructor declaration. We're done with the decl-specifiers
- // and will treat this token as an identifier.
- if (getLang().CPlusPlus &&
- (CurScope->isClassScope() ||
- (CurScope->isTemplateParamScope() &&
- CurScope->getParent()->isClassScope())) &&
+ // If we're in a context where the identifier could be a class name,
+ // check whether this is a constructor declaration.
+ if (getLang().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) &&
- NextToken().getKind() == tok::l_paren)
+ isConstructorDeclarator())
goto DoneWithDeclSpec;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
@@ -1017,6 +1087,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
goto DoneWithDeclSpec;
}
+ // If we're in a context where the template-id could be a
+ // constructor name or specialization, check whether this is a
+ // constructor declaration.
+ if (getLang().CPlusPlus && DSContext == DSC_class &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope) &&
+ isConstructorDeclarator())
+ goto DoneWithDeclSpec;
+
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
AnnotateTemplateIdTokenAsType();
@@ -2082,6 +2160,48 @@ bool Parser::isDeclarationSpecifier() {
}
}
+bool Parser::isConstructorDeclarator() {
+ TentativeParsingAction TPA(*this);
+
+ // Parse the C++ scope specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, 0, true);
+
+ // Parse the constructor name.
+ if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
+ // We already know that we have a constructor name; just consume
+ // the token.
+ ConsumeToken();
+ } else {
+ TPA.Revert();
+ return false;
+ }
+
+ // Current class name must be followed by a left parentheses.
+ if (Tok.isNot(tok::l_paren)) {
+ TPA.Revert();
+ return false;
+ }
+ ConsumeParen();
+
+ // A right parentheses or ellipsis signals that we have a constructor.
+ if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) {
+ TPA.Revert();
+ return true;
+ }
+
+ // If we need to, enter the specified scope.
+ DeclaratorScopeObj DeclScopeObj(*this, SS);
+ if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(CurScope, SS))
+ DeclScopeObj.EnterDeclaratorScope();
+
+ // Check whether the next token(s) are part of a declaration
+ // specifier, in which case we have the start of a parameter and,
+ // therefore, we know that this is a constructor.
+ bool IsConstructor = isDeclarationSpecifier();
+ TPA.Revert();
+ return IsConstructor;
+}
/// ParseTypeQualifierListOpt
/// type-qualifier-list: [C99 6.7.5]
@@ -2366,10 +2486,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) {
// We found something that indicates the start of an unqualified-id.
// Parse that unqualified-id.
+ bool AllowConstructorName
+ = ((D.getCXXScopeSpec().isSet() &&
+ D.getContext() == Declarator::FileContext) ||
+ (!D.getCXXScopeSpec().isSet() &&
+ D.getContext() == Declarator::MemberContext)) &&
+ !D.getDeclSpec().hasTypeSpecifier();
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
- /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
+ AllowConstructorName,
/*ObjectType=*/0,
D.getName())) {
D.SetIdentifier(0, Tok.getLocation());
@@ -2396,6 +2522,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// direct-declarator: '(' attributes declarator ')'
// Example: 'char (*X)' or 'int (*XX)(void)'
ParseParenDeclarator(D);
+
+ // If the declarator was parenthesized, we entered the declarator
+ // scope when parsing the parenthesized declarator, then exited
+ // the scope already. Re-enter the scope, if we need to.
+ if (D.getCXXScopeSpec().isSet()) {
+ if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec()))
+ // Change the declaration context for name lookup, until this function
+ // is exited (and the declarator has been parsed).
+ DeclScopeObj.EnterDeclaratorScope();
+ }
} else if (D.mayOmitIdentifier()) {
// This could be something simple like "int" (in which case the declarator
// portion is empty), if an abstract-declarator is allowed.
@@ -3020,6 +3156,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
Token OpTok = Tok;
SourceLocation StartLoc = ConsumeToken();
+ const bool hasParens = Tok.is(tok::l_paren);
+
bool isCastExpr;
TypeTy *CastTy;
SourceRange CastRange;
@@ -3027,6 +3165,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
isCastExpr,
CastTy,
CastRange);
+ if (hasParens)
+ DS.setTypeofParensRange(CastRange);
if (CastRange.getEnd().isInvalid())
// FIXME: Not accurate, the range gets one token more than it should.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 265d0f3e849f..90040c54bfb1 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -468,7 +468,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (TemplateId->Kind == TNK_Type_template) {
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(SS);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
@@ -489,18 +490,57 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation,
return true;
}
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ if (Tok.is(tok::less)) {
+ // It looks the user intended to write a template-id here, but the
+ // template-name was wrong. Try to fix that.
+ TemplateNameKind TNK = TNK_Type_template;
+ TemplateTy Template;
+ if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope,
+ SS, Template, TNK)) {
+ Diag(IdLoc, diag::err_unknown_template_name)
+ << Id;
+ }
+
+ if (!Template)
+ return true;
+
+ // Form the template name
+ UnqualifiedId TemplateName;
+ TemplateName.setIdentifier(Id, IdLoc);
+
+ // Parse the full template-id, then turn it into a type.
+ if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
+ SourceLocation(), true))
+ return true;
+ if (TNK == TNK_Dependent_template_name)
+ AnnotateTemplateIdTokenAsType(SS);
+
+ // If we didn't end up with a typename token, there's nothing more we
+ // can do.
+ if (Tok.isNot(tok::annot_typename))
+ return true;
+
+ // Retrieve the type from the annotation token, consume that token, and
+ // return.
+ EndLocation = Tok.getAnnotationEndLoc();
+ TypeTy *Type = Tok.getAnnotationValue();
+ ConsumeToken();
+ return Type;
+ }
+
// We have an identifier; check whether it is actually a type.
- TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
- Tok.getLocation(), CurScope, SS,
- true);
- if (!Type) {
- Diag(Tok, DestrExpected ? diag::err_destructor_class_name
+ TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true);
+ if (!Type) {
+ Diag(IdLoc, DestrExpected ? diag::err_destructor_class_name
: diag::err_expected_class_name);
return true;
}
// Consume the identifier.
- EndLocation = ConsumeToken();
+ EndLocation = IdLoc;
return Type;
}
@@ -1527,12 +1567,12 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) {
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
- if (TemplateId->Kind == TNK_Type_template) {
+ if (TemplateId->Kind == TNK_Type_template ||
+ TemplateId->Kind == TNK_Dependent_template_name) {
AnnotateTemplateIdTokenAsType(&SS);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = Tok.getAnnotationValue();
}
- // FIXME. May need to check for TNK_Dependent_template as well.
}
if (!TemplateTypeTy && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_member_or_base_name);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index bdbc67f782dc..669575c4f030 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -200,11 +200,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// expression ',' assignment-expression
///
Parser::OwningExprResult Parser::ParseExpression() {
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
- ConsumeToken();
- }
-
OwningExprResult LHS(ParseAssignmentExpression());
if (LHS.isInvalid()) return move(LHS);
@@ -248,6 +243,11 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
/// ParseAssignmentExpression - Parse an expr that doesn't include commas.
///
Parser::OwningExprResult Parser::ParseAssignmentExpression() {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression);
+ ConsumeToken();
+ }
+
if (Tok.is(tok::kw_throw))
return ParseThrowExpression();
@@ -616,9 +616,17 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// Turn a potentially qualified name into a annot_typename or
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
if (getLang().CPlusPlus) {
- // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
- if (TryAnnotateTypeOrScopeToken())
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ // Avoid the unnecessary parse-time lookup in the common case
+ // where the syntax forbids a type.
+ const Token &Next = NextToken();
+ if (Next.is(tok::coloncolon) ||
+ (!ColonIsSacred && Next.is(tok::colon)) ||
+ Next.is(tok::less) ||
+ Next.is(tok::l_paren)) {
+ // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
+ if (TryAnnotateTypeOrScopeToken())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+ }
}
// Consume the identifier so that we can see if it is followed by a '(' or
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index abd26d7d4905..ca50ef400092 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -585,6 +585,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
/// \returns true if there was a parsing, false otherwise.
bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
DeclPtrTy &DeclResult) {
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition);
+ ConsumeToken();
+ }
+
if (!isCXXConditionDeclaration()) {
ExprResult = ParseExpression(); // expression
DeclResult = DeclPtrTy();
@@ -1148,6 +1153,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
IdentifierInfo *Id = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
+ if (!getLang().CPlusPlus) {
+ // If we're not in C++, only identifiers matter. Record the
+ // identifier and return.
+ Result.setIdentifier(Id, IdLoc);
+ return false;
+ }
+
if (AllowConstructorName &&
Actions.isCurrentClassName(*Id, CurScope, &SS)) {
// We have parsed a constructor name.
@@ -1170,12 +1182,41 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// unqualified-id:
// template-id (already parsed and annotated)
if (Tok.is(tok::annot_template_id)) {
- // FIXME: Could this be a constructor name???
-
+ TemplateIdAnnotation *TemplateId
+ = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue());
+
+ // If the template-name names the current class, then this is a constructor
+ if (AllowConstructorName && TemplateId->Name &&
+ Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) {
+ if (SS.isSet()) {
+ // C++ [class.qual]p2 specifies that a qualified template-name
+ // is taken as the constructor name where a constructor can be
+ // declared. Thus, the template arguments are extraneous, so
+ // complain about them and remove them entirely.
+ Diag(TemplateId->TemplateNameLoc,
+ diag::err_out_of_line_constructor_template_id)
+ << TemplateId->Name
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
+ Result.setConstructorName(Actions.getTypeName(*TemplateId->Name,
+ TemplateId->TemplateNameLoc,
+ CurScope,
+ &SS, false),
+ TemplateId->TemplateNameLoc,
+ TemplateId->RAngleLoc);
+ TemplateId->Destroy();
+ ConsumeToken();
+ return false;
+ }
+
+ Result.setConstructorTemplateId(TemplateId);
+ ConsumeToken();
+ return false;
+ }
+
// We have already parsed a template-id; consume the annotation token as
// our unqualified-id.
- Result.setTemplateId(
- static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()));
+ Result.setTemplateId(TemplateId);
ConsumeToken();
return false;
}
@@ -1202,7 +1243,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
return false;
}
- if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
+ if (getLang().CPlusPlus &&
+ (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
// C++ [expr.unary.op]p10:
// There is an ambiguity in the unary-expression ~X(), where X is a
// class-name. The ambiguity is resolved in favor of treating ~ as a
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 9904a2ca85dc..5e2363535320 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -309,7 +309,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
- SourceLocation AtEndLoc;
+ SourceRange AtEnd;
while (1) {
// If this is a method prototype, parse it.
@@ -334,6 +334,14 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
if (Tok.is(tok::eof))
break;
+ // Code completion within an Objective-C interface.
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ ObjCImpDecl? Action::CCC_ObjCImplementation
+ : Action::CCC_ObjCInterface);
+ ConsumeToken();
+ }
+
// If we don't have an @ directive, parse it as a function definition.
if (Tok.isNot(tok::at)) {
// The code below does not consume '}'s because it is afraid of eating the
@@ -359,7 +367,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
- AtEndLoc = AtLoc;
+ AtEnd.setBegin(AtLoc);
+ AtEnd.setEnd(Tok.getLocation());
break;
}
@@ -422,7 +431,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
// Insert collected methods declarations into the @interface object.
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
- Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
+ Actions.ActOnAtEnd(AtEnd, interfaceDecl,
allMethods.data(), allMethods.size(),
allProperties.data(), allProperties.size(),
allTUVariables.data(), allTUVariables.size());
@@ -964,6 +973,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
// Set the default visibility to private.
if (Tok.is(tok::at)) { // parse objc-visibility-spec
ConsumeToken(); // eat the @ sign
+
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteObjCAtVisibility(CurScope);
+ ConsumeToken();
+ }
+
switch (Tok.getObjCKeywordID()) {
case tok::objc_private:
case tok::objc_public:
@@ -978,6 +993,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
}
}
+ if (Tok.is(tok::code_completion)) {
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ Action::CCC_ObjCInstanceVariableList);
+ ConsumeToken();
+ }
+
struct ObjCIvarCallback : FieldCallback {
Parser &P;
DeclPtrTy IDecl;
@@ -1197,18 +1218,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
return DeclPtrTy();
}
-Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
+Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
DeclPtrTy Result = ObjCImpDecl;
ConsumeToken(); // the "end" identifier
if (ObjCImpDecl) {
- Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
+ Actions.ActOnAtEnd(atEnd, ObjCImpDecl);
ObjCImpDecl = DeclPtrTy();
PendingObjCImpDecl.pop_back();
}
- else
- Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
+ else {
+ // missing @implementation
+ Diag(atEnd.getBegin(), diag::warn_expected_implementation);
+ }
return Result;
}
@@ -1216,7 +1239,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
if (PendingObjCImpDecl.empty())
return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
- Actions.ActOnAtEnd(SourceLocation(), ImpDecl);
+ Actions.ActOnAtEnd(SourceRange(), ImpDecl);
return Actions.ConvertDeclToDeclGroup(ImpDecl);
}
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 9085b8713dfd..21e960aa8173 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -95,7 +95,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
}
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Statement);
ConsumeToken();
return ParseStatementOrDeclaration(OnlyStatement);
@@ -955,7 +955,9 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
DeclPtrTy SecondVar;
if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ C99orCXXorObjC? Action::CCC_ForInit
+ : Action::CCC_Expression);
ConsumeToken();
}
@@ -1182,7 +1184,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() {
return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(),
move_arg(Constraints), move_arg(Exprs),
move(AsmString), move_arg(Clobbers),
- Tok.getLocation());
+ Tok.getLocation(), true);
}
/// ParseAsmStatement - Parse a GNU extended asm statement.
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 8b8af99ec6d7..797c1dfe3e6a 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -196,7 +196,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
DS.AddAttributes(ParseCXX0XAttributes().AttrList);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
+ ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
+ getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
DeclEnd = ConsumeToken();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 52c0153bfad8..0aecac975741 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -455,7 +455,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
SingleDecl = ParseObjCMethodDefinition();
break;
case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(CurScope);
+ Actions.CodeCompleteOrdinaryName(CurScope,
+ ObjCImpDecl? Action::CCC_ObjCImplementation
+ : Action::CCC_Namespace);
ConsumeToken();
return ParseExternalDeclaration(Attr);
case tok::kw_using:
@@ -541,7 +543,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS,
if (Attr)
DS.AddAttributes(Attr);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level);
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 27a5f8b5ffeb..9744496ac4fe 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -97,13 +97,13 @@ int Rewriter::getRangeSize(SourceRange Range) const {
return EndOff-StartOff;
}
-/// getRewritenText - Return the rewritten form of the text in the specified
+/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
///
-std::string Rewriter::getRewritenText(SourceRange Range) const {
+std::string Rewriter::getRewrittenText(SourceRange Range) const {
if (!isRewritable(Range.getBegin()) ||
!isRewritable(Range.getEnd()))
return "";
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index fd3265d874ce..5be6712c8397 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -29,6 +29,7 @@ add_clang_library(clangSema
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
SemaType.cpp
+ TargetAttributesSema.cpp
)
add_dependencies(clangSema ClangDiagnosticSema)
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index b9b85dfb8084..fbd14502b7e5 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -85,6 +85,26 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text)
case CK_Comma:
this->Text = ", ";
break;
+
+ case CK_Colon:
+ this->Text = ": ";
+ break;
+
+ case CK_SemiColon:
+ this->Text = ";";
+ break;
+
+ case CK_Equal:
+ this->Text = " = ";
+ break;
+
+ case CK_HorizontalSpace:
+ this->Text = " ";
+ break;
+
+ case CK_VerticalSpace:
+ this->Text = "\n";
+ break;
}
}
@@ -140,6 +160,11 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
return Chunk(Kind, Text);
case CK_Optional: {
@@ -177,6 +202,11 @@ CodeCompletionString::Chunk::Destroy() {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
break;
}
}
@@ -271,6 +301,11 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
break;
}
}
@@ -326,6 +361,11 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
case CK_LeftAngle:
case CK_RightAngle:
case CK_Comma:
+ case CK_Colon:
+ case CK_SemiColon:
+ case CK_Equal:
+ case CK_HorizontalSpace:
+ case CK_VerticalSpace:
Result->AddChunk(Chunk(Kind));
break;
}
@@ -386,8 +426,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
OS << "COMPLETION: ";
switch (Results[I].Kind) {
case Result::RK_Declaration:
- OS << Results[I].Declaration->getNameAsString() << " : "
- << Results[I].Rank;
+ OS << Results[I].Declaration->getNameAsString() ;
if (Results[I].Hidden)
OS << " (Hidden)";
if (CodeCompletionString *CCS
@@ -400,13 +439,13 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
break;
case Result::RK_Keyword:
- OS << Results[I].Keyword << " : " << Results[I].Rank << '\n';
+ OS << Results[I].Keyword << '\n';
break;
case Result::RK_Macro: {
- OS << Results[I].Macro->getName() << " : " << Results[I].Rank;
+ OS << Results[I].Macro->getName();
if (CodeCompletionString *CCS
- = Results[I].CreateCodeCompletionString(SemaRef)) {
+ = Results[I].CreateCodeCompletionString(SemaRef)) {
OS << " : " << CCS->getAsString();
delete CCS;
}
@@ -415,7 +454,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
}
case Result::RK_Pattern: {
- OS << "Pattern : " << Results[I].Rank << " : "
+ OS << "Pattern : "
<< Results[I].Pattern->getAsString() << '\n';
break;
}
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 0dbf21961fe9..bff47519a743 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -46,22 +46,6 @@ public:
// IdDeclInfo Implementation
//===----------------------------------------------------------------------===//
-/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
-/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
-/// be already added to the scope chain and must be in the same context as
-/// the decl that we want to add.
-void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D,
- NamedDecl *Shadow) {
- for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) {
- if (Shadow == *(I-1)) {
- Decls.insert(I-1, D);
- return;
- }
- }
-
- assert(0 && "Shadow wasn't in scope chain!");
-}
-
/// RemoveDecl - Remove the decl from the scope chain.
/// The decl must already be part of the decl chain.
void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) {
@@ -160,32 +144,6 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {
IDI->AddDecl(D);
}
-/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
-/// after the decl that the iterator points to, thus the 'Shadow' decl will be
-/// encountered before the 'D' decl.
-void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) {
- assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!");
-
- DeclarationName Name = D->getDeclName();
- void *Ptr = Name.getFETokenInfo<void>();
- assert(Ptr && "No decl from Ptr ?");
-
- IdDeclInfo *IDI;
-
- if (isDeclPtr(Ptr)) {
- Name.setFETokenInfo(NULL);
- IDI = &(*IdDeclInfos)[Name];
- NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
- assert(PrevD == Shadow && "Invalid shadow decl ?");
- IDI->AddDecl(D);
- IDI->AddDecl(PrevD);
- return;
- }
-
- IDI = toIdDeclInfo(Ptr);
- IDI->AddShadowed(D, Shadow);
-}
-
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
/// The decl must already be part of the decl chain.
void IdentifierResolver::RemoveDecl(NamedDecl *D) {
diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h
index 65f3256c2138..59bd834073f3 100644
--- a/lib/Sema/IdentifierResolver.h
+++ b/lib/Sema/IdentifierResolver.h
@@ -41,12 +41,6 @@ class IdentifierResolver {
void AddDecl(NamedDecl *D) { Decls.push_back(D); }
- /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl.
- /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must
- /// be already added to the scope chain and must be in the same context as
- /// the decl that we want to add.
- void AddShadowed(NamedDecl *D, NamedDecl *Shadow);
-
/// RemoveDecl - Remove the decl from the scope chain.
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
@@ -163,11 +157,6 @@ public:
/// AddDecl - Link the decl to its shadowed decl chain.
void AddDecl(NamedDecl *D);
- /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it
- /// after the decl that the iterator points to, thus the 'Shadow' decl will be
- /// encountered before the 'D' decl.
- void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow);
-
/// RemoveDecl - Unlink the decl from its shadowed decl chain.
/// The decl must already be part of the decl chain.
void RemoveDecl(NamedDecl *D);
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index c5eecdac48e8..9064de6aa019 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -32,6 +32,11 @@ public:
/// @brief No entity found met the criteria.
NotFound = 0,
+ /// @brief No entity found met the criteria within the current
+ /// instantiation,, but there were dependent base classes of the
+ /// current instantiation that could not be searched.
+ NotFoundInCurrentInstantiation,
+
/// @brief Name lookup found a single declaration that met the
/// criteria. getFoundDecl() will return this declaration.
Found,
@@ -268,6 +273,19 @@ public:
Decls.set_size(N);
}
+ /// \brief Determine whether no result was found because we could not
+ /// search into dependent base classes of the current instantiation.
+ bool wasNotFoundInCurrentInstantiation() const {
+ return ResultKind == NotFoundInCurrentInstantiation;
+ }
+
+ /// \brief Note that while no result was found in the current instantiation,
+ /// there were dependent base classes that could not be searched.
+ void setNotFoundInCurrentInstantiation() {
+ assert(ResultKind == NotFound && Decls.empty());
+ ResultKind = NotFoundInCurrentInstantiation;
+ }
+
/// \brief Resolves the result kind of the lookup, possibly hiding
/// decls.
///
@@ -278,9 +296,10 @@ public:
/// \brief Re-resolves the result kind of the lookup after a set of
/// removals has been performed.
void resolveKindAfterFilter() {
- if (Decls.empty())
- ResultKind = NotFound;
- else {
+ if (Decls.empty()) {
+ if (ResultKind != NotFoundInCurrentInstantiation)
+ ResultKind = NotFound;
+ } else {
ResultKind = Found;
resolveKind();
}
@@ -524,7 +543,11 @@ private:
///
/// \param Hiding a declaration that hides the declaration \p ND,
/// or NULL if no such declaration exists.
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding) = 0;
+ ///
+ /// \param InBaseClass whether this declaration was found in base
+ /// class of the context we searched.
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+ bool InBaseClass) = 0;
};
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 40ad90a129e7..171101bb96de 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "TargetAttributesSema.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/APFloat.h"
#include "clang/AST/ASTConsumer.h"
@@ -109,6 +110,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT,
if (isa<VectorType>(Underlying))
break;
+ // Don't desugar through the primary typedef of an anonymous type.
+ if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
+ if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
+ cast<TypedefType>(QT)->getDecl())
+ break;
+
// Otherwise, we're tearing through something opaque; note that
// we'll eventually need an a.k.a. clause and keep going.
AKA = true;
@@ -347,7 +354,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit,
CodeCompleteConsumer *CodeCompleter)
- : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
+ : TheTargetAttributesSema(0),
+ LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
CurBlock(0), PackContext(0), ParsingDeclDepth(0),
@@ -368,313 +376,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
}
-/// Retrieves the width and signedness of the given integer type,
-/// or returns false if it is not an integer type.
-///
-/// \param T must be canonical
-static bool getIntProperties(ASTContext &C, const Type *T,
- unsigned &BitWidth, bool &Signed) {
- assert(T->isCanonicalUnqualified());
-
- if (const VectorType *VT = dyn_cast<VectorType>(T))
- T = VT->getElementType().getTypePtr();
- if (const ComplexType *CT = dyn_cast<ComplexType>(T))
- T = CT->getElementType().getTypePtr();
-
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
- if (!BT->isInteger()) return false;
-
- BitWidth = C.getIntWidth(QualType(T, 0));
- Signed = BT->isSignedInteger();
- return true;
- }
-
- return false;
-}
-
-/// Checks whether the given value will have the same value if it it
-/// is truncated to the given width, then extended back to the
-/// original width.
-static bool IsSameIntAfterCast(const llvm::APSInt &value,
- unsigned TargetWidth) {
- unsigned SourceWidth = value.getBitWidth();
- llvm::APSInt truncated = value;
- truncated.trunc(TargetWidth);
- truncated.extend(SourceWidth);
- return (truncated == value);
-}
-
-/// Checks whether the given value will have the same value if it
-/// is truncated to the given width, then extended back to the original
-/// width.
-///
-/// The value might be a vector or a complex.
-static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) {
- if (value.isInt())
- return IsSameIntAfterCast(value.getInt(), TargetWidth);
-
- if (value.isVector()) {
- for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
- if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth))
- return false;
- return true;
- }
-
- if (value.isComplexInt()) {
- return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) &&
- IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth);
- }
-
- // This can happen with lossless casts to intptr_t of "based" lvalues.
- // Assume it might use arbitrary bits.
- assert(value.isLValue());
- return false;
-}
-
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-static bool IsSameFloatAfterCast(const llvm::APFloat &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
- llvm::APFloat truncated = value;
-
- bool ignored;
- truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
- truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
-
- return truncated.bitwiseIsEqual(value);
-}
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-///
-/// The value might be a vector of floats (or a complex number).
-static bool IsSameFloatAfterCast(const APValue &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
- if (value.isFloat())
- return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
-
- if (value.isVector()) {
- for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
- if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
- return false;
- return true;
- }
-
- assert(value.isComplexFloat());
- return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
- IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
-}
-
-/// Determines if it's reasonable for the given expression to be truncated
-/// down to the given integer width.
-/// * Boolean expressions are automatically white-listed.
-/// * Arithmetic operations on implicitly-promoted operands of the
-/// target width or less are okay --- not because the results are
-/// actually guaranteed to fit within the width, but because the
-/// user is effectively pretending that the operations are closed
-/// within the implicitly-promoted type.
-static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) {
- E = E->IgnoreParens();
-
-#ifndef NDEBUG
- {
- const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
- unsigned EWidth;
- bool ESigned;
-
- if (!getIntProperties(C, ETy, EWidth, ESigned))
- assert(0 && "expression not of integer type");
-
- // The caller should never let this happen.
- assert(EWidth > Width && "called on expr whose type is too small");
- }
-#endif
-
- // Strip implicit casts off.
- while (isa<ImplicitCastExpr>(E)) {
- E = cast<ImplicitCastExpr>(E)->getSubExpr();
-
- const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr();
-
- unsigned EWidth;
- bool ESigned;
- if (!getIntProperties(C, ETy, EWidth, ESigned))
- return false;
-
- if (EWidth <= Width)
- return true;
- }
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- switch (BO->getOpcode()) {
-
- // Boolean-valued operations are white-listed.
- case BinaryOperator::LAnd:
- case BinaryOperator::LOr:
- case BinaryOperator::LT:
- case BinaryOperator::GT:
- case BinaryOperator::LE:
- case BinaryOperator::GE:
- case BinaryOperator::EQ:
- case BinaryOperator::NE:
- return true;
-
- // Operations with opaque sources are black-listed.
- case BinaryOperator::PtrMemD:
- case BinaryOperator::PtrMemI:
- return false;
-
- // Left shift gets black-listed based on a judgement call.
- case BinaryOperator::Shl:
- return false;
-
- // Various special cases.
- case BinaryOperator::Shr:
- return IsExprValueWithinWidth(C, BO->getLHS(), Width);
- case BinaryOperator::Comma:
- return IsExprValueWithinWidth(C, BO->getRHS(), Width);
- case BinaryOperator::Sub:
- if (BO->getLHS()->getType()->isPointerType())
- return false;
- // fallthrough
-
- // Any other operator is okay if the operands are
- // promoted from expressions of appropriate size.
- default:
- return IsExprValueWithinWidth(C, BO->getLHS(), Width) &&
- IsExprValueWithinWidth(C, BO->getRHS(), Width);
- }
- }
-
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
- switch (UO->getOpcode()) {
- // Boolean-valued operations are white-listed.
- case UnaryOperator::LNot:
- return true;
-
- // Operations with opaque sources are black-listed.
- case UnaryOperator::Deref:
- case UnaryOperator::AddrOf: // should be impossible
- return false;
-
- case UnaryOperator::OffsetOf:
- return false;
-
- default:
- return IsExprValueWithinWidth(C, UO->getSubExpr(), Width);
- }
- }
-
- // Don't diagnose if the expression is an integer constant
- // whose value in the target type is the same as it was
- // in the original type.
- Expr::EvalResult result;
- if (E->Evaluate(result, C))
- if (IsSameIntAfterCast(result.Val, Width))
- return true;
-
- return false;
-}
-
-/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
- S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
-}
-
-/// Implements -Wconversion.
-static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) {
- // Don't diagnose in unevaluated contexts.
- if (S.ExprEvalContexts.back().Context == Sema::Unevaluated)
- return;
-
- // Don't diagnose for value-dependent expressions.
- if (E->isValueDependent())
- return;
-
- const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
- const Type *Target = S.Context.getCanonicalType(T).getTypePtr();
-
- // Never diagnose implicit casts to bool.
- if (Target->isSpecificBuiltinType(BuiltinType::Bool))
- return;
-
- // Strip vector types.
- if (isa<VectorType>(Source)) {
- if (!isa<VectorType>(Target))
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar);
-
- Source = cast<VectorType>(Source)->getElementType().getTypePtr();
- Target = cast<VectorType>(Target)->getElementType().getTypePtr();
- }
-
- // Strip complex types.
- if (isa<ComplexType>(Source)) {
- if (!isa<ComplexType>(Target))
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar);
-
- Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
- Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
- }
-
- const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
- const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
-
- // If the source is floating point...
- if (SourceBT && SourceBT->isFloatingPoint()) {
- // ...and the target is floating point...
- if (TargetBT && TargetBT->isFloatingPoint()) {
- // ...then warn if we're dropping FP rank.
-
- // Builtin FP kinds are ordered by increasing FP rank.
- if (SourceBT->getKind() > TargetBT->getKind()) {
- // Don't warn about float constants that are precisely
- // representable in the target type.
- Expr::EvalResult result;
- if (E->Evaluate(result, S.Context)) {
- // Value might be a float, a float vector, or a float complex.
- if (IsSameFloatAfterCast(result.Val,
- S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
- S.Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
- return;
- }
-
- DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision);
- }
- return;
- }
-
- // If the target is integral, always warn.
- if ((TargetBT && TargetBT->isInteger()))
- // TODO: don't warn for integer values?
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer);
-
- return;
- }
-
- unsigned SourceWidth, TargetWidth;
- bool SourceSigned, TargetSigned;
-
- if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) ||
- !getIntProperties(S.Context, Target, TargetWidth, TargetSigned))
- return;
-
- if (SourceWidth > TargetWidth) {
- if (IsExprValueWithinWidth(S.Context, E, TargetWidth))
- return;
-
- // People want to build with -Wshorten-64-to-32 and not -Wconversion
- // and by god we'll let them.
- if (SourceWidth == 64 && TargetWidth == 32)
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32);
- return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision);
- }
-
- return;
+Sema::~Sema() {
+ if (PackContext) FreePackedContext();
+ delete TheTargetAttributesSema;
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
@@ -697,7 +401,7 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
}
}
- CheckImplicitConversion(*this, Expr, Ty);
+ CheckImplicitConversion(Expr, Ty);
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4cecee46e468..fab729299936 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -42,6 +42,7 @@ namespace llvm {
}
namespace clang {
+ class AnalysisContext;
class ASTContext;
class ASTConsumer;
class CodeCompleteConsumer;
@@ -101,6 +102,7 @@ namespace clang {
class InitializationKind;
class InitializationSequence;
class VisibleDeclConsumer;
+ class TargetAttributesSema;
/// BlockSemaInfo - When a block is being parsed, this contains information
/// about the block. It is pointed to from Sema::CurBlock.
@@ -176,6 +178,7 @@ public:
class Sema : public Action {
Sema(const Sema&); // DO NOT IMPLEMENT
void operator=(const Sema&); // DO NOT IMPLEMENT
+ mutable const TargetAttributesSema* TheTargetAttributesSema;
public:
const LangOptions &LangOpts;
Preprocessor &PP;
@@ -426,13 +429,12 @@ public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit = true,
CodeCompleteConsumer *CompletionConsumer = 0);
- ~Sema() {
- if (PackContext) FreePackedContext();
- }
+ ~Sema();
const LangOptions &getLangOptions() const { return LangOpts; }
Diagnostic &getDiagnostics() const { return Diags; }
SourceManager &getSourceManager() const { return SourceMgr; }
+ const TargetAttributesSema &getTargetAttributesSema() const;
/// \brief Helper class that creates diagnostics with optional
/// template instantiation stacks.
@@ -561,8 +563,6 @@ public:
const FunctionProtoType *Target, SourceLocation TargetLoc,
const FunctionProtoType *Source, SourceLocation SourceLoc);
- QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D);
-
bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
@@ -1030,10 +1030,25 @@ public:
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
+
+ enum OverloadCandidateDisplayKind {
+ /// Requests that all candidates be shown. Viable candidates will
+ /// be printed first.
+ OCD_AllCandidates,
+
+ /// Requests that only viable candidates be shown.
+ OCD_ViableCandidates
+ };
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable,
- const char *Opc=0,
- SourceLocation Loc=SourceLocation());
+ OverloadCandidateDisplayKind OCD,
+ Expr **Args, unsigned NumArgs,
+ const char *Opc = 0,
+ SourceLocation Loc = SourceLocation());
+
+ void NoteOverloadCandidate(FunctionDecl *Fn);
+ void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS,
+ SourceLocation CaretLoc,
+ const PartialDiagnostic &PDiag);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
@@ -1083,6 +1098,9 @@ public:
OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc);
+ /// CheckUnreachable - Check for unreachable code.
+ void CheckUnreachable(AnalysisContext &);
+
/// CheckCallReturnType - Checks that a call expression's return type is
/// complete. Returns true on failure. The location passed in is the location
/// that best represents the call.
@@ -1090,14 +1108,14 @@ public:
CallExpr *CE, FunctionDecl *FD);
/// Helpers for dealing with blocks and functions.
- void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
- void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
+ void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &);
+ void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
- ControlFlowKind CheckFallThrough(Stmt *);
+ ControlFlowKind CheckFallThrough(AnalysisContext &);
Scope *getNonFieldDeclScope(Scope *S);
@@ -1168,8 +1186,14 @@ public:
LookupObjCImplementationName
};
+ /// \brief Specifies whether (or how) name lookup is being performed for a
+ /// redeclaration (vs. a reference).
enum RedeclarationKind {
- NotForRedeclaration,
+ /// \brief The lookup is a reference to this name that is not for the
+ /// purpose of redeclaring the name.
+ NotForRedeclaration = 0,
+ /// \brief The lookup results will be used for redeclaration of a name,
+ /// if an entity by that name already exists.
ForRedeclaration
};
@@ -1188,7 +1212,8 @@ public:
= NotForRedeclaration);
bool LookupName(LookupResult &R, Scope *S,
bool AllowBuiltinCreation = false);
- bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx);
+ bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ bool InUnqualifiedLookup = false);
bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
bool AllowBuiltinCreation = false,
bool EnteringContext = false);
@@ -1210,7 +1235,8 @@ public:
bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS,
DeclContext *MemberContext = 0,
- bool EnteringContext = false);
+ bool EnteringContext = false,
+ const ObjCObjectPointerType *OPT = 0);
void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
AssociatedNamespaceSet &AssociatedNamespaces,
@@ -1219,7 +1245,8 @@ public:
bool DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
- ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
+ ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id,
+ SourceLocation RecoverLoc = SourceLocation());
NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
Scope *S, bool ForRedeclaration,
SourceLocation Loc);
@@ -1383,7 +1410,8 @@ public:
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ bool MSAsm = false);
virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
SourceLocation RParen,
@@ -1437,10 +1465,6 @@ public:
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
- const PartialDiagnostic &PD,
- bool Equality = false);
-
virtual void
PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
@@ -1462,7 +1486,8 @@ public:
OwningExprResult LookupInObjCMethod(LookupResult &R,
Scope *S,
- IdentifierInfo *II);
+ IdentifierInfo *II,
+ bool AllowBuiltinCreation=false);
OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS,
DeclarationName Name,
@@ -1571,13 +1596,13 @@ public:
QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
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,
@@ -2008,6 +2033,7 @@ public:
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
+ bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS);
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
@@ -2175,11 +2201,11 @@ public:
void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor);
/// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual
- /// members might need to be marked as referenced. This is either done when
- /// the key function definition is emitted (this is handled by by
- /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit
- /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers).
- std::map<CXXRecordDecl *, SourceLocation> ClassesWithUnmarkedVirtualMembers;
+ /// members need to be marked as referenced at the end of the translation
+ /// unit. It will contain polymorphic classes that do not have a key
+ /// function or have a key function that has been defined.
+ llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4>
+ ClassesWithUnmarkedVirtualMembers;
/// MaybeMarkVirtualMembersReferenced - If the passed in method is the
/// key function of the record decl, will mark virtual member functions as
@@ -2236,8 +2262,6 @@ public:
void CheckConversionDeclarator(Declarator &D, QualType &R,
FunctionDecl::StorageClass& SC);
DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
-
- bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType);
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -2338,6 +2362,8 @@ public:
bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl);
+ bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl);
+
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
@@ -2350,6 +2376,14 @@ public:
TypeTy *ObjectType,
bool EnteringContext,
TemplateTy &Template);
+
+ virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TemplateTy &SuggestedTemplate,
+ TemplateNameKind &SuggestedKind);
+
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
@@ -3348,10 +3382,11 @@ public:
void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
ObjCProtocolDecl *PDecl);
- virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
- DeclPtrTy *allMethods = 0, unsigned allNum = 0,
- DeclPtrTy *allProperties = 0, unsigned pNum = 0,
- DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+ virtual void ActOnAtEnd(SourceRange AtEnd,
+ DeclPtrTy classDecl,
+ DeclPtrTy *allMethods = 0, unsigned allNum = 0,
+ DeclPtrTy *allProperties = 0, unsigned pNum = 0,
+ DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc,
FieldDeclarator &FD, ObjCDeclSpec &ODS,
@@ -3617,9 +3652,6 @@ public:
bool PerformImplicitConversion(Expr *&From, QualType ToType,
const StandardConversionSequence& SCS,
AssignmentAction Action, bool IgnoreBaseAccess);
-
- bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
@@ -3629,7 +3661,8 @@ public:
QualType CheckPointerToMemberOperands( // C++ 5.5
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign,
+ bool isDivide);
QualType CheckRemainderOperands( // C99 6.5.5
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
QualType CheckAdditionOperands( // C99 6.5.6
@@ -3801,7 +3834,8 @@ public:
/// \name Code completion
//@{
- virtual void CodeCompleteOrdinaryName(Scope *S);
+ virtual void CodeCompleteOrdinaryName(Scope *S,
+ CodeCompletionContext CompletionContext);
virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base,
SourceLocation OpLoc,
bool IsArrow);
@@ -3819,6 +3853,7 @@ public:
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
bool InInterface);
+ virtual void CodeCompleteObjCAtVisibility(Scope *S);
virtual void CodeCompleteObjCAtStatement(Scope *S);
virtual void CodeCompleteObjCAtExpression(Scope *S);
virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS);
@@ -3895,6 +3930,11 @@ private:
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+ void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
+ const PartialDiagnostic &PD,
+ bool Equality = false);
+ void CheckImplicitConversion(Expr *E, QualType Target);
+
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 800c544d3364..f924bd3bb121 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -893,7 +893,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
/*InOverloadResolution=*/false,
/*one of user provided casts*/true);
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ if (ICS.isBad())
return TC_NotApplicable;
// The conversion is possible, so commit to it.
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 82d58eab1aad..8594583ec3ef 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -210,6 +210,28 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
return getCurrentInstantiationOf(NNS) == 0;
}
+/// \brief Determine whether the given scope specifier refers to a
+/// current instantiation that has any dependent base clases.
+///
+/// This check is typically used when we've performed lookup into the
+/// current instantiation of a template, but that lookup failed. When
+/// there are dependent bases present, however, the lookup needs to be
+/// delayed until template instantiation time.
+bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) {
+ if (!SS.isSet())
+ return false;
+
+ NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep();
+ if (!NNS->isDependent())
+ return false;
+
+ CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS);
+ if (!CurrentInstantiation)
+ return false;
+
+ return CurrentInstantiation->hasAnyDependentBases();
+}
+
/// \brief If the given nested name specifier refers to the current
/// instantiation, return the declaration that corresponds to that
/// current instantiation (C++0x [temp.dep.type]p1).
@@ -446,6 +468,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
<< Name << Found.getLookupName()
<< CodeModificationHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
+
+ if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
} else
Found.clear();
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f10fa07d8607..5f124e457223 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -318,7 +319,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
// Determine the index of the size.
unsigned SizeIndex;
- switch (Context.getTypeSize(ValType)/8) {
+ switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
case 1: SizeIndex = 0; break;
case 2: SizeIndex = 1; break;
case 4: SizeIndex = 2; break;
@@ -966,9 +967,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
///
/// (8) Check that the format string is a wide literal.
///
-/// (9) Also check the arguments of functions with the __format__ attribute.
-/// (TODO).
-///
/// All of these checks can be done by parsing the format string.
///
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
@@ -1559,3 +1557,475 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
Diag(loc, diag::warn_floatingpoint_eq)
<< lex->getSourceRange() << rex->getSourceRange();
}
+
+//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
+//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===//
+
+namespace {
+
+/// Structure recording the 'active' range of an integer-valued
+/// expression.
+struct IntRange {
+ /// The number of bits active in the int.
+ unsigned Width;
+
+ /// True if the int is known not to have negative values.
+ bool NonNegative;
+
+ IntRange() {}
+ IntRange(unsigned Width, bool NonNegative)
+ : Width(Width), NonNegative(NonNegative)
+ {}
+
+ // Returns the range of the bool type.
+ static IntRange forBoolType() {
+ return IntRange(1, true);
+ }
+
+ // Returns the range of an integral type.
+ static IntRange forType(ASTContext &C, QualType T) {
+ return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr());
+ }
+
+ // Returns the range of an integeral type based on its canonical
+ // representation.
+ static IntRange forCanonicalType(ASTContext &C, const Type *T) {
+ assert(T->isCanonicalUnqualified());
+
+ if (const VectorType *VT = dyn_cast<VectorType>(T))
+ T = VT->getElementType().getTypePtr();
+ if (const ComplexType *CT = dyn_cast<ComplexType>(T))
+ T = CT->getElementType().getTypePtr();
+ if (const EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType().getTypePtr();
+
+ const BuiltinType *BT = cast<BuiltinType>(T);
+ assert(BT->isInteger());
+
+ return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
+ }
+
+ // Returns the supremum of two ranges: i.e. their conservative merge.
+ static IntRange join(const IntRange &L, const IntRange &R) {
+ return IntRange(std::max(L.Width, R.Width),
+ L.NonNegative && R.NonNegative);
+ }
+
+ // Returns the infinum of two ranges: i.e. their aggressive merge.
+ static IntRange meet(const IntRange &L, const IntRange &R) {
+ return IntRange(std::min(L.Width, R.Width),
+ L.NonNegative || R.NonNegative);
+ }
+};
+
+IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
+ if (value.isSigned() && value.isNegative())
+ return IntRange(value.getMinSignedBits(), false);
+
+ if (value.getBitWidth() > MaxWidth)
+ value.trunc(MaxWidth);
+
+ // isNonNegative() just checks the sign bit without considering
+ // signedness.
+ return IntRange(value.getActiveBits(), true);
+}
+
+IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
+ unsigned MaxWidth) {
+ if (result.isInt())
+ return GetValueRange(C, result.getInt(), MaxWidth);
+
+ if (result.isVector()) {
+ IntRange R = GetValueRange(C, result.getVectorElt(0), Ty, MaxWidth);
+ for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) {
+ IntRange El = GetValueRange(C, result.getVectorElt(i), Ty, MaxWidth);
+ R = IntRange::join(R, El);
+ }
+ return R;
+ }
+
+ if (result.isComplexInt()) {
+ IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth);
+ IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth);
+ return IntRange::join(R, I);
+ }
+
+ // This can happen with lossless casts to intptr_t of "based" lvalues.
+ // Assume it might use arbitrary bits.
+ // FIXME: The only reason we need to pass the type in here is to get
+ // the sign right on this one case. It would be nice if APValue
+ // preserved this.
+ assert(result.isLValue());
+ return IntRange(MaxWidth, Ty->isUnsignedIntegerType());
+}
+
+/// Pseudo-evaluate the given integer expression, estimating the
+/// range of values it might take.
+///
+/// \param MaxWidth - the width to which the value will be truncated
+IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
+ E = E->IgnoreParens();
+
+ // Try a full evaluation first.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, C))
+ return GetValueRange(C, result.Val, E->getType(), MaxWidth);
+
+ // I think we only want to look through implicit casts here; if the
+ // user has an explicit widening cast, we should treat the value as
+ // being of the new, wider type.
+ if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (CE->getCastKind() == CastExpr::CK_NoOp)
+ return GetExprRange(C, CE->getSubExpr(), MaxWidth);
+
+ IntRange OutputTypeRange = IntRange::forType(C, CE->getType());
+
+ bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast);
+ if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown)
+ isIntegerCast = CE->getSubExpr()->getType()->isIntegerType();
+
+ // Assume that non-integer casts can span the full range of the type.
+ if (!isIntegerCast)
+ return OutputTypeRange;
+
+ IntRange SubRange
+ = GetExprRange(C, CE->getSubExpr(),
+ std::min(MaxWidth, OutputTypeRange.Width));
+
+ // Bail out if the subexpr's range is as wide as the cast type.
+ if (SubRange.Width >= OutputTypeRange.Width)
+ return OutputTypeRange;
+
+ // Otherwise, we take the smaller width, and we're non-negative if
+ // either the output type or the subexpr is.
+ return IntRange(SubRange.Width,
+ SubRange.NonNegative || OutputTypeRange.NonNegative);
+ }
+
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ // If we can fold the condition, just take that operand.
+ bool CondResult;
+ if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
+ return GetExprRange(C, CondResult ? CO->getTrueExpr()
+ : CO->getFalseExpr(),
+ MaxWidth);
+
+ // Otherwise, conservatively merge.
+ IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth);
+ IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth);
+ return IntRange::join(L, R);
+ }
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+
+ // Boolean-valued operations are single-bit and positive.
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ return IntRange::forBoolType();
+
+ // Operations with opaque sources are black-listed.
+ case BinaryOperator::PtrMemD:
+ case BinaryOperator::PtrMemI:
+ return IntRange::forType(C, E->getType());
+
+ // Bitwise-and uses the *infinum* of the two source ranges.
+ case BinaryOperator::And:
+ return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
+ GetExprRange(C, BO->getRHS(), MaxWidth));
+
+ // Left shift gets black-listed based on a judgement call.
+ case BinaryOperator::Shl:
+ return IntRange::forType(C, E->getType());
+
+ // Right shift by a constant can narrow its left argument.
+ case BinaryOperator::Shr: {
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+
+ // If the shift amount is a positive constant, drop the width by
+ // that much.
+ llvm::APSInt shift;
+ if (BO->getRHS()->isIntegerConstantExpr(shift, C) &&
+ shift.isNonNegative()) {
+ unsigned zext = shift.getZExtValue();
+ if (zext >= L.Width)
+ L.Width = (L.NonNegative ? 0 : 1);
+ else
+ L.Width -= zext;
+ }
+
+ return L;
+ }
+
+ // Comma acts as its right operand.
+ case BinaryOperator::Comma:
+ return GetExprRange(C, BO->getRHS(), MaxWidth);
+
+ // Black-list pointer subtractions.
+ case BinaryOperator::Sub:
+ if (BO->getLHS()->getType()->isPointerType())
+ return IntRange::forType(C, E->getType());
+ // fallthrough
+
+ default:
+ break;
+ }
+
+ // Treat every other operator as if it were closed on the
+ // narrowest type that encompasses both operands.
+ IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+ IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
+ return IntRange::join(L, R);
+ }
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ switch (UO->getOpcode()) {
+ // Boolean-valued operations are white-listed.
+ case UnaryOperator::LNot:
+ return IntRange::forBoolType();
+
+ // Operations with opaque sources are black-listed.
+ case UnaryOperator::Deref:
+ case UnaryOperator::AddrOf: // should be impossible
+ case UnaryOperator::OffsetOf:
+ return IntRange::forType(C, E->getType());
+
+ default:
+ return GetExprRange(C, UO->getSubExpr(), MaxWidth);
+ }
+ }
+
+ FieldDecl *BitField = E->getBitField();
+ if (BitField) {
+ llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
+ unsigned BitWidth = BitWidthAP.getZExtValue();
+
+ return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType());
+ }
+
+ return IntRange::forType(C, E->getType());
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ llvm::APFloat truncated = value;
+
+ bool ignored;
+ truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
+ truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
+
+ return truncated.bitwiseIsEqual(value);
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+///
+/// The value might be a vector of floats (or a complex number).
+bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
+ if (value.isFloat())
+ return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+
+ if (value.isVector()) {
+ for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+ if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
+ return false;
+ return true;
+ }
+
+ assert(value.isComplexFloat());
+ return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
+ IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
+}
+
+} // end anonymous namespace
+
+/// \brief Implements -Wsign-compare.
+///
+/// \param lex the left-hand expression
+/// \param rex the right-hand expression
+/// \param OpLoc the location of the joining operator
+/// \param Equality whether this is an "equality-like" join, which
+/// suppresses the warning in some cases
+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 (ExprEvalContexts.back().Context == Unevaluated)
+ return;
+
+ // If either expression is value-dependent, don't warn. We'll get another
+ // chance at instantiation time.
+ if (lex->isValueDependent() || rex->isValueDependent())
+ return;
+
+ QualType lt = lex->getType(), rt = rex->getType();
+
+ // Only warn if both operands are integral.
+ if (!lt->isIntegerType() || !rt->isIntegerType())
+ return;
+
+ // In C, the width of a bitfield determines its type, and the
+ // declared type only contributes the signedness. This duplicates
+ // the work that will later be done by UsualUnaryConversions.
+ // Eventually, this check will be reorganized in a way that avoids
+ // this duplication.
+ if (!getLangOptions().CPlusPlus) {
+ QualType tmp;
+ tmp = Context.isPromotableBitField(lex);
+ if (!tmp.isNull()) lt = tmp;
+ tmp = Context.isPromotableBitField(rex);
+ if (!tmp.isNull()) rt = tmp;
+ }
+
+ // The rule is that the signed operand becomes unsigned, so isolate the
+ // signed operand.
+ Expr *signedOperand = lex, *unsignedOperand = rex;
+ QualType signedType = lt, unsignedType = rt;
+ if (lt->isSignedIntegerType()) {
+ if (rt->isSignedIntegerType()) return;
+ } else {
+ if (!rt->isSignedIntegerType()) return;
+ std::swap(signedOperand, unsignedOperand);
+ std::swap(signedType, unsignedType);
+ }
+
+ unsigned unsignedWidth = Context.getIntWidth(unsignedType);
+ unsigned signedWidth = Context.getIntWidth(signedType);
+
+ // If the unsigned type is strictly smaller than the signed type,
+ // then (1) the result type will be signed and (2) the unsigned
+ // value will fit fully within the signed type, and thus the result
+ // of the comparison will be exact.
+ if (signedWidth > unsignedWidth)
+ return;
+
+ // Otherwise, calculate the effective ranges.
+ IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth);
+ IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth);
+
+ // We should never be unable to prove that the unsigned operand is
+ // non-negative.
+ assert(unsignedRange.NonNegative && "unsigned range includes negative?");
+
+ // If the signed operand is non-negative, then the signed->unsigned
+ // conversion won't change it.
+ if (signedRange.NonNegative)
+ return;
+
+ // For (in)equality comparisons, if the unsigned operand is a
+ // constant which cannot collide with a overflowed signed operand,
+ // then reinterpreting the signed operand as unsigned will not
+ // change the result of the comparison.
+ if (Equality && unsignedRange.Width < unsignedWidth)
+ return;
+
+ Diag(OpLoc, PD)
+ << lt << rt << lex->getSourceRange() << rex->getSourceRange();
+}
+
+/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
+static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) {
+ S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange();
+}
+
+/// Implements -Wconversion.
+void Sema::CheckImplicitConversion(Expr *E, QualType T) {
+ // Don't diagnose in unevaluated contexts.
+ if (ExprEvalContexts.back().Context == Sema::Unevaluated)
+ return;
+
+ // Don't diagnose for value-dependent expressions.
+ if (E->isValueDependent())
+ return;
+
+ const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
+ const Type *Target = Context.getCanonicalType(T).getTypePtr();
+
+ // Never diagnose implicit casts to bool.
+ if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+
+ // Strip vector types.
+ if (isa<VectorType>(Source)) {
+ if (!isa<VectorType>(Target))
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar);
+
+ Source = cast<VectorType>(Source)->getElementType().getTypePtr();
+ Target = cast<VectorType>(Target)->getElementType().getTypePtr();
+ }
+
+ // Strip complex types.
+ if (isa<ComplexType>(Source)) {
+ if (!isa<ComplexType>(Target))
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar);
+
+ Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
+ Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
+ }
+
+ const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
+ const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
+
+ // If the source is floating point...
+ if (SourceBT && SourceBT->isFloatingPoint()) {
+ // ...and the target is floating point...
+ if (TargetBT && TargetBT->isFloatingPoint()) {
+ // ...then warn if we're dropping FP rank.
+
+ // Builtin FP kinds are ordered by increasing FP rank.
+ if (SourceBT->getKind() > TargetBT->getKind()) {
+ // Don't warn about float constants that are precisely
+ // representable in the target type.
+ Expr::EvalResult result;
+ if (E->Evaluate(result, Context)) {
+ // Value might be a float, a float vector, or a float complex.
+ if (IsSameFloatAfterCast(result.Val,
+ Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+ Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+ return;
+ }
+
+ DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision);
+ }
+ return;
+ }
+
+ // If the target is integral, always warn.
+ if ((TargetBT && TargetBT->isInteger()))
+ // TODO: don't warn for integer values?
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer);
+
+ return;
+ }
+
+ if (!Source->isIntegerType() || !Target->isIntegerType())
+ return;
+
+ IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType()));
+ IntRange TargetRange = IntRange::forCanonicalType(Context, Target);
+
+ // FIXME: also signed<->unsigned?
+
+ if (SourceRange.Width > TargetRange.Width) {
+ // People want to build with -Wshorten-64-to-32 and not -Wconversion
+ // and by god we'll let them.
+ if (SourceRange.Width == 64 && TargetRange.Width == 32)
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32);
+ return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision);
+ }
+
+ return;
+}
+
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index ef82a941b5a5..a4cda014aae2 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -111,14 +112,18 @@ namespace {
/// \brief If non-NULL, a filter function used to remove any code-completion
/// results that are not desirable.
LookupFilter Filter;
-
+
+ /// \brief Whether we should allow declarations as
+ /// nested-name-specifiers that would otherwise be filtered out.
+ bool AllowNestedNameSpecifiers;
+
/// \brief A list of shadow maps, which is used to model name hiding at
/// different levels of, e.g., the inheritance hierarchy.
std::list<ShadowMap> ShadowMaps;
public:
explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0)
- : SemaRef(SemaRef), Filter(Filter) { }
+ : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { }
/// \brief Set the filter used for code-completion results.
void setFilter(LookupFilter Filter) {
@@ -133,15 +138,55 @@ namespace {
unsigned size() const { return Results.size(); }
bool empty() const { return Results.empty(); }
+ /// \brief Specify whether nested-name-specifiers are allowed.
+ void allowNestedNameSpecifiers(bool Allow = true) {
+ AllowNestedNameSpecifiers = Allow;
+ }
+
+ /// \brief Determine whether the given declaration is at all interesting
+ /// as a code-completion result.
+ ///
+ /// \param ND the declaration that we are inspecting.
+ ///
+ /// \param AsNestedNameSpecifier will be set true if this declaration is
+ /// only interesting when it is a nested-name-specifier.
+ bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const;
+
+ /// \brief Check whether the result is hidden by the Hiding declaration.
+ ///
+ /// \returns true if the result is hidden and cannot be found, false if
+ /// the hidden result could still be found. When false, \p R may be
+ /// modified to describe how the result can be found (e.g., via extra
+ /// qualification).
+ bool CheckHiddenResult(Result &R, DeclContext *CurContext,
+ NamedDecl *Hiding);
+
/// \brief Add a new result to this result set (if it isn't already in one
/// of the shadow maps), or replace an existing result (for, e.g., a
/// redeclaration).
///
- /// \param R the result to add (if it is unique).
+ /// \param CurContext the result to add (if it is unique).
///
/// \param R the context in which this result will be named.
void MaybeAddResult(Result R, DeclContext *CurContext = 0);
+ /// \brief Add a new result to this result set, where we already know
+ /// the hiding declation (if any).
+ ///
+ /// \param R the result to add (if it is unique).
+ ///
+ /// \param CurContext the context in which this result will be named.
+ ///
+ /// \param Hiding the declaration that hides the result.
+ ///
+ /// \param InBaseClass whether the result was found in a base
+ /// class of the searched context.
+ void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding,
+ bool InBaseClass);
+
+ /// \brief Add a new non-declaration result to this result set.
+ void AddResult(Result R);
+
/// \brief Enter into a new scope.
void EnterNewScope();
@@ -158,6 +203,7 @@ namespace {
///
//@{
bool IsOrdinaryName(NamedDecl *ND) const;
+ bool IsOrdinaryNonValueName(NamedDecl *ND) const;
bool IsNestedNameSpecifier(NamedDecl *ND) const;
bool IsEnum(NamedDecl *ND) const;
bool IsClassOrStruct(NamedDecl *ND) const;
@@ -166,6 +212,7 @@ namespace {
bool IsNamespaceOrAlias(NamedDecl *ND) const;
bool IsType(NamedDecl *ND) const;
bool IsMember(NamedDecl *ND) const;
+ bool IsObjCIvar(NamedDecl *ND) const;
//@}
};
}
@@ -259,31 +306,6 @@ ResultBuilder::ShadowMapEntry::end() const {
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
}
-/// \brief Determines whether the given hidden result could be found with
-/// some extra work, e.g., by qualifying the name.
-///
-/// \param Hidden the declaration that is hidden by the currenly \p Visible
-/// declaration.
-///
-/// \param Visible the declaration with the same name that is already visible.
-///
-/// \returns true if the hidden result can be found by some mechanism,
-/// false otherwise.
-static bool canHiddenResultBeFound(const LangOptions &LangOpts,
- NamedDecl *Hidden, NamedDecl *Visible) {
- // In C, there is no way to refer to a hidden name.
- if (!LangOpts.CPlusPlus)
- return false;
-
- DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext();
-
- // There is no way to qualify a name declared in a function or method.
- if (HiddenCtx->isFunctionOrMethod())
- return false;
-
- return HiddenCtx != Visible->getDeclContext()->getLookupContext();
-}
-
/// \brief Compute the qualification required to get from the current context
/// (\p CurContext) to the target context (\p TargetContext).
///
@@ -330,46 +352,37 @@ getRequiredQualification(ASTContext &Context,
return Result;
}
-void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
- assert(!ShadowMaps.empty() && "Must enter into a results scope");
-
- if (R.Kind != Result::RK_Declaration) {
- // For non-declaration results, just add the result.
- Results.push_back(R);
- return;
- }
+bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
+ bool &AsNestedNameSpecifier) const {
+ AsNestedNameSpecifier = false;
+
+ ND = ND->getUnderlyingDecl();
+ unsigned IDNS = ND->getIdentifierNamespace();
// Skip unnamed entities.
- if (!R.Declaration->getDeclName())
- return;
-
- // Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration))
- MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier),
- CurContext);
-
- Decl *CanonDecl = R.Declaration->getCanonicalDecl();
- unsigned IDNS = CanonDecl->getIdentifierNamespace();
+ if (!ND->getDeclName())
+ return false;
// Friend declarations and declarations introduced due to friends are never
// added as results.
- if (isa<FriendDecl>(CanonDecl) ||
+ if (isa<FriendDecl>(ND) ||
(IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)))
- return;
-
+ return false;
+
// Class template (partial) specializations are never added as results.
- if (isa<ClassTemplateSpecializationDecl>(CanonDecl) ||
- isa<ClassTemplatePartialSpecializationDecl>(CanonDecl))
- return;
+ if (isa<ClassTemplateSpecializationDecl>(ND) ||
+ isa<ClassTemplatePartialSpecializationDecl>(ND))
+ return false;
// Using declarations themselves are never added as results.
- if (isa<UsingDecl>(CanonDecl))
- return;
-
- if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) {
+ if (isa<UsingDecl>(ND))
+ return false;
+
+ // Some declarations have reserved names that we don't want to ever show.
+ if (const IdentifierInfo *Id = ND->getIdentifier()) {
// __va_list_tag is a freak of nature. Find it and skip it.
if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
- return;
+ return false;
// Filter out names reserved for the implementation (C99 7.1.3,
// C++ [lib.global.names]). Users don't need to see those.
@@ -379,18 +392,83 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
const char *Name = Id->getNameStart();
if (Name[0] == '_' &&
(Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
- return;
+ return false;
}
}
-
+
// C++ constructors are never found by name lookup.
- if (isa<CXXConstructorDecl>(CanonDecl))
- return;
+ if (isa<CXXConstructorDecl>(ND))
+ return false;
// Filter out any unwanted results.
- if (Filter && !(this->*Filter)(R.Declaration))
+ if (Filter && !(this->*Filter)(ND)) {
+ // Check whether it is interesting as a nested-name-specifier.
+ if (AllowNestedNameSpecifiers && SemaRef.getLangOptions().CPlusPlus &&
+ IsNestedNameSpecifier(ND) &&
+ (Filter != &ResultBuilder::IsMember ||
+ (isa<CXXRecordDecl>(ND) &&
+ cast<CXXRecordDecl>(ND)->isInjectedClassName()))) {
+ AsNestedNameSpecifier = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ // ... then it must be interesting!
+ return true;
+}
+
+bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,
+ NamedDecl *Hiding) {
+ // In C, there is no way to refer to a hidden name.
+ // FIXME: This isn't true; we can find a tag name hidden by an ordinary
+ // name if we introduce the tag type.
+ if (!SemaRef.getLangOptions().CPlusPlus)
+ return true;
+
+ DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getLookupContext();
+
+ // There is no way to qualify a name declared in a function or method.
+ if (HiddenCtx->isFunctionOrMethod())
+ return true;
+
+ if (HiddenCtx == Hiding->getDeclContext()->getLookupContext())
+ return true;
+
+ // We can refer to the result with the appropriate qualification. Do it.
+ R.Hidden = true;
+ R.QualifierIsInformative = false;
+
+ if (!R.Qualifier)
+ R.Qualifier = getRequiredQualification(SemaRef.Context,
+ CurContext,
+ R.Declaration->getDeclContext());
+ return false;
+}
+
+void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
+ assert(!ShadowMaps.empty() && "Must enter into a results scope");
+
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
return;
+ }
+
+ // Look through using declarations.
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext);
+ return;
+ }
+ Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ unsigned IDNS = CanonDecl->getIdentifierNamespace();
+
+ bool AsNestedNameSpecifier = false;
+ if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))
+ return;
+
ShadowMap &SMap = ShadowMaps.back();
ShadowMapEntry::iterator I, IEnd;
ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName());
@@ -406,9 +484,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// This is a redeclaration. Always pick the newer declaration.
Results[Index].Declaration = R.Declaration;
- // Pick the best rank of the two.
- Results[Index].Rank = std::min(Results[Index].Rank, R.Rank);
-
// We're done.
return;
}
@@ -440,21 +515,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
continue;
// The newly-added result is hidden by an entry in the shadow map.
- if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration,
- I->first)) {
- // Note that this result was hidden.
- R.Hidden = true;
- R.QualifierIsInformative = false;
-
- if (!R.Qualifier)
- R.Qualifier = getRequiredQualification(SemaRef.Context,
- CurContext,
- R.Declaration->getDeclContext());
- } else {
- // This result was hidden and cannot be found; don't bother adding
- // it.
+ if (CheckHiddenResult(R, CurContext, I->first))
return;
- }
break;
}
@@ -466,10 +528,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If the filter is for nested-name-specifiers, then this result starts a
// nested-name-specifier.
- if ((Filter == &ResultBuilder::IsNestedNameSpecifier) ||
- (Filter == &ResultBuilder::IsMember &&
- isa<CXXRecordDecl>(R.Declaration) &&
- cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName()))
+ if (AsNestedNameSpecifier)
R.StartsNestedNameSpecifier = true;
// If this result is supposed to have an informative qualifier, add one.
@@ -491,6 +550,63 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
Results.push_back(R);
}
+void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
+ NamedDecl *Hiding, bool InBaseClass = false) {
+ if (R.Kind != Result::RK_Declaration) {
+ // For non-declaration results, just add the result.
+ Results.push_back(R);
+ return;
+ }
+
+ // Look through using declarations.
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding);
+ return;
+ }
+
+ bool AsNestedNameSpecifier = false;
+ if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier))
+ return;
+
+ if (Hiding && CheckHiddenResult(R, CurContext, Hiding))
+ return;
+
+ // Make sure that any given declaration only shows up in the result set once.
+ if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()))
+ return;
+
+ // If the filter is for nested-name-specifiers, then this result starts a
+ // nested-name-specifier.
+ if (AsNestedNameSpecifier)
+ R.StartsNestedNameSpecifier = true;
+ else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass &&
+ isa<CXXRecordDecl>(R.Declaration->getDeclContext()
+ ->getLookupContext()))
+ R.QualifierIsInformative = true;
+
+ // If this result is supposed to have an informative qualifier, add one.
+ if (R.QualifierIsInformative && !R.Qualifier &&
+ !R.StartsNestedNameSpecifier) {
+ DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+ else
+ R.QualifierIsInformative = false;
+ }
+
+ // Insert this result into the set of results.
+ Results.push_back(R);
+}
+
+void ResultBuilder::AddResult(Result R) {
+ assert(R.Kind != Result::RK_Declaration &&
+ "Declaration results need more context");
+ Results.push_back(R);
+}
+
/// \brief Enter into a new scope.
void ResultBuilder::EnterNewScope() {
ShadowMaps.push_back(ShadowMap());
@@ -513,10 +629,23 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
unsigned IDNS = Decl::IDNS_Ordinary;
if (SemaRef.getLangOptions().CPlusPlus)
IDNS |= Decl::IDNS_Tag;
-
+ else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND))
+ return true;
+
return ND->getIdentifierNamespace() & IDNS;
}
+/// \brief Determines whether this given declaration will be found by
+/// ordinary name lookup.
+bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ if (SemaRef.getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Tag;
+
+ return (ND->getIdentifierNamespace() & IDNS) &&
+ !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND);
+}
+
/// \brief Determines whether the given declaration is suitable as the
/// start of a C++ nested-name-specifier, e.g., a class or namespace.
bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
@@ -584,251 +713,601 @@ bool ResultBuilder::IsMember(NamedDecl *ND) const {
isa<ObjCPropertyDecl>(ND);
}
-// Find the next outer declaration context corresponding to this scope.
-static DeclContext *findOuterContext(Scope *S) {
- for (S = S->getParent(); S; S = S->getParent())
- if (S->getEntity())
- return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
-
- return 0;
-}
-
-/// \brief Collect the results of searching for members within the given
-/// declaration context.
-///
-/// \param Ctx the declaration context from which we will gather results.
-///
-/// \param Rank the rank given to results in this declaration context.
-///
-/// \param Visited the set of declaration contexts that have already been
-/// visited. Declaration contexts will only be visited once.
-///
-/// \param Results the result set that will be extended with any results
-/// found within this declaration context (and, for a C++ class, its bases).
-///
-/// \param InBaseClass whether we are in a base class.
-///
-/// \returns the next higher rank value, after considering all of the
-/// names within this declaration context.
-static unsigned CollectMemberLookupResults(DeclContext *Ctx,
- unsigned Rank,
- DeclContext *CurContext,
- llvm::SmallPtrSet<DeclContext *, 16> &Visited,
- ResultBuilder &Results,
- bool InBaseClass = false) {
- // Make sure we don't visit the same context twice.
- if (!Visited.insert(Ctx->getPrimaryContext()))
- return Rank;
-
- // Enumerate all of the results in this context.
- typedef CodeCompleteConsumer::Result Result;
- Results.EnterNewScope();
- for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx;
- CurCtx = CurCtx->getNextContext()) {
- for (DeclContext::decl_iterator D = CurCtx->decls_begin(),
- DEnd = CurCtx->decls_end();
- D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
- Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext);
-
- // Visit transparent contexts inside this context.
- if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
- if (InnerCtx->isTransparentContext())
- CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited,
- Results, InBaseClass);
- }
- }
- }
-
- // Traverse the contexts of inherited classes.
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
- for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
- BEnd = Record->bases_end();
- B != BEnd; ++B) {
- QualType BaseType = B->getType();
-
- // Don't look into dependent bases, because name lookup can't look
- // there anyway.
- if (BaseType->isDependentType())
- continue;
-
- const RecordType *Record = BaseType->getAs<RecordType>();
- if (!Record)
- continue;
-
- // FIXME: It would be nice to be able to determine whether referencing
- // a particular member would be ambiguous. For example, given
- //
- // struct A { int member; };
- // struct B { int member; };
- // struct C : A, B { };
- //
- // void f(C *c) { c->### }
- // accessing 'member' would result in an ambiguity. However, code
- // completion could be smart enough to qualify the member with the
- // base class, e.g.,
- //
- // c->B::member
- //
- // or
- //
- // c->A::member
-
- // Collect results from this base class (and its bases).
- CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited,
- Results, /*InBaseClass=*/true);
- }
- }
-
- // FIXME: Look into base classes in Objective-C!
-
- Results.ExitScope();
- return Rank + 1;
+/// \rief Determines whether the given declaration is an Objective-C
+/// instance variable.
+bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const {
+ return isa<ObjCIvarDecl>(ND);
}
-/// \brief Collect the results of searching for members within the given
-/// declaration context.
-///
-/// \param Ctx the declaration context from which we will gather results.
-///
-/// \param InitialRank the initial rank given to results in this declaration
-/// context. Larger rank values will be used for, e.g., members found in
-/// base classes.
-///
-/// \param Results the result set that will be extended with any results
-/// found within this declaration context (and, for a C++ class, its bases).
-///
-/// \returns the next higher rank value, after considering all of the
-/// names within this declaration context.
-static unsigned CollectMemberLookupResults(DeclContext *Ctx,
- unsigned InitialRank,
- DeclContext *CurContext,
- ResultBuilder &Results) {
- llvm::SmallPtrSet<DeclContext *, 16> Visited;
- return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited,
- Results);
-}
-
-/// \brief Collect the results of searching for declarations within the given
-/// scope and its parent scopes.
-///
-/// \param S the scope in which we will start looking for declarations.
-///
-/// \param InitialRank the initial rank given to results in this scope.
-/// Larger rank values will be used for results found in parent scopes.
-///
-/// \param CurContext the context from which lookup results will be found.
-///
-/// \param Results the builder object that will receive each result.
-static unsigned CollectLookupResults(Scope *S,
- TranslationUnitDecl *TranslationUnit,
- unsigned InitialRank,
- DeclContext *CurContext,
- ResultBuilder &Results) {
- if (!S)
- return InitialRank;
-
- // FIXME: Using directives!
-
- unsigned NextRank = InitialRank;
- Results.EnterNewScope();
- if (S->getEntity() &&
- !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
- // Look into this scope's declaration context, along with any of its
- // parent lookup contexts (e.g., enclosing classes), up to the point
- // where we hit the context stored in the next outer scope.
- DeclContext *Ctx = (DeclContext *)S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S);
-
- for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
- Ctx = Ctx->getLookupParent()) {
- if (Ctx->isFunctionOrMethod())
- continue;
-
- NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext,
- Results);
- }
- } else if (!S->getParent()) {
- // Look into the translation unit scope. We walk through the translation
- // unit's declaration context, because the Scope itself won't have all of
- // the declarations if we loaded a precompiled header.
- // FIXME: We would like the translation unit's Scope object to point to the
- // translation unit, so we don't need this special "if" branch. However,
- // doing so would force the normal C++ name-lookup code to look into the
- // translation unit decl when the IdentifierInfo chains would suffice.
- // Once we fix that problem (which is part of a more general "don't look
- // in DeclContexts unless we have to" optimization), we can eliminate the
- // TranslationUnit parameter entirely.
- NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1,
- CurContext, Results);
- } else {
- // Walk through the declarations in this Scope.
- for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
- Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank),
- CurContext);
- }
+namespace {
+ /// \brief Visible declaration consumer that adds a code-completion result
+ /// for each visible declaration.
+ class CodeCompletionDeclConsumer : public VisibleDeclConsumer {
+ ResultBuilder &Results;
+ DeclContext *CurContext;
- NextRank = NextRank + 1;
- }
-
- // Lookup names in the parent scope.
- NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank,
- CurContext, Results);
- Results.ExitScope();
-
- return NextRank;
+ public:
+ CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
+ : Results(Results), CurContext(CurContext) { }
+
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) {
+ Results.AddResult(ND, CurContext, Hiding, InBaseClass);
+ }
+ };
}
/// \brief Add type specifiers for the current language as keyword results.
-static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank,
+static void AddTypeSpecifierResults(const LangOptions &LangOpts,
ResultBuilder &Results) {
typedef CodeCompleteConsumer::Result Result;
- Results.MaybeAddResult(Result("short", Rank));
- Results.MaybeAddResult(Result("long", Rank));
- Results.MaybeAddResult(Result("signed", Rank));
- Results.MaybeAddResult(Result("unsigned", Rank));
- Results.MaybeAddResult(Result("void", Rank));
- Results.MaybeAddResult(Result("char", Rank));
- Results.MaybeAddResult(Result("int", Rank));
- Results.MaybeAddResult(Result("float", Rank));
- Results.MaybeAddResult(Result("double", Rank));
- Results.MaybeAddResult(Result("enum", Rank));
- Results.MaybeAddResult(Result("struct", Rank));
- Results.MaybeAddResult(Result("union", Rank));
-
+ Results.AddResult(Result("short"));
+ Results.AddResult(Result("long"));
+ Results.AddResult(Result("signed"));
+ Results.AddResult(Result("unsigned"));
+ Results.AddResult(Result("void"));
+ Results.AddResult(Result("char"));
+ Results.AddResult(Result("int"));
+ Results.AddResult(Result("float"));
+ Results.AddResult(Result("double"));
+ Results.AddResult(Result("enum"));
+ Results.AddResult(Result("struct"));
+ Results.AddResult(Result("union"));
+ Results.AddResult(Result("const"));
+ Results.AddResult(Result("volatile"));
+
if (LangOpts.C99) {
// C99-specific
- Results.MaybeAddResult(Result("_Complex", Rank));
- Results.MaybeAddResult(Result("_Imaginary", Rank));
- Results.MaybeAddResult(Result("_Bool", Rank));
+ Results.AddResult(Result("_Complex"));
+ Results.AddResult(Result("_Imaginary"));
+ Results.AddResult(Result("_Bool"));
+ Results.AddResult(Result("restrict"));
}
if (LangOpts.CPlusPlus) {
// C++-specific
- Results.MaybeAddResult(Result("bool", Rank));
- Results.MaybeAddResult(Result("class", Rank));
- Results.MaybeAddResult(Result("typename", Rank));
- Results.MaybeAddResult(Result("wchar_t", Rank));
+ Results.AddResult(Result("bool"));
+ Results.AddResult(Result("class"));
+ Results.AddResult(Result("wchar_t"));
+ // typename qualified-id
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Results.AddResult(Result(Pattern));
+
if (LangOpts.CPlusPlus0x) {
- Results.MaybeAddResult(Result("char16_t", Rank));
- Results.MaybeAddResult(Result("char32_t", Rank));
- Results.MaybeAddResult(Result("decltype", Rank));
+ Results.AddResult(Result("auto"));
+ Results.AddResult(Result("char16_t"));
+ Results.AddResult(Result("char32_t"));
+ Results.AddResult(Result("decltype"));
}
}
// GNU extensions
if (LangOpts.GNUMode) {
// FIXME: Enable when we actually support decimal floating point.
- // Results.MaybeAddResult(Result("_Decimal32", Rank));
- // Results.MaybeAddResult(Result("_Decimal64", Rank));
- // Results.MaybeAddResult(Result("_Decimal128", Rank));
- Results.MaybeAddResult(Result("typeof", Rank));
+ // Results.AddResult(Result("_Decimal32"));
+ // Results.AddResult(Result("_Decimal64"));
+ // Results.AddResult(Result("_Decimal128"));
+
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
}
}
+static void AddStorageSpecifiers(Action::CodeCompletionContext CCC,
+ const LangOptions &LangOpts,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ // Note: we don't suggest either "auto" or "register", because both
+ // are pointless as storage specifiers. Elsewhere, we suggest "auto"
+ // in C++0x as a type specifier.
+ Results.AddResult(Result("extern"));
+ Results.AddResult(Result("static"));
+}
+
+static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC,
+ const LangOptions &LangOpts,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ switch (CCC) {
+ case Action::CCC_Class:
+ case Action::CCC_MemberTemplate:
+ if (LangOpts.CPlusPlus) {
+ Results.AddResult(Result("explicit"));
+ Results.AddResult(Result("friend"));
+ Results.AddResult(Result("mutable"));
+ Results.AddResult(Result("virtual"));
+ }
+ // Fall through
+
+ case Action::CCC_ObjCInterface:
+ case Action::CCC_ObjCImplementation:
+ case Action::CCC_Namespace:
+ case Action::CCC_Template:
+ if (LangOpts.CPlusPlus || LangOpts.C99)
+ Results.AddResult(Result("inline"));
+ break;
+
+ case Action::CCC_ObjCInstanceVariableList:
+ case Action::CCC_Expression:
+ case Action::CCC_Statement:
+ case Action::CCC_ForInit:
+ case Action::CCC_Condition:
+ break;
+ }
+}
+
+static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt);
+static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt);
+static void AddObjCVisibilityResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCImplementationResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCInterfaceResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt);
+static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt);
+
+/// \brief Add language constructs that show up for "ordinary" names.
+static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC,
+ Scope *S,
+ Sema &SemaRef,
+ ResultBuilder &Results) {
+ typedef CodeCompleteConsumer::Result Result;
+ switch (CCC) {
+ case Action::CCC_Namespace:
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // namespace <identifier> { }
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("declarations");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // namespace identifier = identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_Equal);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // asm(string-literal)
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("asm");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("string-literal");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Explicit template instantiation
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("template");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("declaration");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (SemaRef.getLangOptions().ObjC1)
+ AddObjCTopLevelResults(Results, true);
+
+ // Fall through
+
+ case Action::CCC_Class:
+ Results.AddResult(Result("typedef"));
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // Using declaration
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // using typename qualified-id; (only in a dependent context)
+ if (SemaRef.CurContext->isDependentContext()) {
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("typename");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("qualified-id");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (CCC == Action::CCC_Class) {
+ // public:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("public");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // protected:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("protected");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // private:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("private");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+ }
+ }
+ // Fall through
+
+ case Action::CCC_Template:
+ case Action::CCC_MemberTemplate:
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // template < parameters >
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("template");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("parameters");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Results.AddResult(Result(Pattern));
+ }
+
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCInterface:
+ AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCImplementation:
+ AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true);
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ break;
+
+ case Action::CCC_ObjCInstanceVariableList:
+ AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true);
+ break;
+
+ case Action::CCC_Statement: {
+ Results.AddResult(Result("typedef"));
+
+ CodeCompletionString *Pattern = 0;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("try");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("catch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("declaration");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+ }
+ if (SemaRef.getLangOptions().ObjC1)
+ AddObjCStatementResults(Results, true);
+
+ // if (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("if");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // switch (condition) { }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("switch");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // Switch-specific statements.
+ if (!SemaRef.getSwitchStack().empty()) {
+ // case expression:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("case");
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+
+ // default:
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("default");
+ Pattern->AddChunk(CodeCompletionString::CK_Colon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ /// while (condition) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Pattern->AddPlaceholderChunk("condition");
+ else
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ // do { statements } while ( expression );
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("do");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Pattern->AddTextChunk("while");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // for ( for-init-statement ; condition ; expression ) { statements }
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("for");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99)
+ Pattern->AddPlaceholderChunk("init-statement");
+ else
+ Pattern->AddPlaceholderChunk("init-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("condition");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Pattern->AddPlaceholderChunk("inc-expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
+ Pattern->AddPlaceholderChunk("statements");
+ Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
+ Results.AddResult(Result(Pattern));
+
+ if (S->getContinueParent()) {
+ // continue ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("continue");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (S->getBreakParent()) {
+ // break ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("break");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ // "return expression ;" or "return ;", depending on whether we
+ // know the function is void or not.
+ bool isVoid = false;
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext))
+ isVoid = Function->getResultType()->isVoidType();
+ else if (ObjCMethodDecl *Method
+ = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
+ isVoid = Method->getResultType()->isVoidType();
+ else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull())
+ isVoid = SemaRef.CurBlock->ReturnType->isVoidType();
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("return");
+ if (!isVoid)
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // goto identifier ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("goto");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // Using directives
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("using");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("namespace");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+ }
+
+ // Fall through (for statement expressions).
+ case Action::CCC_ForInit:
+ case Action::CCC_Condition:
+ AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results);
+ // Fall through: conditions and statements can have expressions.
+
+ case Action::CCC_Expression: {
+ CodeCompletionString *Pattern = 0;
+ if (SemaRef.getLangOptions().CPlusPlus) {
+ // 'this', if we're in a non-static member function.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
+ if (!Method->isStatic())
+ Results.AddResult(Result("this"));
+
+ // true, false
+ Results.AddResult(Result("true"));
+ Results.AddResult(Result("false"));
+
+ // dynamic_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("dynamic_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // static_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("static_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // reinterpret_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("reinterpret_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // const_cast < type-id > ( expression )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("const_cast");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftAngle);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_RightAngle);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // typeid ( expression-or-type )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("typeid");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // new T ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // new T [ ] ( ... )
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("new");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("type-id");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddPlaceholderChunk("size");
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expressions");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+
+ // delete expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+
+ // delete [] expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("delete");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_RightBracket);
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+
+ // throw expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("throw");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("expression");
+ Results.AddResult(Result(Pattern));
+ }
+
+ if (SemaRef.getLangOptions().ObjC1) {
+ // Add "super", if we're in an Objective-C class with a superclass.
+ if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
+ if (Method->getClassInterface()->getSuperClass())
+ Results.AddResult(Result("super"));
+
+ AddObjCExpressionResults(Results, true);
+ }
+
+ // sizeof expression
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("sizeof");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("expression-or-type");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Result(Pattern));
+ break;
+ }
+ }
+
+ AddTypeSpecifierResults(SemaRef.getLangOptions(), Results);
+
+ if (SemaRef.getLangOptions().CPlusPlus)
+ Results.AddResult(Result("operator"));
+}
+
/// \brief If the given declaration has an associated type, add it as a result
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
@@ -1178,7 +1657,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
if (Idx > 0) {
std::string Keyword;
if (Idx > StartParameter)
- Keyword = " ";
+ Result->AddChunk(CodeCompletionString::CK_HorizontalSpace);
if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx))
Keyword += II->getName().str();
Keyword += ":";
@@ -1344,29 +1823,49 @@ namespace {
Y.getAsString()) < 0;
}
- bool operator()(const Result &X, const Result &Y) const {
- // Sort first by rank.
- if (X.Rank < Y.Rank)
- return true;
- else if (X.Rank > Y.Rank)
- return false;
-
- // We use a special ordering for keywords and patterns, based on the
- // typed text.
- if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) &&
- (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) {
- const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword
- : X.Pattern->getTypedText();
- const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword
- : Y.Pattern->getTypedText();
- return llvm::StringRef(XStr).compare_lower(YStr) < 0;
+ /// \brief Retrieve the name that should be used to order a result.
+ ///
+ /// If the name needs to be constructed as a string, that string will be
+ /// saved into Saved and the returned StringRef will refer to it.
+ static llvm::StringRef getOrderedName(const Result &R,
+ std::string &Saved) {
+ switch (R.Kind) {
+ case Result::RK_Keyword:
+ return R.Keyword;
+
+ case Result::RK_Pattern:
+ return R.Pattern->getTypedText();
+
+ case Result::RK_Macro:
+ return R.Macro->getName();
+
+ case Result::RK_Declaration:
+ // Handle declarations below.
+ break;
}
+
+ DeclarationName Name = R.Declaration->getDeclName();
- // Result kinds are ordered by decreasing importance.
- if (X.Kind < Y.Kind)
- return true;
- else if (X.Kind > Y.Kind)
- return false;
+ // If the name is a simple identifier (by far the common case), or a
+ // zero-argument selector, just return a reference to that identifier.
+ if (IdentifierInfo *Id = Name.getAsIdentifierInfo())
+ return Id->getName();
+ if (Name.isObjCZeroArgSelector())
+ if (IdentifierInfo *Id
+ = Name.getObjCSelector().getIdentifierInfoForSlot(0))
+ return Id->getName();
+
+ Saved = Name.getAsString();
+ return Saved;
+ }
+
+ bool operator()(const Result &X, const Result &Y) const {
+ std::string XSaved, YSaved;
+ llvm::StringRef XStr = getOrderedName(X, XSaved);
+ llvm::StringRef YStr = getOrderedName(Y, YSaved);
+ int cmp = XStr.compare_lower(YStr);
+ if (cmp)
+ return cmp < 0;
// Non-hidden names precede hidden names.
if (X.Hidden != Y.Hidden)
@@ -1376,35 +1875,17 @@ namespace {
if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier)
return !X.StartsNestedNameSpecifier;
- // Ordering depends on the kind of result.
- switch (X.Kind) {
- case Result::RK_Declaration:
- // Order based on the declaration names.
- return isEarlierDeclarationName(X.Declaration->getDeclName(),
- Y.Declaration->getDeclName());
-
- case Result::RK_Macro:
- return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0;
-
- case Result::RK_Keyword:
- case Result::RK_Pattern:
- llvm_unreachable("Result kinds handled above");
- break;
- }
-
- // Silence GCC warning.
return false;
}
};
}
-static void AddMacroResults(Preprocessor &PP, unsigned Rank,
- ResultBuilder &Results) {
+static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results) {
Results.EnterNewScope();
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M)
- Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank));
+ Results.AddResult(M->first);
Results.ExitScope();
}
@@ -1412,7 +1893,6 @@ static void HandleCodeCompleteResults(Sema *S,
CodeCompleteConsumer *CodeCompleter,
CodeCompleteConsumer::Result *Results,
unsigned NumResults) {
- // Sort the results by rank/kind/etc.
std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult());
if (CodeCompleter)
@@ -1422,26 +1902,42 @@ static void HandleCodeCompleteResults(Sema *S,
Results[I].Destroy();
}
-void Sema::CodeCompleteOrdinaryName(Scope *S) {
+void Sema::CodeCompleteOrdinaryName(Scope *S,
+ CodeCompletionContext CompletionContext) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ ResultBuilder Results(*this);
- Results.EnterNewScope();
- AddTypeSpecifierResults(getLangOptions(), NextRank, Results);
-
- if (getLangOptions().ObjC1) {
- // Add the "super" keyword, if appropriate.
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
- if (Method->getClassInterface()->getSuperClass())
- Results.MaybeAddResult(Result("super", NextRank));
+ // Determine how to filter results, e.g., so that the names of
+ // values (functions, enumerators, function templates, etc.) are
+ // only allowed where we can have an expression.
+ switch (CompletionContext) {
+ case CCC_Namespace:
+ case CCC_Class:
+ case CCC_ObjCInterface:
+ case CCC_ObjCImplementation:
+ case CCC_ObjCInstanceVariableList:
+ case CCC_Template:
+ case CCC_MemberTemplate:
+ Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName);
+ break;
+
+ case CCC_Expression:
+ case CCC_Statement:
+ case CCC_ForInit:
+ case CCC_Condition:
+ Results.setFilter(&ResultBuilder::IsOrdinaryName);
+ break;
}
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
+
+ Results.EnterNewScope();
+ AddOrdinaryNameResults(CompletionContext, S, *this, Results);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1513,13 +2009,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
}
ResultBuilder Results(*this, &ResultBuilder::IsMember);
- unsigned NextRank = 0;
-
Results.EnterNewScope();
if (const RecordType *Record = BaseType->getAs<RecordType>()) {
// Access to a C/C++ class, struct, or union.
- NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank,
- Record->getDecl(), Results);
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer);
if (getLangOptions().CPlusPlus) {
if (!Results.empty()) {
@@ -1536,16 +2031,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
}
if (IsDependent)
- Results.MaybeAddResult(Result("template", NextRank++));
+ Results.AddResult(Result("template"));
}
-
- // We could have the start of a nested-name-specifier. Add those
- // results as well.
- // FIXME: We should really walk base classes to produce
- // nested-name-specifiers so that we produce more-precise results.
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank,
- CurContext, Results);
}
} else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) {
// Objective-C property reference.
@@ -1561,9 +2048,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
E = ObjCPtr->qual_end();
I != E; ++I)
AddObjCProperties(*I, true, CurContext, Results);
-
- // FIXME: We could (should?) also look for "implicit" properties, identified
- // only by the presence of nullary and unary selectors.
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCInterfaceType())) {
// Objective-C instance variable access.
@@ -1575,11 +2059,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
Class = BaseType->getAs<ObjCInterfaceType>()->getDecl();
// Add all ivars from this class and its superclasses.
- for (; Class; Class = Class->getSuperClass()) {
- for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
- IVarEnd = Class->ivar_end();
- IVar != IVarEnd; ++IVar)
- Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+ if (Class) {
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ Results.setFilter(&ResultBuilder::IsObjCIvar);
+ LookupVisibleDecls(Class, LookupMemberName, Consumer);
}
}
@@ -1589,7 +2072,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
// Add macros
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
// Hand off the results found for code completion.
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -1621,19 +2104,12 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
}
ResultBuilder Results(*this, Filter);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
-
- if (getLangOptions().CPlusPlus) {
- // We could have the start of a nested-name-specifier. Add those
- // results as well.
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- NextRank, CurContext, Results);
- }
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupTagName, Consumer);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1707,12 +2183,13 @@ void Sema::CodeCompleteCase(Scope *S) {
if (EnumeratorsSeen.count(*E))
continue;
- Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier));
+ Results.AddResult(CodeCompleteConsumer::Result(*E, Qualifier),
+ CurContext, 0, false);
}
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1746,7 +2223,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// Ignore type-dependent call expressions entirely.
if (Fn->isTypeDependent() ||
Expr::hasAnyTypeDependentArguments(Args, NumArgs)) {
- CodeCompleteOrdinaryName(S);
+ CodeCompleteOrdinaryName(S, CCC_Expression);
return;
}
@@ -1784,7 +2261,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
}
if (Results.empty())
- CodeCompleteOrdinaryName(S);
+ CodeCompleteOrdinaryName(S, CCC_Expression);
else
CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(),
Results.size());
@@ -1805,16 +2282,17 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
return;
ResultBuilder Results(*this);
- unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer);
// The "template" keyword can follow "::" in the grammar, but only
// put it into the grammar if the nested-name-specifier is dependent.
NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
if (!Results.empty() && NNS->isDependent())
- Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank));
+ Results.AddResult("template");
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank + 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1827,16 +2305,16 @@ void Sema::CodeCompleteUsing(Scope *S) {
// If we aren't in class scope, we could see the "namespace" keyword.
if (!S->isClassScope())
- Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("namespace"));
// After "using", we can see anything that would start a
// nested-name-specifier.
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1848,11 +2326,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) {
// alias.
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
Results.EnterNewScope();
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1882,13 +2360,13 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator
NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
- Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0),
- CurContext);
+ Results.AddResult(CodeCompleteConsumer::Result(NS->second, 0),
+ CurContext, 0, false);
Results.ExitScope();
}
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, 1, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1898,10 +2376,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) {
// After "namespace", we expect to see a namespace or alias.
ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias);
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -1916,155 +2394,168 @@ void Sema::CodeCompleteOperatorName(Scope *S) {
// Add the names of overloadable operators.
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
if (std::strcmp(Spelling, "?")) \
- Results.MaybeAddResult(Result(Spelling, 0));
+ Results.AddResult(Result(Spelling));
#include "clang/Basic/OperatorKinds.def"
// Add any type names visible from the current scope
- unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- 0, CurContext, Results);
+ Results.allowNestedNameSpecifiers();
+ CodeCompletionDeclConsumer Consumer(Results, CurContext);
+ LookupVisibleDecls(S, LookupOrdinaryName, Consumer);
// Add any type specifiers
- AddTypeSpecifierResults(getLangOptions(), 0, Results);
-
- // Add any nested-name-specifiers
- Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
- NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(),
- NextRank + 1, CurContext, Results);
+ AddTypeSpecifierResults(getLangOptions(), Results);
Results.ExitScope();
if (CodeCompleter->includeMacros())
- AddMacroResults(PP, NextRank, Results);
+ AddMacroResults(PP, Results);
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
- bool InInterface) {
+// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is
+// true or false.
+#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword
+static void AddObjCImplementationResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this);
- Results.EnterNewScope();
- if (ObjCImpDecl) {
- // Since we have an implementation, we can end it.
- Results.MaybeAddResult(Result("end", 0));
-
- CodeCompletionString *Pattern = 0;
- Decl *ImpDecl = ObjCImpDecl.getAs<Decl>();
- if (isa<ObjCImplementationDecl>(ImpDecl) ||
- isa<ObjCCategoryImplDecl>(ImpDecl)) {
- // @dynamic
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("dynamic");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("property");
- Results.MaybeAddResult(Result(Pattern, 0));
-
- // @synthesize
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("synthesize");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("property");
- Results.MaybeAddResult(Result(Pattern, 0));
- }
- } else if (InInterface) {
- // Since we have an interface or protocol, we can end it.
- Results.MaybeAddResult(Result("end", 0));
-
- if (LangOpts.ObjC2) {
- // @property
- Results.MaybeAddResult(Result("property", 0));
- }
-
- // @required
- Results.MaybeAddResult(Result("required", 0));
-
- // @optional
- Results.MaybeAddResult(Result("optional", 0));
- } else {
- CodeCompletionString *Pattern = 0;
-
- // @class name ;
+ // Since we have an implementation, we can end it.
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+
+ CodeCompletionString *Pattern = 0;
+ if (LangOpts.ObjC2) {
+ // @dynamic
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("class");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("identifier");
- Pattern->AddTextChunk(";"); // add ';' chunk
- Results.MaybeAddResult(Result(Pattern, 0));
-
- // @interface name
- // FIXME: Could introduce the whole pattern, including superclasses and
- // such.
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("property");
+ Results.AddResult(Result(Pattern));
+
+ // @synthesize
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("interface");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("property");
+ Results.AddResult(Result(Pattern));
+ }
+}
- // @protocol name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("protocol");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("protocol");
- Results.MaybeAddResult(Result(Pattern, 0));
+static void AddObjCInterfaceResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+
+ // Since we have an interface or protocol, we can end it.
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end)));
+
+ if (LangOpts.ObjC2) {
+ // @property
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,property)));
+
+ // @required
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,required)));
+
+ // @optional
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,optional)));
+ }
+}
- // @implementation name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("implementation");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
+static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+ CodeCompletionString *Pattern = 0;
+
+ // @class name ;
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("identifier");
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
+ // @interface name
+ // FIXME: Could introduce the whole pattern, including superclasses and
+ // such.
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+
+ // @protocol name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("protocol");
+ Results.AddResult(Result(Pattern));
+
+ // @implementation name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+
+ // @compatibility_alias name
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("alias");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("class");
+ Results.AddResult(Result(Pattern));
+}
- // @compatibility_alias name
- Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("compatibility_alias");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("alias");
- Pattern->AddTextChunk(" ");
- Pattern->AddPlaceholderChunk("class");
- Results.MaybeAddResult(Result(Pattern, 0));
- }
+void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
+ bool InInterface) {
+ typedef CodeCompleteConsumer::Result Result;
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ if (ObjCImpDecl)
+ AddObjCImplementationResults(getLangOptions(), Results, false);
+ else if (InInterface)
+ AddObjCInterfaceResults(getLangOptions(), Results, false);
+ else
+ AddObjCTopLevelResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
-static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) {
+static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
CodeCompletionString *Pattern = 0;
// @encode ( type-name )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("encode");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("type-name");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
// @protocol ( protocol-name )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("protocol");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("protocol-name");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
// @selector ( selector )
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("selector");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector));
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("selector");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
- Results.MaybeAddResult(Result(Pattern, Rank));
+ Results.AddResult(Result(Pattern));
}
-void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) {
typedef CodeCompleteConsumer::Result Result;
- ResultBuilder Results(*this);
- Results.EnterNewScope();
-
CodeCompletionString *Pattern = 0;
-
+
// @try { statements } @catch ( declaration ) { statements } @finally
// { statements }
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("try");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try));
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
@@ -2079,29 +2570,53 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) {
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.MaybeAddResult(Result(Pattern, 0));
-
+ Results.AddResult(Result(Pattern));
+
// @throw
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("throw");
- Pattern->AddTextChunk(" ");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddPlaceholderChunk("expression");
- Pattern->AddTextChunk(";");
- Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
-
+ Pattern->AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Pattern));
+
// @synchronized ( expression ) { statements }
Pattern = new CodeCompletionString;
- Pattern->AddTypedTextChunk("synchronized");
- Pattern->AddTextChunk(" ");
+ Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized));
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
Pattern->AddPlaceholderChunk("expression");
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
Pattern->AddChunk(CodeCompletionString::CK_LeftBrace);
Pattern->AddPlaceholderChunk("statements");
Pattern->AddChunk(CodeCompletionString::CK_RightBrace);
- Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk
+ Results.AddResult(Result(Pattern));
+}
+
+static void AddObjCVisibilityResults(const LangOptions &LangOpts,
+ ResultBuilder &Results,
+ bool NeedAt) {
+ typedef CodeCompleteConsumer::Result Result;
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected)));
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public)));
+ if (LangOpts.ObjC2)
+ Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,package)));
+}
- AddObjCExpressionResults(0, Results);
+void Sema::CodeCompleteObjCAtVisibility(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCVisibilityResults(getLangOptions(), Results, false);
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
+}
+
+void Sema::CodeCompleteObjCAtStatement(Scope *S) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+ AddObjCStatementResults(Results, false);
+ AddObjCExpressionResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2109,7 +2624,7 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) {
void Sema::CodeCompleteObjCAtExpression(Scope *S) {
ResultBuilder Results(*this);
Results.EnterNewScope();
- AddObjCExpressionResults(0, Results);
+ AddObjCExpressionResults(Results, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
}
@@ -2154,30 +2669,30 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
ResultBuilder Results(*this);
Results.EnterNewScope();
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("readonly"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("assign"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("readwrite"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("retain"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
- Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0));
+ Results.AddResult(CodeCompleteConsumer::Result("nonatomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionString *Setter = new CodeCompletionString;
Setter->AddTypedTextChunk("setter");
Setter->AddTextChunk(" = ");
Setter->AddPlaceholderChunk("method");
- Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0));
+ Results.AddResult(CodeCompleteConsumer::Result(Setter));
}
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) {
CodeCompletionString *Getter = new CodeCompletionString;
Getter->AddTypedTextChunk("getter");
Getter->AddTextChunk(" = ");
Getter->AddPlaceholderChunk("method");
- Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0));
+ Results.AddResult(CodeCompleteConsumer::Result(Getter));
}
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2522,7 +3037,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
if (!OnlyForwardDeclarations || Proto->isForwardDecl())
- Results.MaybeAddResult(Result(Proto, 0), CurContext);
+ Results.AddResult(Result(Proto, 0), CurContext, 0, false);
// Record any forward-declared protocols we find.
if (ObjCForwardProtocolDecl *Forward
@@ -2532,7 +3047,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
PEnd = Forward->protocol_end();
P != PEnd; ++P)
if (!OnlyForwardDeclarations || (*P)->isForwardDecl())
- Results.MaybeAddResult(Result(*P, 0), CurContext);
+ Results.AddResult(Result(*P, 0), CurContext, 0, false);
}
}
}
@@ -2583,7 +3098,7 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
if ((!OnlyForwardDeclarations || Class->isForwardDecl()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
- Results.MaybeAddResult(Result(Class, 0), CurContext);
+ Results.AddResult(Result(Class, 0), CurContext, 0, false);
// Record any forward-declared interfaces we find.
if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
@@ -2591,7 +3106,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
C != CEnd; ++C)
if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) &&
(!OnlyUnimplemented || !C->getInterface()->getImplementation()))
- Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext);
+ Results.AddResult(Result(C->getInterface(), 0), CurContext,
+ 0, false);
}
}
}
@@ -2662,7 +3178,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
D != DEnd; ++D)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
if (CategoryNames.insert(Category->getIdentifier()))
- Results.MaybeAddResult(Result(Category, 0), CurContext);
+ Results.AddResult(Result(Category, 0), CurContext, 0, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
@@ -2694,7 +3210,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Category = Category->getNextClassCategory())
if ((!IgnoreImplemented || !Category->getImplementation()) &&
CategoryNames.insert(Category->getIdentifier()))
- Results.MaybeAddResult(Result(Category, 0), CurContext);
+ Results.AddResult(Result(Category, 0), CurContext, 0, false);
Class = Class->getSuperClass();
IgnoreImplemented = false;
@@ -2768,7 +3284,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(),
IVarEnd = Class->ivar_end();
IVar != IVarEnd; ++IVar)
- Results.MaybeAddResult(Result(*IVar, 0), CurContext);
+ Results.AddResult(Result(*IVar, 0), CurContext, 0, false);
}
Results.ExitScope();
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2253f093df09..0ccb8f2b1d5f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -137,6 +138,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
NamedDecl *IIDecl = 0;
switch (Result.getResultKind()) {
case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
return 0;
@@ -281,6 +283,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
else
llvm_unreachable("could not have corrected a typo here");
+ Diag(Result->getLocation(), diag::note_previous_decl)
+ << Result->getDeclName();
+
SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS);
return true;
}
@@ -555,11 +560,38 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
/// return 0 if one not found.
-ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
+///
+/// \param Id the name of the Objective-C class we're looking for. If
+/// typo-correction fixes this name, the Id will be updated
+/// to the fixed name.
+///
+/// \param RecoverLoc if provided, this routine will attempt to
+/// recover from a typo in the name of an existing Objective-C class
+/// and, if successful, will return the lookup that results from
+/// typo-correction.
+ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
+ SourceLocation RecoverLoc) {
// The third "scope" argument is 0 since we aren't enabling lazy built-in
// creation from this context.
NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName);
+ if (!IDecl && !RecoverLoc.isInvalid()) {
+ // Perform typo correction at the given location, but only if we
+ // find an Objective-C class name.
+ LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ Diag(RecoverLoc, diag::err_undef_interface_suggest)
+ << Id << IDecl->getDeclName()
+ << CodeModificationHint::CreateReplacement(RecoverLoc,
+ IDecl->getNameAsString());
+ Diag(IDecl->getLocation(), diag::note_previous_decl)
+ << IDecl->getDeclName();
+
+ Id = IDecl->getIdentifier();
+ }
+ }
+
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
}
@@ -773,13 +805,38 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) {
if (getLangOptions().Microsoft)
return;
- // C++ [dcl.typedef]p2:
- // In a given non-class scope, a typedef specifier can be used to
- // redefine the name of any type declared in that scope to refer
- // to the type to which it already refers.
if (getLangOptions().CPlusPlus) {
+ // C++ [dcl.typedef]p2:
+ // In a given non-class scope, a typedef specifier can be used to
+ // redefine the name of any type declared in that scope to refer
+ // to the type to which it already refers.
if (!isa<CXXRecordDecl>(CurContext))
return;
+
+ // C++0x [dcl.typedef]p4:
+ // In a given class scope, a typedef specifier can be used to redefine
+ // any class-name declared in that scope that is not also a typedef-name
+ // to refer to the type to which it already refers.
+ //
+ // This wording came in via DR424, which was a correction to the
+ // wording in DR56, which accidentally banned code like:
+ //
+ // struct S {
+ // typedef struct A { } A;
+ // };
+ //
+ // in the C++03 standard. We implement the C++0x semantics, which
+ // allow the above but disallow
+ //
+ // struct S {
+ // typedef int I;
+ // typedef int I;
+ // };
+ //
+ // since that was the intent of DR56.
+ if (!isa<TypedefDecl >(Old))
+ return;
+
Diag(New->getLocation(), diag::err_redefinition)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
@@ -1250,34 +1307,61 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setPreviousDeclaration(Old);
}
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
- // FIXME: Eventually share this CFG object when we have other warnings based
- // of the CFG. This can be done using AnalysisContext.
- llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context));
+static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ workq.push(e);
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+}
- // FIXME: They should never return 0, fix that, delete this code.
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
- // The CFG leaves in dead things, and we don't want to dead code paths to
- // confuse us, so we mark all live things first.
+static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
+ SourceManager &SM) {
std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
// Prep work queue
- workq.push(&cfg->getEntry());
+ workq.push(e);
+ SourceLocation top;
+ if (!e->empty())
+ top = e[0][0].getStmt()->getLocStart();
+ bool FromMainFile = false;
+ bool FromSystemHeader = false;
+ bool TopValid = false;
+ if (top.isValid()) {
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ TopValid = true;
+ }
// Solve
while (!workq.empty()) {
CFGBlock *item = workq.front();
workq.pop();
+ SourceLocation c;
+ if (!item->empty())
+ c = item[0][0].getStmt()->getLocStart();
+ else if (item->getTerminator())
+ c = item->getTerminator()->getLocStart();
+ if (c.isValid()
+ && (!TopValid
+ || (SM.isFromMainFile(c) && !FromMainFile)
+ || (FromSystemHeader && !SM.isInSystemHeader(c))
+ || SM.isBeforeInTranslationUnit(c, top))) {
+ top = c;
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ }
live.set(item->getBlockID());
for (CFGBlock::succ_iterator I=item->succ_begin(),
E=item->succ_end();
@@ -1289,6 +1373,92 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
}
}
}
+ return top;
+}
+
+namespace {
+class LineCmp {
+ SourceManager &SM;
+public:
+ LineCmp(SourceManager &sm) : SM(sm) {
+ }
+ bool operator () (SourceLocation l1, SourceLocation l2) {
+ return l1 < l2;
+ }
+};
+}
+
+/// CheckUnreachable - Check for unreachable code.
+void Sema::CheckUnreachable(AnalysisContext &AC) {
+ // We avoid checking when there are errors, as the CFG won't faithfully match
+ // the user's code.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ return;
+
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Mark all live things first.
+ MarkLive(&cfg->getEntry(), live);
+
+ llvm::SmallVector<SourceLocation, 24> lines;
+ // First, give warnings for blocks with no predecessors, as they
+ // can't be part of a loop.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (!b.empty())
+ lines.push_back(b[0].getStmt()->getLocStart());
+ else if (b.getTerminator())
+ lines.push_back(b.getTerminator()->getLocStart());
+ // Avoid excessive errors by marking everything reachable from here
+ MarkLive(&b, live);
+ }
+ }
+ }
+
+ // And then give warnings for the tops of loops.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()])
+ // Avoid excessive errors by marking everything reachable from here
+ lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
+ }
+
+ std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager()));
+ for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
+ E = lines.end();
+ I != E;
+ ++I)
+ if (I->isValid())
+ Diag(*I, diag::warn_unreachable);
+}
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want to dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ MarkLive(&cfg->getEntry(), live);
// Now we know what is live, we check the live precessors of the exit block
// and look for fall through paths, being careful to ignore normal returns,
@@ -1321,6 +1491,14 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
HasFakeEdge = true;
continue;
}
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
+ if (AS->isMSAsm()) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
+ }
+
bool NoReturnEdge = false;
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
Expr *CEE = C->getCallee()->IgnoreParenCasts();
@@ -1356,7 +1534,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
/// function that should return a value. Check that we don't fall off the end
/// of a noreturn function. We assume that functions and blocks not marked
/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1394,7 +1573,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
return;
// FIXME: Function try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
@@ -1421,7 +1600,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
/// that should return a value. Check that we don't fall off the end of a
/// noreturn block. We assume that functions and blocks not marked noreturn
/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1447,7 +1627,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
return;
// FIXME: Funtion try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
@@ -1878,6 +2058,30 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
Context.getCanonicalType(Ty));
}
+ case UnqualifiedId::IK_ConstructorTemplateId: {
+ // In well-formed code, we can only have a constructor
+ // template-id that refers to the current context, so go there
+ // to find the actual type being constructed.
+ CXXRecordDecl *CurClass = dyn_cast<CXXRecordDecl>(CurContext);
+ if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name)
+ return DeclarationName();
+
+ // Determine the type of the class being constructed.
+ QualType CurClassType;
+ if (ClassTemplateDecl *ClassTemplate
+ = CurClass->getDescribedClassTemplate())
+ CurClassType = ClassTemplate->getInjectedClassNameType(Context);
+ else
+ CurClassType = Context.getTypeDeclType(CurClass);
+
+ // FIXME: Check two things: that the template-id names the same type as
+ // CurClassType, and that the template-id does not occur when the name
+ // was qualified.
+
+ return Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(CurClassType));
+ }
+
case UnqualifiedId::IK_DestructorName: {
QualType Ty = GetTypeFromParser(Name.DestructorName);
if (Ty.isNull())
@@ -3393,7 +3597,12 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (NewFD->isOverloadedOperator() &&
CheckOverloadedOperatorDeclaration(NewFD))
return NewFD->setInvalidDecl();
-
+
+ // Extra checking for C++0x literal operators (C++0x [over.literal]).
+ if (NewFD->getLiteralIdentifier() &&
+ CheckLiteralOperatorDeclaration(NewFD))
+ return NewFD->setInvalidDecl();
+
// In C++, check default arguments now that we have merged decls. Unless
// the lexical context is the class, because in this case this is done
// during delayed parsing anyway.
@@ -3717,7 +3926,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
if (getLangOptions().CPlusPlus) {
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
- if (const ArrayType *Array = Context.getAsArrayType(InitType))
+ while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
if (InitType->isRecordType())
FinalizeVarWithDestructor(VDecl, InitType);
@@ -4267,6 +4476,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
+ AnalysisContext AC(dcl);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -4281,7 +4491,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
else
- CheckFallThroughForFunctionDef(FD, Body);
+ CheckFallThroughForFunctionDef(FD, Body, AC);
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
@@ -4293,7 +4503,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- CheckFallThroughForFunctionDef(MD, Body);
+ CheckFallThroughForFunctionDef(MD, Body, AC);
MD->setEndLoc(Body->getLocEnd());
if (!MD->isInvalidDecl())
@@ -4351,6 +4561,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
if (!Body) return D;
+ CheckUnreachable(AC);
+
// Verify that that gotos and switch cases don't jump into scopes illegally.
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(Body);
@@ -4657,8 +4869,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.isAmbiguous())
return DeclPtrTy();
- // A tag 'foo::bar' must already exist.
if (Previous.empty()) {
+ // Name lookup did not find anything. However, if the
+ // nested-name-specifier refers to the current instantiation,
+ // and that current instantiation has any dependent base
+ // classes, we might find something at instantiation time: treat
+ // this as a dependent elaborated-type-specifier.
+ if (Previous.wasNotFoundInCurrentInstantiation()) {
+ IsDependent = true;
+ return DeclPtrTy();
+ }
+
+ // A tag 'foo::bar' must already exist.
Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
Name = 0;
Invalid = true;
@@ -5054,6 +5276,29 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD,
"Broken injected-class-name");
}
+// Traverses the class and any nested classes, making a note of any
+// dynamic classes that have no key function so that we can mark all of
+// their virtual member functions as "used" at the end of the translation
+// unit. This ensures that all functions needed by the vtable will get
+// instantiated/synthesized.
+static void
+RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record,
+ SourceLocation Loc) {
+ // We don't look at dependent or undefined classes.
+ if (Record->isDependentContext() || !Record->isDefinition())
+ return;
+
+ if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record))
+ S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc));
+
+ for (DeclContext::decl_iterator D = Record->decls_begin(),
+ DEnd = Record->decls_end();
+ D != DEnd; ++D) {
+ if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D))
+ RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc);
+ }
+}
+
void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
SourceLocation RBraceLoc) {
AdjustDeclIfTemplate(TagD);
@@ -5066,6 +5311,10 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
+ if (isa<CXXRecordDecl>(Tag) && !Tag->getDeclContext()->isRecord())
+ RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag),
+ RBraceLoc);
+
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 094e5b56e558..1a12208e5a94 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -925,14 +926,19 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
// If the target wants to validate the section specifier, make it happen.
std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString());
- if (Error.empty()) {
- D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
+ if (!Error.empty()) {
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
+ << Error;
return;
}
- S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target)
- << Error;
-
+ // This attribute cannot be applied to local variables.
+ if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) {
+ S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) SectionAttr(SE->getString()));
}
static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1959,7 +1965,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D,
// Just ignore
break;
default:
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ // Ask target about the attribute.
+ const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
+ if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
break;
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 204d7764682b..a81a04e45e18 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -270,18 +270,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
ParmVarDecl *NewParam = New->getParamDecl(p);
if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) {
- // FIXME: If the parameter doesn't have an identifier then the location
- // points to the '=' which means that the fixit hint won't remove any
- // extra spaces between the type and the '='.
- SourceLocation Begin = NewParam->getLocation();
- if (NewParam->getIdentifier())
- Begin = PP.getLocForEndOfToken(Begin);
-
+ // FIXME: If we knew where the '=' was, we could easily provide a fix-it
+ // hint here. Alternatively, we could walk the type-source information
+ // for NewParam to find the last source location in the type... but it
+ // isn't worth the effort right now. This is the kind of test case that
+ // is hard to get right:
+
+ // int f(int);
+ // void g(int (*fp)(int) = f);
+ // void g(int (*fp)(int) = &f);
Diag(NewParam->getLocation(),
diag::err_param_default_argument_redefinition)
- << NewParam->getDefaultArgRange()
- << CodeModificationHint::CreateRemoval(SourceRange(Begin,
- NewParam->getLocEnd()));
+ << NewParam->getDefaultArgRange();
// Look for the function declaration where the default argument was
// actually written, which may be a declaration prior to Old.
@@ -424,6 +424,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
/// the innermost class.
bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
const CXXScopeSpec *SS) {
+ assert(getLangOptions().CPlusPlus && "No class names in C!");
+
CXXRecordDecl *CurDecl;
if (SS && SS->isSet() && !SS->isInvalid()) {
DeclContext *DC = computeDeclContext(*SS, true);
@@ -1072,6 +1074,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
<< MemberOrBase << true << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
+ Diag(Member->getLocation(), diag::note_previous_decl)
+ << Member->getDeclName();
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
LParenLoc, RParenLoc);
@@ -1089,7 +1093,14 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
<< MemberOrBase << false << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
-
+
+ const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
+ : VirtualBaseSpec;
+ Diag(BaseSpec->getSourceRange().getBegin(),
+ diag::note_base_class_specified_here)
+ << BaseSpec->getType()
+ << BaseSpec->getSourceRange();
+
TyD = Type;
}
}
@@ -2054,7 +2065,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (!Record->isDependentType())
AddImplicitlyDeclaredMembersToClass(Record);
-
+
if (Record->isInvalidDecl())
return;
@@ -2734,18 +2745,23 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
<< ClassType << ConvType;
}
- if (Conversion->getPreviousDeclaration()) {
- const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+ if (Conversion->getPrimaryTemplate()) {
+ // ignore specializations
+ } else if (Conversion->getPreviousDeclaration()) {
if (FunctionTemplateDecl *ConversionTemplate
- = Conversion->getDescribedFunctionTemplate())
- ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
- if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion))
+ = Conversion->getDescribedFunctionTemplate()) {
+ if (ClassDecl->replaceConversion(
+ ConversionTemplate->getPreviousDeclaration(),
+ ConversionTemplate))
+ return DeclPtrTy::make(ConversionTemplate);
+ } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(),
+ Conversion))
return DeclPtrTy::make(Conversion);
assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
} else if (FunctionTemplateDecl *ConversionTemplate
= Conversion->getDescribedFunctionTemplate())
ClassDecl->addConversionFunction(ConversionTemplate);
- else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+ else
ClassDecl->addConversionFunction(Conversion);
return DeclPtrTy::make(Conversion);
@@ -2986,6 +3002,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ case UnqualifiedId::IK_ConstructorTemplateId:
// C++0x inherited constructors.
if (getLangOptions().CPlusPlus0x) break;
@@ -4184,7 +4201,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
else
Diag(Loc, diag::err_ovl_no_viable_function_in_init)
<< ClassType << Range;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return 0;
case OR_Ambiguous:
@@ -4192,7 +4209,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
else
Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
return 0;
case OR_Deleted:
@@ -4207,7 +4224,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
<< Best->Function->isDeleted()
<< RD->getDeclName() << Range;
}
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return 0;
}
@@ -4373,8 +4390,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
// Most paths end in a failed conversion.
- if (ICS)
- ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
+ if (ICS) {
+ ICS->setBad();
+ ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType);
+ }
// C++ [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4412,7 +4431,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// has a type that is a derived class of the parameter type,
// in which case the implicit conversion sequence is a
// derived-to-base Conversion (13.3.3.1).
- ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->setStandard();
ICS->Standard.First = ICK_Identity;
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
@@ -4497,7 +4516,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// conversion or, if the conversion function returns an
// entity of a type that is a derived class of the parameter
// type, a derived-to-base Conversion.
- ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ ICS->setUserDefined();
ICS->UserDefined.Before = Best->Conversions[0].Standard;
ICS->UserDefined.After = Best->FinalConversion;
ICS->UserDefined.ConversionFunction = Best->Function;
@@ -4523,15 +4542,16 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
case OR_Ambiguous:
if (ICS) {
+ ICS->setAmbiguous();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
if (Cand->Viable)
- ICS->ConversionFunctionSet.push_back(Cand->Function);
+ ICS->Ambiguous.addConversion(Cand->Function);
break;
}
Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType()
<< Init->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1);
return true;
case OR_No_Viable_Function:
@@ -4600,7 +4620,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
RefRelationship >= Ref_Compatible_With_Added_Qualification) {
if (ICS) {
- ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS->setStandard();
ICS->Standard.First = ICK_Identity;
ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
ICS->Standard.Third = ICK_Identity;
@@ -4672,30 +4692,27 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
/*InOverloadResolution=*/false);
// Of course, that's still a reference binding.
- if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) {
+ if (ICS->isStandard()) {
ICS->Standard.ReferenceBinding = true;
ICS->Standard.RRefBinding = isRValRef;
- } else if (ICS->ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) {
+ } else if (ICS->isUserDefined()) {
ICS->UserDefined.After.ReferenceBinding = true;
ICS->UserDefined.After.RRefBinding = isRValRef;
}
- return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
+ return ICS->isBad();
} else {
ImplicitConversionSequence Conversions;
bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing,
false, false,
Conversions);
if (badConversion) {
- if ((Conversions.ConversionKind ==
- ImplicitConversionSequence::BadConversion)
- && !Conversions.ConversionFunctionSet.empty()) {
+ if (Conversions.isAmbiguous()) {
Diag(DeclLoc,
diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange();
- for (int j = Conversions.ConversionFunctionSet.size()-1;
+ for (int j = Conversions.Ambiguous.conversions().size()-1;
j >= 0; j--) {
- FunctionDecl *Func = Conversions.ConversionFunctionSet[j];
- Diag(Func->getLocation(), diag::err_ovl_candidate);
+ FunctionDecl *Func = Conversions.Ambiguous.conversions()[j];
+ NoteOverloadCandidate(Func);
}
}
else {
@@ -4993,6 +5010,88 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
return false;
}
+/// CheckLiteralOperatorDeclaration - Check whether the declaration
+/// of this literal operator function is well-formed. If so, returns
+/// false; otherwise, emits appropriate diagnostics and returns true.
+bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
+ DeclContext *DC = FnDecl->getDeclContext();
+ Decl::Kind Kind = DC->getDeclKind();
+ if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace &&
+ Kind != Decl::LinkageSpec) {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace)
+ << FnDecl->getDeclName();
+ return true;
+ }
+
+ bool Valid = false;
+
+ // FIXME: Check for the one valid template signature
+ // template <char...> type operator "" name();
+
+ if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) {
+ // Check the first parameter
+ QualType T = (*Param)->getType();
+
+ // unsigned long long int and long double are allowed, but only
+ // alone.
+ // We also allow any character type; their omission seems to be a bug
+ // in n3000
+ if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
+ Context.hasSameType(T, Context.LongDoubleTy) ||
+ Context.hasSameType(T, Context.CharTy) ||
+ Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.Char16Ty) ||
+ Context.hasSameType(T, Context.Char32Ty)) {
+ if (++Param == FnDecl->param_end())
+ Valid = true;
+ goto FinishedParams;
+ }
+
+ // Otherwise it must be a pointer to const; let's strip those.
+ const PointerType *PT = T->getAs<PointerType>();
+ if (!PT)
+ goto FinishedParams;
+ T = PT->getPointeeType();
+ if (!T.isConstQualified())
+ goto FinishedParams;
+ T = T.getUnqualifiedType();
+
+ // Move on to the second parameter;
+ ++Param;
+
+ // If there is no second parameter, the first must be a const char *
+ if (Param == FnDecl->param_end()) {
+ if (Context.hasSameType(T, Context.CharTy))
+ Valid = true;
+ goto FinishedParams;
+ }
+
+ // const char *, const wchar_t*, const char16_t*, and const char32_t*
+ // are allowed as the first parameter to a two-parameter function
+ if (!(Context.hasSameType(T, Context.CharTy) ||
+ Context.hasSameType(T, Context.WCharTy) ||
+ Context.hasSameType(T, Context.Char16Ty) ||
+ Context.hasSameType(T, Context.Char32Ty)))
+ goto FinishedParams;
+
+ // The second and final parameter must be an std::size_t
+ T = (*Param)->getType().getUnqualifiedType();
+ if (Context.hasSameType(T, Context.getSizeType()) &&
+ ++Param == FnDecl->param_end())
+ Valid = true;
+ }
+
+ // FIXME: This diagnostic is absolutely terrible.
+FinishedParams:
+ if (!Valid) {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
+ << FnDecl->getDeclName();
+ return true;
+ }
+
+ return false;
+}
+
/// ActOnStartLinkageSpecification - Parsed the beginning of a C++
/// linkage specification, including the language and (if present)
/// the '{'. ExternLoc is the location of the 'extern', LangLoc is
@@ -5693,55 +5792,56 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
if (!RD->isDynamicClass())
return;
- if (!MD->isOutOfLine()) {
- // The only inline functions we care about are constructors. We also defer
- // marking the virtual members as referenced until we've reached the end
- // of the translation unit. We do this because we need to know the key
- // function of the class in order to determine the key function.
- if (isa<CXXConstructorDecl>(MD))
- ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc));
+ // Ignore declarations that are not definitions.
+ if (!MD->isThisDeclarationADefinition())
return;
- }
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-
- if (!KeyFunction) {
- // This record does not have a key function, so we assume that the vtable
- // will be emitted when it's used by the constructor.
- if (!isa<CXXConstructorDecl>(MD))
+ if (isa<CXXConstructorDecl>(MD)) {
+ switch (MD->getParent()->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ // Classes that aren't instantiations of templates don't need their
+ // virtual methods marked until we see the definition of the key
+ // function.
+ return;
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ // This is a constructor of a class template; mark all of the virtual
+ // members as referenced to ensure that they get instantiatied.
+ break;
+ }
+ } else if (!MD->isOutOfLine()) {
+ // Consider only out-of-line definitions of member functions. When we see
+ // an inline definition, it's too early to compute the key function.
+ return;
+ } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) {
+ // If this is not the key function, we don't need to mark virtual members.
+ if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
- } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) {
- // We don't have the right key function.
+ } else {
+ // The class has no key function, so we've already noted that we need to
+ // mark the virtual members of this class.
return;
}
- // Mark the members as referenced.
- MarkVirtualMembersReferenced(Loc, RD);
- ClassesWithUnmarkedVirtualMembers.erase(RD);
+ // We will need to mark all of the virtual members as referenced to build the
+ // vtable.
+ ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));
}
bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
if (ClassesWithUnmarkedVirtualMembers.empty())
return false;
- for (std::map<CXXRecordDecl *, SourceLocation>::iterator i =
- ClassesWithUnmarkedVirtualMembers.begin(),
- e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) {
- CXXRecordDecl *RD = i->first;
-
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
- if (KeyFunction) {
- // We know that the class has a key function. If the key function was
- // declared in this translation unit, then it the class decl would not
- // have been in the ClassesWithUnmarkedVirtualMembers map.
- continue;
- }
-
- SourceLocation Loc = i->second;
+ while (!ClassesWithUnmarkedVirtualMembers.empty()) {
+ CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first;
+ SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second;
+ ClassesWithUnmarkedVirtualMembers.pop_back();
MarkVirtualMembersReferenced(Loc, RD);
}
- ClassesWithUnmarkedVirtualMembers.clear();
return true;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index beadb588f3e9..f2fc1f4f56df 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
@@ -133,6 +134,19 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName);
+
+ if (!PrevDecl) {
+ // Try to correct for a typo in the superclass name.
+ LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ Diag(SuperLoc, diag::err_undef_superclass_suggest)
+ << SuperName << ClassName << PrevDecl->getDeclName();
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl)
+ << PrevDecl->getDeclName();
+ }
+ }
+
if (PrevDecl == IDecl) {
Diag(SuperLoc, diag::err_recursive_superclass)
<< SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
@@ -317,6 +331,18 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
for (unsigned i = 0; i != NumProtocols; ++i) {
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first);
if (!PDecl) {
+ LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
+ LookupObjCProtocolName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+ Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
+ << ProtocolId[i].first << R.getLookupName();
+ Diag(PDecl->getLocation(), diag::note_previous_decl)
+ << PDecl->getDeclName();
+ }
+ }
+
+ if (!PDecl) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol)
<< ProtocolId[i].first;
continue;
@@ -568,7 +594,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
/// Check that class of this category is already completely declared.
if (!IDecl || IDecl->isForwardDecl()) {
CDecl->setInvalidDecl();
@@ -616,7 +642,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
SourceLocation AtCatImplLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
- ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
ObjCCategoryDecl *CatIDecl = 0;
if (IDecl) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
@@ -667,13 +693,33 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- } else {
- // Is there an interface declaration of this class; if not, warn!
- IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
- if (!IDecl || IDecl->isForwardDecl()) {
+ } else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
+ // If this is a forward declaration of an interface, warn.
+ if (IDecl->isForwardDecl()) {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
IDecl = 0;
}
+ } else {
+ // We did not find anything with the name ClassName; try to correct for
+ // typos in the class name.
+ LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
+ if (CorrectTypo(R, TUScope, 0) &&
+ (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+ // Suggest the (potentially) correct interface name. However, put the
+ // fix-it hint itself in a separate note, since changing the name in
+ // the warning would make the fix-it change semantics.However, don't
+ // provide a code-modification hint or use the typo name for recovery,
+ // because this is just a warning. The program may actually be correct.
+ Diag(ClassLoc, diag::warn_undef_interface_suggest)
+ << ClassName << R.getLookupName();
+ Diag(IDecl->getLocation(), diag::note_previous_decl)
+ << R.getLookupName()
+ << CodeModificationHint::CreateReplacement(ClassLoc,
+ R.getLookupName().getAsString());
+ IDecl = 0;
+ } else {
+ Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
+ }
}
// Check that super class name is valid class name
@@ -1437,8 +1483,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getLocation());
if (SetterMethod) {
- if (Context.getCanonicalType(SetterMethod->getResultType())
- != Context.VoidTy)
+ ObjCPropertyDecl::PropertyAttributeKind CAttr =
+ property->getPropertyAttributes();
+ if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
+ Context.getCanonicalType(SetterMethod->getResultType()) !=
+ Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
((*SetterMethod->param_begin())->getType() != property->getType())) {
@@ -1563,7 +1612,8 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl,
// Note: For class/category implemenations, allMethods/allProperties is
// always null.
-void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
+void Sema::ActOnAtEnd(SourceRange AtEnd,
+ DeclPtrTy classDecl,
DeclPtrTy *allMethods, unsigned allNum,
DeclPtrTy *allProperties, unsigned pNum,
DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
@@ -1580,9 +1630,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
- if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) {
- AtEndLoc = ClassDecl->getLocation();
- Diag(AtEndLoc, diag::warn_missing_atend);
+ if (!isInterfaceDeclKind && AtEnd.isInvalid()) {
+ // FIXME: This is wrong. We shouldn't be pretending that there is
+ // an '@end' in the declaration.
+ SourceLocation L = ClassDecl->getLocation();
+ AtEnd.setBegin(L);
+ AtEnd.setEnd(L);
+ Diag(L, diag::warn_missing_atend);
}
DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
@@ -1659,17 +1713,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl,
E = CDecl->prop_end();
I != E; ++I)
ProcessPropertyDecl(*I, CDecl);
- CDecl->setAtEndLoc(AtEndLoc);
+ CDecl->setAtEndRange(AtEnd);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
- IC->setAtEndLoc(AtEndLoc);
+ IC->setAtEndRange(AtEnd);
if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) {
ImplMethodsVsClassMethods(IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
}
} else if (ObjCCategoryImplDecl* CatImplClass =
dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) {
- CatImplClass->setAtEndLoc(AtEndLoc);
+ CatImplClass->setAtEndRange(AtEnd);
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
@@ -1980,6 +2034,32 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(AtLoc, diag::warn_property_attr_mismatch);
Diag(PIDecl->getLocation(), diag::note_property_declare);
}
+ DeclContext *DC = dyn_cast<DeclContext>(CCPrimary);
+ assert(DC && "ClassDecl is not a DeclContext");
+ DeclContext::lookup_result Found =
+ DC->lookup(PIDecl->getDeclName());
+ bool PropertyInPrimaryClass = false;
+ for (; Found.first != Found.second; ++Found.first)
+ if (isa<ObjCPropertyDecl>(*Found.first)) {
+ PropertyInPrimaryClass = true;
+ break;
+ }
+ if (!PropertyInPrimaryClass) {
+ // Protocol is not in the primary class. Must build one for it.
+ ObjCDeclSpec ProtocolPropertyODS;
+ // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and
+ // ObjCPropertyDecl::PropertyAttributeKind have identical values.
+ // Should consolidate both into one enum type.
+ ProtocolPropertyODS.setPropertyAttributes(
+ (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind);
+ DeclPtrTy ProtocolPtrTy =
+ ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS,
+ PIDecl->getGetterName(),
+ PIDecl->getSetterName(),
+ DeclPtrTy::make(CCPrimary), isOverridingProperty,
+ MethodImplKind);
+ PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>();
+ }
PIDecl->makeitReadWriteAttribute();
if (Attributes & ObjCDeclSpec::DQ_PR_retain)
PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 7bf04d88cd59..034accd1c4e1 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -565,7 +566,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
IsDerivedFrom(ThisType, AnonFieldType)) {
// Our base object expression is "this".
BaseObjectExpr = new (Context) CXXThisExpr(Loc,
- MD->getThisType(Context));
+ MD->getThisType(Context),
+ /*isImplicit=*/true);
BaseObjectIsPointer = true;
}
} else {
@@ -943,7 +945,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
<< SS.getRange()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
-
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
+
// Tell the callee to try to recover.
return false;
}
@@ -1006,11 +1011,18 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
+ // -- an identifier that was declared with a dependent type,
+ // (note: handled after lookup)
+ // -- a template-id that is dependent,
+ // (note: handled in BuildTemplateIdExpr)
+ // -- a conversion-function-id that specifies a dependent type,
// -- 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)) {
+ if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+ Name.getCXXNameType()->isDependentType()) ||
+ (SS.isSet() && IsDependentIdExpression(*this, SS))) {
return ActOnDependentIdExpression(SS, Name, NameLoc,
isAddressOfOperand,
TemplateArgs);
@@ -1022,12 +1034,13 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
// Just re-use the lookup done by isTemplateName.
DecomposeTemplateName(R, Id);
} else {
- LookupParsedName(R, S, &SS, true);
+ bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl());
+ LookupParsedName(R, S, &SS, !IvarLookupFollowUp);
// 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 (IvarLookupFollowUp) {
+ OwningExprResult E(LookupInObjCMethod(R, S, II, true));
if (E.isInvalid())
return ExprError();
@@ -1059,6 +1072,16 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
assert(!R.empty() &&
"DiagnoseEmptyLookup returned false but added no results");
+
+ // If we found an Objective-C instance variable, let
+ // LookupInObjCMethod build the appropriate expression to
+ // reference the ivar.
+ if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
+ R.clear();
+ OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
+ assert(E.isInvalid() || E.get());
+ return move(E);
+ }
}
}
@@ -1197,7 +1220,8 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS,
/// Returns a null sentinel to indicate trivial success.
Sema::OwningExprResult
Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II) {
+ IdentifierInfo *II,
+ bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
// There are two cases to handle here. 1) scoped lookup could have failed,
@@ -1278,7 +1302,18 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
T = Context.getObjCClassType();
return Owned(new (Context) ObjCSuperExpr(Loc, T));
}
-
+ if (Lookup.empty() && II && AllowBuiltinCreation) {
+ // FIXME. Consolidate this with similar code in LookupName.
+ if (unsigned BuiltinID = II->getBuiltinID()) {
+ if (!(getLangOptions().CPlusPlus &&
+ Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
+ NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
+ S, Lookup.isForRedeclaration(),
+ Lookup.getNameLoc());
+ if (D) Lookup.addDecl(D);
+ }
+ }
+ }
// Sentinel value saying that we didn't do anything special.
return Owned((Expr*) 0);
}
@@ -1353,13 +1388,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
Expr *This = 0; // null signifies implicit access
if (IsKnownInstance) {
- This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true);
}
return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
- SS, R, TemplateArgs);
+ SS,
+ /*FirstQualifierInScope*/ 0,
+ R, TemplateArgs);
}
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
@@ -1521,6 +1561,18 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// as they do not get snapshotted.
//
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ if (VD->getType().getTypePtr()->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_ref_vm_type);
+ Diag(D->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
+ if (VD->getType()->isArrayType()) {
+ Diag(Loc, diag::err_ref_array_type);
+ Diag(D->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
MarkDeclarationReferenced(Loc, VD);
QualType ExprTy = VD->getType().getNonReferenceType();
// The BlocksAttr indicates the variable is bound by-reference.
@@ -2252,7 +2304,7 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
}
}
- assert(BaseType->isDependentType());
+ assert(BaseType->isDependentType() || Name.isDependentName());
// 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.
@@ -2378,6 +2430,9 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
<< Name << DC << R.getLookupName() << SS.getRange()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+ << ND->getDeclName();
return false;
} else {
R.clear();
@@ -2418,8 +2473,7 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
} else {
OwningExprResult Result =
LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- /*ObjCImpDecl*/ DeclPtrTy());
+ SS, /*ObjCImpDecl*/ DeclPtrTy());
if (Result.isInvalid()) {
Owned(Base);
@@ -2431,13 +2485,15 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
}
return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
- OpLoc, IsArrow, SS, R, TemplateArgs);
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
Sema::OwningExprResult
Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
+ NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
Expr *BaseExpr = Base.takeAs<Expr>();
@@ -2467,11 +2523,17 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
return ExprError();
}
- // Diagnose qualified lookups that find only declarations from a
- // non-base type. Note that it's okay for lookup to find
- // declarations from a non-base type as long as those aren't the
- // ones picked by overload resolution.
- if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
+ // Diagnose lookups that find only declarations from a non-base
+ // type. This is possible for either qualified lookups (which may
+ // have been qualified with an unrelated type) or implicit member
+ // expressions (which were found with unqualified lookup and thus
+ // may have come from an enclosing scope). Note that it's okay for
+ // lookup to find declarations from a non-base type as long as those
+ // aren't the ones picked by overload resolution.
+ if ((SS.isSet() || !BaseExpr ||
+ (isa<CXXThisExpr>(BaseExpr) &&
+ cast<CXXThisExpr>(BaseExpr)->isImplicit())) &&
+ CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
// Construct an unresolved result if we in fact got an unresolved
@@ -2513,7 +2575,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
if (!IsInstanceMember(MemberDecl))
return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
- BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType);
+ SourceLocation Loc = R.getNameLoc();
+ if (SS.getRange().isValid())
+ Loc = SS.getRange().getBegin();
+ BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
}
bool ShouldCheckUse = true;
@@ -2610,7 +2675,6 @@ Sema::OwningExprResult
Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
bool &IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
- NamedDecl *FirstQualifierInScope,
DeclPtrTy ObjCImpDecl) {
assert(BaseExpr && "no base expression");
@@ -2848,6 +2912,22 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
ObjCInterfaceDecl *ClassDeclared;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+ if (!IV) {
+ // Attempt to correct for typos in ivar names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupMemberName);
+ if (CorrectTypo(Res, 0, 0, IDecl) &&
+ (IV = Res.getAsSingle<ObjCIvarDecl>())) {
+ Diag(R.getNameLoc(),
+ diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName << IV->getDeclName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
+ Diag(IV->getLocation(), diag::note_previous_decl)
+ << IV->getDeclName();
+ }
+ }
+
if (IV) {
// If the decl being referenced had an error, return an error for this
// sub-expr without emitting another error, in order to avoid cascading
@@ -3014,6 +3094,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
+
+ // Attempt to correct for typos in property names.
+ LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
+ LookupOrdinaryName);
+ if (CorrectTypo(Res, 0, 0, IFace, false, OPT) &&
+ Res.getAsSingle<ObjCPropertyDecl>()) {
+ Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
+ << MemberName << BaseType << Res.getLookupName()
+ << CodeModificationHint::CreateReplacement(R.getNameLoc(),
+ Res.getLookupName().getAsString());
+ ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
+ Diag(Property->getLocation(), diag::note_previous_decl)
+ << Property->getDeclName();
+
+ return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl);
+ }
+
return ExprError(Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
@@ -3101,7 +3199,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
- if (Base->getType()->isDependentType()) {
+ if (Base->getType()->isDependentType() || Name.isDependentName()) {
Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
@@ -3114,8 +3212,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
DecomposeTemplateName(R, Id);
} else {
Result = LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- ObjCImpDecl);
+ SS, ObjCImpDecl);
if (Result.isInvalid()) {
Owned(Base);
@@ -3136,7 +3233,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
}
Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(),
- OpLoc, IsArrow, SS, R, TemplateArgs);
+ OpLoc, IsArrow, SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
return move(Result);
@@ -4717,8 +4815,7 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
return QualType();
}
-inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
- Expr *&rex) {
+QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) {
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhsType =
@@ -4779,19 +4876,27 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex,
return QualType();
}
-inline QualType Sema::CheckMultiplyDivideOperands(
- Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
+QualType Sema::CheckMultiplyDivideOperands(
+ Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
return CheckVectorOperands(Loc, lex, rex);
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
- return compType;
- return InvalidOperands(Loc, lex, rex);
+ if (!lex->getType()->isArithmeticType() ||
+ !rex->getType()->isArithmeticType())
+ return InvalidOperands(Loc, lex, rex);
+
+ // Check for division by zero.
+ if (isDiv &&
+ rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero)
+ << rex->getSourceRange());
+
+ return compType;
}
-inline QualType Sema::CheckRemainderOperands(
+QualType Sema::CheckRemainderOperands(
Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
@@ -4801,12 +4906,18 @@ inline QualType Sema::CheckRemainderOperands(
QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
- if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType())
- return compType;
- return InvalidOperands(Loc, lex, rex);
+ if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType())
+ return InvalidOperands(Loc, lex, rex);
+
+ // Check for remainder by zero.
+ if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull))
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero)
+ << rex->getSourceRange());
+
+ return compType;
}
-inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
+QualType Sema::CheckAdditionOperands( // C99 6.5.6
Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(Loc, lex, rex);
@@ -5072,80 +5183,6 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return LHSTy;
}
-/// \brief Implements -Wsign-compare.
-///
-/// \param lex the left-hand expression
-/// \param rex the right-hand expression
-/// \param OpLoc the location of the joining operator
-/// \param Equality whether this is an "equality-like" join, which
-/// suppresses the warning in some cases
-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 (ExprEvalContexts.back().Context == Unevaluated)
- return;
-
- QualType lt = lex->getType(), rt = rex->getType();
-
- // Only warn if both operands are integral.
- if (!lt->isIntegerType() || !rt->isIntegerType())
- return;
-
- // If either expression is value-dependent, don't warn. We'll get another
- // chance at instantiation time.
- if (lex->isValueDependent() || rex->isValueDependent())
- return;
-
- // The rule is that the signed operand becomes unsigned, so isolate the
- // signed operand.
- Expr *signedOperand, *unsignedOperand;
- if (lt->isSignedIntegerType()) {
- if (rt->isSignedIntegerType()) return;
- signedOperand = lex;
- unsignedOperand = rex;
- } else {
- if (!rt->isSignedIntegerType()) return;
- signedOperand = rex;
- unsignedOperand = lex;
- }
-
- // If the unsigned type is strictly smaller than the signed type,
- // then (1) the result type will be signed and (2) the unsigned
- // value will fit fully within the signed type, and thus the result
- // of the comparison will be exact.
- if (Context.getIntWidth(signedOperand->getType()) >
- Context.getIntWidth(unsignedOperand->getType()))
- return;
-
- // If the value is a non-negative integer constant, then the
- // signed->unsigned conversion won't change it.
- llvm::APSInt value;
- if (signedOperand->isIntegerConstantExpr(value, Context)) {
- assert(value.isSigned() && "result of signed expression not signed");
-
- if (value.isNonNegative())
- return;
- }
-
- if (Equality) {
- // For (in)equality comparisons, if the unsigned operand is a
- // constant which cannot collide with a overflowed signed operand,
- // then reinterpreting the signed operand as unsigned will not
- // change the result of the comparison.
- if (unsignedOperand->isIntegerConstantExpr(value, Context)) {
- assert(!value.isSigned() && "result of unsigned expression is signed");
-
- // 2's complement: test the top bit.
- if (value.isNonNegative())
- return;
- }
- }
-
- Diag(OpLoc, PD)
- << lex->getType() << rex->getType()
- << lex->getSourceRange() << rex->getSourceRange();
-}
-
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
unsigned OpaqueOpc, bool isRelational) {
@@ -5181,7 +5218,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped))
if (DRL->getDecl() == DRR->getDecl() &&
!isa<EnumConstantDecl>(DRL->getDecl()))
- Diag(Loc, diag::warn_selfcomparison);
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
if (isa<CastExpr>(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();
@@ -5216,15 +5253,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
case BinaryOperator::NE: resultComparison = ") != 0"; break;
default: assert(false && "Invalid comparison operator");
}
- Diag(Loc, diag::warn_stringcompare)
- << isa<ObjCEncodeExpr>(literalStringStripped)
- << literalString->getSourceRange()
- << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
- << CodeModificationHint::CreateInsertion(lex->getLocStart(),
- "strcmp(")
- << CodeModificationHint::CreateInsertion(
- PP.getLocForEndOfToken(rex->getLocEnd()),
- resultComparison);
+
+ DiagRuntimeBehavior(Loc,
+ PDiag(diag::warn_stringcompare)
+ << isa<ObjCEncodeExpr>(literalStringStripped)
+ << literalString->getSourceRange()
+ << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ")
+ << CodeModificationHint::CreateInsertion(lex->getLocStart(),
+ "strcmp(")
+ << CodeModificationHint::CreateInsertion(
+ PP.getLocForEndOfToken(rex->getLocEnd()),
+ resultComparison));
}
}
@@ -5488,7 +5527,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex,
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens()))
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens()))
if (DRL->getDecl() == DRR->getDecl())
- Diag(Loc, diag::warn_selfcomparison);
+ DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison));
}
// Check for comparisons of floating point operands using != and ==.
@@ -5776,7 +5815,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
<< PointeeTy << Op->getSourceRange();
return QualType();
}
- } else if (ResType->isComplexType()) {
+ } else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
Diag(OpLoc, diag::ext_integer_increment_complex)
<< ResType << Op->getSourceRange();
@@ -5877,7 +5916,22 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
NamedDecl *dcl = getPrimaryDecl(op);
Expr::isLvalueResult lval = op->isLvalue(Context);
- if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(op);
+ if (lval == Expr::LV_MemberFunction && ME &&
+ isa<CXXMethodDecl>(ME->getMemberDecl())) {
+ ValueDecl *dcl = cast<MemberExpr>(op)->getMemberDecl();
+ // &f where f is a member of the current object, or &o.f, or &p->f
+ // All these are not allowed, and we need to catch them before the dcl
+ // branch of the if, below.
+ Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+ << dcl;
+ // FIXME: Improve this diagnostic and provide a fixit.
+
+ // Now recover by acting as if the function had been accessed qualified.
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext()))
+ .getTypePtr());
+ } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
if (!op->getType()->isFunctionType()) {
@@ -6065,7 +6119,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BinaryOperator::Mul:
case BinaryOperator::Div:
- ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc);
+ ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false,
+ Opc == BinaryOperator::Div);
break;
case BinaryOperator::Rem:
ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc);
@@ -6101,7 +6156,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BinaryOperator::MulAssign:
case BinaryOperator::DivAssign:
- CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true);
+ CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true,
+ Opc == BinaryOperator::DivAssign);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull())
ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy);
@@ -6155,8 +6211,9 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
/// ParenRange in parentheses.
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
- SourceRange ParenRange)
-{
+ SourceRange ParenRange,
+ const PartialDiagnostic &SecondPD = PartialDiagnostic(0),
+ SourceRange SecondParenRange = SourceRange()) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
@@ -6168,6 +6225,21 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
Self.Diag(Loc, PD)
<< CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
<< CodeModificationHint::CreateInsertion(EndLoc, ")");
+
+ if (!SecondPD.getDiagID())
+ return;
+
+ EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
+ if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Self.Diag(Loc, SecondPD);
+ return;
+ }
+
+ Self.Diag(Loc, SecondPD)
+ << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << CodeModificationHint::CreateInsertion(EndLoc, ")");
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -6199,12 +6271,18 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
+ lhs->getSourceRange(),
+ PDiag(diag::note_precedence_bitwise_first)
+ << BinOp::getOpcodeStr(Opc),
SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()));
else if (BinOp::isComparisonOp(rhsopc))
SuggestParentheses(Self, OpLoc,
PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
+ rhs->getSourceRange(),
+ PDiag(diag::note_precedence_bitwise_first)
+ << BinOp::getOpcodeStr(Opc),
SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
}
@@ -6790,7 +6868,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
- CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
+ AnalysisContext AC(BSI->TheDecl);
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
+ CheckUnreachable(AC);
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
@@ -7256,6 +7336,8 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
<< E->getSourceRange()
<< CodeModificationHint::CreateInsertion(Open, "(")
<< CodeModificationHint::CreateInsertion(Close, ")");
+ Diag(Loc, diag::note_condition_assign_to_comparison)
+ << CodeModificationHint::CreateReplacement(Loc, "==");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 5f723f92146d..d10e11fdb4a3 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -179,7 +179,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext))
if (MD->isInstance())
return Owned(new (Context) CXXThisExpr(ThisLoc,
- MD->getThisType(Context)));
+ MD->getThisType(Context),
+ /*isImplicit=*/false));
return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
}
@@ -672,20 +673,20 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_No_Viable_Function:
Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/false);
+ PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs);
return true;
case OR_Ambiguous:
Diag(StartLoc, diag::err_ovl_ambiguous_call)
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ PrintOverloadCandidates(Candidates, OCD_ViableCandidates, Args, NumArgs);
return true;
case OR_Deleted:
Diag(StartLoc, diag::err_ovl_deleted_call)
<< Best->Function->isDeleted()
<< Name << Range;
- PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+ PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs);
return true;
}
assert(false && "Unreachable, bad result from BestViableFunction");
@@ -921,7 +922,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
<< Type << Ex->getSourceRange();
for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
CXXConversionDecl *Conv = ObjectPtrConversions[i];
- Diag(Conv->getLocation(), diag::err_ovl_candidate);
+ NoteOverloadCandidate(Conv);
}
return ExprError();
}
@@ -1074,7 +1075,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
bool Elidable,
ImplicitConversionSequence& ICS) {
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
if (Elidable && getLangOptions().CPlusPlus0x) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
@@ -1082,7 +1084,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
/*ForceRValue=*/true,
/*InOverloadResolution=*/false);
}
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
AllowExplicit,
@@ -1092,39 +1094,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return PerformImplicitConversion(From, ToType, ICS, Action);
}
-/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST
-/// for the derived to base conversion of the expression 'From'. All
-/// necessary information is passed in ICS.
-bool
-Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
- const ImplicitConversionSequence& ICS) {
- QualType BaseType =
- QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
- // Must do additional defined to base conversion.
- QualType DerivedType =
- QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr);
-
- From = new (Context) ImplicitCastExpr(
- DerivedType.getNonReferenceType(),
- CastKind,
- From,
- DerivedType->isLValueReferenceType());
- From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(),
- CastExpr::CK_DerivedToBase, From,
- BaseType->isLValueReferenceType());
- ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
- OwningExprResult FromResult =
- BuildCXXConstructExpr(
- ICS.UserDefined.After.CopyConstructor->getLocation(),
- BaseType,
- ICS.UserDefined.After.CopyConstructor,
- MultiExprArg(*this, (void **)&From, 1));
- if (FromResult.isInvalid())
- return true;
- From = FromResult.takeAs<Expr>();
- return false;
-}
-
/// PerformImplicitConversion - Perform an implicit conversion of the
/// expression From to the type ToType using the pre-computed implicit
/// conversion sequence ICS. Returns true if there was an error, false
@@ -1135,7 +1104,7 @@ bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
const ImplicitConversionSequence &ICS,
AssignmentAction Action, bool IgnoreBaseAccess) {
- switch (ICS.ConversionKind) {
+ switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
if (PerformImplicitConversion(From, ToType, ICS.Standard, Action,
IgnoreBaseAccess))
@@ -1186,23 +1155,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
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) {
- return BuildCXXDerivedToBaseExpr(From, CastKind, ICS);
- }
-
- if (ICS.UserDefined.After.CopyConstructor) {
- From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
- CastKind, From,
- ToType->isLValueReferenceType());
- return false;
- }
-
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
AA_Converting, IgnoreBaseAccess);
}
+
+ case ImplicitConversionSequence::AmbiguousConversion:
+ DiagnoseAmbiguousConversion(ICS, From->getExprLoc(),
+ PDiag(diag::err_typecheck_ambiguous_condition)
+ << From->getSourceRange());
+ return true;
case ImplicitConversionSequence::EllipsisConversion:
assert(false && "Cannot perform an ellipsis conversion");
@@ -1520,14 +1481,18 @@ QualType Sema::CheckPointerToMemberOperands(
/// \brief Get the target type of a standard or user-defined conversion.
static QualType TargetType(const ImplicitConversionSequence &ICS) {
- assert((ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion ||
- ICS.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) &&
- "function only valid for standard or user-defined conversions");
- if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion)
- return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr);
- return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
+ switch (ICS.getKind()) {
+ case ImplicitConversionSequence::StandardConversion:
+ return ICS.Standard.getToType();
+ case ImplicitConversionSequence::UserDefinedConversion:
+ return ICS.UserDefined.After.getToType();
+ case ImplicitConversionSequence::AmbiguousConversion:
+ return ICS.Ambiguous.getToType();
+ case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::BadConversion:
+ llvm_unreachable("function not valid for ellipsis or bad conversions");
+ }
+ return QualType(); // silence warnings
}
/// \brief Try to convert a type to another according to C++0x 5.16p3.
@@ -1557,19 +1522,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
/*ForceRValue=*/false,
&ICS))
{
- assert((ICS.ConversionKind ==
- ImplicitConversionSequence::StandardConversion ||
- ICS.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) &&
+ assert((ICS.isStandard() || ICS.isUserDefined()) &&
"expected a definite conversion");
bool DirectBinding =
- ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ?
- ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding;
+ ICS.isStandard() ? ICS.Standard.DirectBinding
+ : ICS.UserDefined.After.DirectBinding;
if (DirectBinding)
return false;
}
}
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
// -- If E2 is an rvalue, or if the conversion above cannot be done:
// -- if E1 and E2 have class type, and the underlying class types are
// the same or one is a base class of the other:
@@ -1665,8 +1627,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// handles the reference binding specially.
static bool ConvertForConditional(Sema &Self, Expr *&E,
const ImplicitConversionSequence &ICS) {
- if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
- ICS.Standard.ReferenceBinding) {
+ if (ICS.isStandard() && ICS.Standard.ReferenceBinding) {
assert(ICS.Standard.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
// FIXME: CheckReferenceInit should be able to reuse the ICS instead of
@@ -1678,8 +1639,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E,
/*AllowExplicit=*/false,
/*ForceRValue=*/false);
}
- if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
- ICS.UserDefined.After.ReferenceBinding) {
+ if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) {
assert(ICS.UserDefined.After.DirectBinding &&
"TryClassUnification should never generate indirect ref bindings");
return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
@@ -1767,10 +1727,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
return QualType();
- bool HaveL2R = ICSLeftToRight.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
- bool HaveR2L = ICSRightToLeft.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
+ bool HaveL2R = !ICSLeftToRight.isBad();
+ bool HaveR2L = !ICSRightToLeft.isBad();
// If both can be converted, [...] the program is ill-formed.
if (HaveL2R && HaveR2L) {
Diag(QuestionLoc, diag::err_conditional_ambiguous)
@@ -1837,6 +1795,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// type and the other is a null pointer constant; pointer conversions
// and qualification conversions are performed to bring them to their
// composite pointer type. The result is of the composite pointer type.
+ // -- The second and third operands have pointer to member type, or one has
+ // pointer to member type and the other is a null pointer constant;
+ // pointer to member conversions and qualification conversions are
+ // performed to bring them to a common type, whose cv-qualification
+ // shall match the cv-qualification of either the second or the third
+ // operand. The result is of the common type.
QualType Composite = FindCompositePointerType(LHS, RHS);
if (!Composite.isNull())
return Composite;
@@ -1846,83 +1810,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!Composite.isNull())
return Composite;
- // Fourth bullet is same for pointers-to-member. However, the possible
- // conversions are far more limited: we have null-to-pointer, upcast of
- // containing class, and second-level cv-ness.
- // cv-ness is not a union, but must match one of the two operands. (Which,
- // frankly, is stupid.)
- const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>();
- const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>();
- if (LMemPtr &&
- RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer);
- return LTy;
- }
- if (RMemPtr &&
- LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer);
- return RTy;
- }
- if (LMemPtr && RMemPtr) {
- QualType LPointee = LMemPtr->getPointeeType();
- QualType RPointee = RMemPtr->getPointeeType();
-
- QualifierCollector LPQuals, RPQuals;
- const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee));
- const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee));
-
- // First, we check that the unqualified pointee type is the same. If it's
- // not, there's no conversion that will unify the two pointers.
- if (LPCan == RPCan) {
-
- // Second, we take the greater of the two qualifications. If neither
- // is greater than the other, the conversion is not possible.
-
- Qualifiers MergedQuals = LPQuals + RPQuals;
-
- bool CompatibleQuals = true;
- if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() &&
- MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers())
- CompatibleQuals = false;
- else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace())
- // FIXME:
- // C99 6.5.15 as modified by TR 18037:
- // If the second and third operands are pointers into different
- // address spaces, the address spaces must overlap.
- CompatibleQuals = false;
- // FIXME: GC qualifiers?
-
- if (CompatibleQuals) {
- // Third, we check if either of the container classes is derived from
- // the other.
- QualType LContainer(LMemPtr->getClass(), 0);
- QualType RContainer(RMemPtr->getClass(), 0);
- QualType MoreDerived;
- if (Context.getCanonicalType(LContainer) ==
- Context.getCanonicalType(RContainer))
- MoreDerived = LContainer;
- else if (IsDerivedFrom(LContainer, RContainer))
- MoreDerived = LContainer;
- else if (IsDerivedFrom(RContainer, LContainer))
- MoreDerived = RContainer;
-
- if (!MoreDerived.isNull()) {
- // The type 'Q Pointee (MoreDerived::*)' is the common type.
- // We don't use ImpCastExprToType here because this could still fail
- // for ambiguous or inaccessible conversions.
- LPointee = Context.getQualifiedType(LPointee, MergedQuals);
- QualType Common
- = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr());
- if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting))
- return QualType();
- if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting))
- return QualType();
- return Common;
- }
- }
- }
- }
-
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();
@@ -2055,8 +1942,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*InOverloadResolution=*/false);
ImplicitConversionSequence E1ToC2, E2ToC2;
- E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
- E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
+ E1ToC2.setBad();
+ E2ToC2.setBad();
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2,
@@ -2071,14 +1958,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
/*InOverloadResolution=*/false);
}
- bool ToC1Viable = E1ToC1.ConversionKind !=
- ImplicitConversionSequence::BadConversion
- && E2ToC1.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
- bool ToC2Viable = E1ToC2.ConversionKind !=
- ImplicitConversionSequence::BadConversion
- && E2ToC2.ConversionKind !=
- ImplicitConversionSequence::BadConversion;
+ bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad();
+ bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad();
if (ToC1Viable && !ToC2Viable) {
if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) &&
!PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting))
@@ -2305,71 +2186,3 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
return Owned(FullExpr);
}
-
-/// \brief Determine whether a reference to the given declaration in the
-/// current context is an implicit member access
-/// (C++ [class.mfct.non-static]p2).
-///
-/// FIXME: Should Objective-C also use this approach?
-///
-/// \param D the declaration being referenced from the current scope.
-///
-/// \param NameLoc the location of the name in the source.
-///
-/// \param ThisType if the reference to this declaration is an implicit member
-/// access, will be set to the type of the "this" pointer to be used when
-/// building that implicit member access.
-///
-/// \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 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())
- return false;
-
- // C++ [class.mfct.nonstatic]p2:
- // [...] if name lookup (3.4.1) resolves the name in the
- // id-expression to a nonstatic nontype member of class X or of
- // a base class of X, the id-expression is transformed into a
- // 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 (R.isUnresolvableResult()) {
- // FIXME: this is just picking one at random
- Ctx = R.getRepresentativeDecl()->getDeclContext();
- } else if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) {
- Ctx = FD->getDeclContext();
- } else {
- 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>(*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();
- break;
- }
- }
- }
-
- if (!Ctx || !Ctx->isRecord())
- return false;
-
- // 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);
-
- // FIXME: this doesn't really work for overloaded lookups.
-
- QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx));
- QualType ClassType
- = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent()));
- return Context.hasSameType(CtxType, ClassType) ||
- IsDerivedFrom(ClassType, CtxType);
-}
-
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2e31e4764536..85889fa5d6d9 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -287,7 +287,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
SourceLocation &receiverNameLoc,
SourceLocation &propertyNameLoc) {
- ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName);
+ IdentifierInfo *receiverNamePtr = &receiverName;
+ ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
// Search for a declared property first.
@@ -400,7 +401,7 @@ Sema::ExprResult Sema::ActOnClassMessage(
return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
}
} else
- ClassDecl = getObjCInterfaceDecl(receiverName);
+ ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
// The following code allows for the following GCC-ism:
//
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3ef51561ffe2..1970f56e284b 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -88,7 +88,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType,
S.Diag(Init->getSourceRange().getBegin(),
diag::err_typecheck_convert_ambiguous)
<< DeclType << Init->getType() << Init->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1);
return true;
}
return false;
@@ -670,7 +670,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) {
+ if (!ICS.isBad()) {
if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS,
Sema::AA_Initializing))
hadError = true;
@@ -1136,7 +1136,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
// Expand the current designator into the set of replacement
// designators, so we have a full subobject path down to where the
// member of the anonymous struct/union is actually stored.
- DIE->ExpandDesignator(DesigIdx, &Replacements[0],
+ DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0],
&Replacements[0] + Replacements.size());
// Update FieldIter/FieldIndex;
@@ -1302,6 +1302,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
<< FieldName << CurrentObjectType << R.getLookupName()
<< CodeModificationHint::CreateReplacement(D->getFieldLoc(),
R.getLookupName().getAsString());
+ SemaRef.Diag(ReplacementField->getLocation(),
+ diag::note_previous_decl)
+ << ReplacementField->getDeclName();
} else {
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
<< FieldName << CurrentObjectType;
@@ -2224,9 +2227,11 @@ static void TryReferenceInitialization(Sema &S,
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
- QualType T1 = cv1T1.getUnqualifiedType();
+ Qualifiers T1Quals;
+ QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = Initializer->getType();
- QualType T2 = cv2T2.getUnqualifiedType();
+ Qualifiers T2Quals;
+ QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
SourceLocation DeclLoc = Initializer->getLocStart();
// If the initializer is the address of an overloaded function, try
@@ -2276,9 +2281,9 @@ static void TryReferenceInitialization(Sema &S,
// can occur. This property will be checked by PerformInitialization.
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
- S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/true);
- if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true);
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false);
return;
@@ -2297,6 +2302,11 @@ static void TryReferenceInitialization(Sema &S,
Sequence);
if (ConvOvlResult == OR_Success)
return;
+ if (ConvOvlResult != OR_No_Viable_Function) {
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ }
}
}
@@ -2304,7 +2314,7 @@ static void TryReferenceInitialization(Sema &S,
// non-volatile const type (i.e., cv1 shall be const), or the reference
// shall be an rvalue reference and the initializer expression shall
// be an rvalue.
- if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) ||
+ if (!((isLValueRef && T1Quals.hasConst()) ||
(isRValueRef && InitLvalue != Expr::LV_Valid))) {
if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
Sequence.SetOverloadFailure(
@@ -2331,9 +2341,9 @@ static void TryReferenceInitialization(Sema &S,
RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
if (DerivedToBase)
Sequence.AddDerivedToBaseCastStep(
- S.Context.getQualifiedType(T1, cv2T2.getQualifiers()),
+ S.Context.getQualifiedType(T1, T2Quals),
/*isLValue=*/false);
- if (cv1T1.getQualifiers() != cv2T2.getQualifiers())
+ if (T1Quals != T2Quals)
Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false);
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
return;
@@ -2381,7 +2391,7 @@ static void TryReferenceInitialization(Sema &S,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
// FIXME: Use the conversion function set stored in ICS to turn
// this into an overloading ambiguity diagnostic. However, we need
// to keep that set as an OverloadCandidateSet rather than as some
@@ -2398,8 +2408,10 @@ static void TryReferenceInitialization(Sema &S,
// [...] If T1 is reference-related to T2, cv1 must be the
// same cv-qualification as, or greater cv-qualification
// than, cv2; otherwise, the program is ill-formed.
+ unsigned T1CVRQuals = T1Quals.getCVRQualifiers();
+ unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
if (RefRelationship == Sema::Ref_Related &&
- !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) {
+ (T1CVRQuals | T2CVRQuals) != T1CVRQuals) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -2682,14 +2694,14 @@ static void TryUserDefinedConversion(Sema &S,
// Perform overload resolution. If it fails, return the failed result.
OverloadCandidateSet::iterator Best;
- if (OverloadingResult Result
+ if (OverloadingResult Result
= S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
Sequence.SetOverloadFailure(
InitializationSequence::FK_UserConversionOverloadFailed,
Result);
return;
}
-
+
FunctionDecl *Function = Best->Function;
if (isa<CXXConstructorDecl>(Function)) {
@@ -2708,7 +2720,7 @@ static void TryUserDefinedConversion(Sema &S,
if (Best->FinalConversion.First || Best->FinalConversion.Second ||
Best->FinalConversion.Third) {
ImplicitConversionSequence ICS;
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.setStandard();
ICS.Standard = Best->FinalConversion;
Sequence.AddConversionSequenceStep(ICS, DestType);
}
@@ -2729,7 +2741,7 @@ static void TryImplicitConversion(Sema &S,
/*FIXME:InOverloadResolution=*/false,
/*UserCast=*/Kind.isExplicitCast());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ICS.isBad()) {
Sequence.SetFailed(InitializationSequence::FK_ConversionFailed);
return;
}
@@ -3007,14 +3019,16 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
S.Diag(Loc, diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, false);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates,
+ &CurInitExpr, 1);
return S.ExprError();
case OR_Ambiguous:
S.Diag(Loc, diag::err_temp_copy_ambiguous)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
- S.PrintOverloadCandidates(CandidateSet, true);
+ S.PrintOverloadCandidates(CandidateSet, Sema::OCD_ViableCandidates,
+ &CurInitExpr, 1);
return S.ExprError();
case OR_Deleted:
@@ -3429,14 +3443,16 @@ bool InitializationSequence::Diagnose(Sema &S,
<< DestType << Args[0]->getType()
<< Args[0]->getSourceRange();
- S.PrintOverloadCandidates(FailedCandidateSet, true);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_ViableCandidates,
+ Args, NumArgs);
break;
case OR_No_Viable_Function:
S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition)
<< Args[0]->getType() << DestType.getNonReferenceType()
<< Args[0]->getSourceRange();
- S.PrintOverloadCandidates(FailedCandidateSet, false);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
+ Args, NumArgs);
break;
case OR_Deleted: {
@@ -3538,13 +3554,15 @@ bool InitializationSequence::Diagnose(Sema &S,
case OR_Ambiguous:
S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange;
- S.PrintOverloadCandidates(FailedCandidateSet, true);
+ S.PrintOverloadCandidates(FailedCandidateSet,
+ Sema::OCD_ViableCandidates, Args, NumArgs);
break;
case OR_No_Viable_Function:
S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
- S.PrintOverloadCandidates(FailedCandidateSet, false);
+ S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates,
+ Args, NumArgs);
break;
case OR_Deleted: {
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1419ceb4b660..cda245deba13 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -444,10 +444,83 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
bool Found = false;
DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I)
- if (R.isAcceptableDecl(*I))
- R.addDecl(*I), Found = true;
+ for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
+ if (R.isAcceptableDecl(*I)) {
+ R.addDecl(*I);
+ Found = true;
+ }
+ }
+ if (R.getLookupName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName &&
+ !R.getLookupName().getCXXNameType()->isDependentType() &&
+ isa<CXXRecordDecl>(DC)) {
+ // C++ [temp.mem]p6:
+ // A specialization of a conversion function template is not found by
+ // name lookup. Instead, any conversion function templates visible in the
+ // context of the use are considered. [...]
+ const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ if (!Record->isDefinition())
+ return Found;
+
+ const UnresolvedSet *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSet::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end();
+ U != UEnd; ++U) {
+ FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
+ if (!ConvTemplate)
+ continue;
+
+ // When we're performing lookup for the purposes of redeclaration, just
+ // add the conversion function template. When we deduce template
+ // arguments for specializations, we'll end up unifying the return
+ // type of the new declaration with the type of the function template.
+ if (R.isForRedeclaration()) {
+ R.addDecl(ConvTemplate);
+ Found = true;
+ continue;
+ }
+
+ // C++ [temp.mem]p6:
+ // [...] For each such operator, if argument deduction succeeds
+ // (14.9.2.3), the resulting specialization is used as if found by
+ // name lookup.
+ //
+ // When referencing a conversion function for any purpose other than
+ // a redeclaration (such that we'll be building an expression with the
+ // result), perform template argument deduction and place the
+ // specialization into the result set. We do this to avoid forcing all
+ // callers to perform special deduction for conversion functions.
+ Sema::TemplateDeductionInfo Info(R.getSema().Context);
+ FunctionDecl *Specialization = 0;
+
+ const FunctionProtoType *ConvProto
+ = ConvTemplate->getTemplatedDecl()->getType()
+ ->getAs<FunctionProtoType>();
+ assert(ConvProto && "Nonsensical conversion function template type");
+
+ // Compute the type of the function that we would expect the conversion
+ // function to have, if it were to match the name given.
+ // FIXME: Calling convention!
+ QualType ExpectedType
+ = R.getSema().Context.getFunctionType(
+ R.getLookupName().getCXXNameType(),
+ 0, 0, ConvProto->isVariadic(),
+ ConvProto->getTypeQuals(),
+ false, false, 0, 0,
+ ConvProto->getNoReturnAttr());
+
+ // Perform template argument deduction against the type that we would
+ // expect the function to have.
+ if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+ Specialization, Info)
+ == Sema::TDK_Success) {
+ R.addDecl(Specialization);
+ Found = true;
+ }
+ }
+ }
+
return Found;
}
@@ -550,7 +623,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// example, inside a class without any base classes, we never need to
// perform qualified lookup because all of the members are on top of the
// identifier chain.
- if (LookupQualifiedName(R, Ctx))
+ if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true))
return true;
}
}
@@ -577,7 +650,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
for (; S; S = S->getParent()) {
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- if (Ctx->isTransparentContext())
+ if (!Ctx || Ctx->isTransparentContext())
continue;
assert(Ctx && Ctx->isFileContext() &&
@@ -854,11 +927,11 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
return Found;
}
-/// @brief Perform qualified name lookup into a given context.
+/// \brief Perform qualified name lookup into a given context.
///
/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
/// names when the context of those names is explicit specified, e.g.,
-/// "std::vector" or "x->member".
+/// "std::vector" or "x->member", or as part of unqualified name lookup.
///
/// Different lookup criteria can find different names. For example, a
/// particular scope can have both a struct and a function of the same
@@ -866,25 +939,18 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R,
/// information about lookup criteria, see the documentation for the
/// class LookupCriteria.
///
-/// @param LookupCtx The context in which qualified name lookup will
+/// \param R captures both the lookup criteria and any lookup results found.
+///
+/// \param LookupCtx The context in which qualified name lookup will
/// search. If the lookup criteria permits, name lookup may also search
/// in the parent contexts or (for C++ classes) base classes.
///
-/// @param Name The name of the entity that we are searching for.
+/// \param InUnqualifiedLookup true if this is qualified name lookup that
+/// occurs as part of unqualified name lookup.
///
-/// @param Criteria The criteria that this routine will use to
-/// determine which names are visible and which names will be
-/// found. Note that name lookup will find a name that is visible by
-/// the given criteria, but the entity itself may not be semantically
-/// correct or even the kind of entity expected based on the
-/// lookup. For example, searching for a nested-name-specifier name
-/// might result in an EnumDecl, which is visible but is not permitted
-/// as a nested-name-specifier in C++03.
-///
-/// @returns The result of name lookup, which includes zero or more
-/// declarations and possibly additional information used to diagnose
-/// ambiguities.
-bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
+/// \returns true if lookup succeeded, false if it failed.
+bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
+ bool InUnqualifiedLookup) {
assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
if (!R.getLookupName())
@@ -922,11 +988,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) {
// If this isn't a C++ class, we aren't allowed to look into base
// classes, we're done.
- if (!isa<CXXRecordDecl>(LookupCtx))
+ CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
+ if (!LookupRec)
return false;
+ // If we're performing qualified name lookup into a dependent class,
+ // then we are actually looking into a current instantiation. If we have any
+ // dependent base classes, then we either have to delay lookup until
+ // template instantiation time (at which point all bases will be available)
+ // or we have to fail.
+ if (!InUnqualifiedLookup && LookupRec->isDependentContext() &&
+ LookupRec->hasAnyDependentBases()) {
+ R.setNotFoundInCurrentInstantiation();
+ return false;
+ }
+
// Perform lookup into our base classes.
- CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx);
CXXBasePaths Paths;
Paths.setOrigin(LookupRec);
@@ -1843,6 +1920,9 @@ VisibleDeclsRecord::ShadowMapEntry::end() {
}
NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
+ // Look through using declarations.
+ ND = ND->getUnderlyingDecl();
+
unsigned IDNS = ND->getIdentifierNamespace();
std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin();
for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend();
@@ -1866,6 +1946,14 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
(*I)->getIdentifierNamespace() != IDNS)
continue;
+ // Functions and function templates in the same scope overload
+ // rather than hide. FIXME: Look for hiding based on function
+ // signatures!
+ if ((*I)->isFunctionOrFunctionTemplate() &&
+ ND->isFunctionOrFunctionTemplate() &&
+ SM == ShadowMaps.rbegin())
+ continue;
+
// We've found a declaration that hides this one.
return *I;
}
@@ -1876,6 +1964,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
bool QualifiedNameLookup,
+ bool InBaseClass,
VisibleDeclConsumer &Consumer,
VisibleDeclsRecord &Visited) {
// Make sure we don't visit the same context twice.
@@ -1890,14 +1979,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
D != DEnd; ++D) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
if (Result.isAcceptableDecl(ND)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND));
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass);
Visited.add(ND);
}
// Visit transparent contexts inside this context.
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) {
if (InnerCtx->isTransparentContext())
- LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup,
+ LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass,
Consumer, Visited);
}
}
@@ -1909,11 +1998,11 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
DeclContext::udir_iterator I, E;
for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) {
LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
- QualifiedNameLookup, Consumer, Visited);
+ QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
}
- // Traverse the contexts of inherited classes.
+ // Traverse the contexts of inherited C++ classes.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
BEnd = Record->bases_end();
@@ -1951,11 +2040,49 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Find results in this base class (and its bases).
ShadowContextRAII Shadow(Visited);
LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup,
- Consumer, Visited);
+ true, Consumer, Visited);
}
}
- // FIXME: Look into base classes in Objective-C!
+ // Traverse the contexts of Objective-C classes.
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
+ // Traverse categories.
+ for (ObjCCategoryDecl *Category = IFace->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ Consumer, Visited);
+ }
+
+ // Traverse protocols.
+ for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
+ E = IFace->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+
+ // Traverse the superclass.
+ if (IFace->getSuperClass()) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
+ true, Consumer, Visited);
+ }
+ } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
+ for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
+ E = Protocol->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+ } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
+ for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(),
+ E = Category->protocol_end(); I != E; ++I) {
+ ShadowContextRAII Shadow(Visited);
+ LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ Visited);
+ }
+ }
}
static void LookupVisibleDecls(Scope *S, LookupResult &Result,
@@ -1965,9 +2092,21 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
if (!S)
return;
+ if (!S->getEntity() || !S->getParent() ||
+ ((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ // Walk through the declarations in this Scope.
+ for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ D != DEnd; ++D) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
+ if (Result.isAcceptableDecl(ND)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), false);
+ Visited.add(ND);
+ }
+ }
+ }
+
DeclContext *Entity = 0;
- if (S->getEntity() &&
- !((DeclContext *)S->getEntity())->isFunctionOrMethod()) {
+ if (S->getEntity()) {
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
// where we hit the context stored in the next outer scope.
@@ -1976,11 +2115,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
+ if (Method->isInstanceMethod()) {
+ // For instance methods, look for ivars in the method's interface.
+ LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
+ Result.getNameLoc(), Sema::LookupMemberName);
+ ObjCInterfaceDecl *IFace = Method->getClassInterface();
+ LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
+ }
+
+ // We've already performed all of the name lookup that we need
+ // to for Objective-C methods; the next context will be the
+ // outer scope.
+ break;
+ }
+
if (Ctx->isFunctionOrMethod())
continue;
LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
- Consumer, Visited);
+ /*InBaseClass=*/false, Consumer, Visited);
}
} else if (!S->getParent()) {
// Look into the translation unit scope. We walk through the translation
@@ -1991,22 +2146,11 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// doing so would force the normal C++ name-lookup code to look into the
// translation unit decl when the IdentifierInfo chains would suffice.
// Once we fix that problem (which is part of a more general "don't look
- // in DeclContexts unless we have to" optimization), we can eliminate the
- // TranslationUnit parameter entirely.
+ // in DeclContexts unless we have to" optimization), we can eliminate this.
Entity = Result.getSema().Context.getTranslationUnitDecl();
LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
- Consumer, Visited);
- } else {
- // Walk through the declarations in this Scope.
- for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get())))
- if (Result.isAcceptableDecl(ND)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND));
- Visited.add(ND);
- }
- }
- }
+ /*InBaseClass=*/false, Consumer, Visited);
+ }
if (Entity) {
// Lookup visible declarations in any namespaces found by using
@@ -2015,8 +2159,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
for (; UI != UEnd; ++UI)
LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()),
- Result, /*QualifiedNameLookup=*/false, Consumer,
- Visited);
+ Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false, Consumer, Visited);
}
// Lookup names in the parent scope.
@@ -2051,8 +2195,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
VisibleDeclsRecord Visited;
ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer,
- Visited);
+ ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
+ /*InBaseClass=*/false, Consumer, Visited);
}
//----------------------------------------------------------------------------
@@ -2075,7 +2219,7 @@ public:
explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
: Typo(Typo->getName()) { }
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding);
+ virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator;
iterator begin() const { return BestResults.begin(); }
@@ -2087,7 +2231,8 @@ public:
}
-void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) {
+void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
+ bool InBaseClass) {
// Don't consider hidden names for typo correction.
if (Hiding)
return;
@@ -2140,11 +2285,19 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) {
/// \param EnteringContext whether we're entering the context described by
/// the nested-name-specifier SS.
///
+/// \param OPT when non-NULL, the search for visible declarations will
+/// also walk the protocols in the qualified interfaces of \p OPT.
+///
/// \returns true if the typo was corrected, in which case the \p Res
/// structure will contain the results of name lookup for the
/// corrected name. Otherwise, returns false.
bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
- DeclContext *MemberContext, bool EnteringContext) {
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) {
+
+ if (Diags.hasFatalErrorOccurred())
+ return false;
+
// We only attempt to correct typos for identifiers.
IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
if (!Typo)
@@ -2161,9 +2314,17 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
return false;
TypoCorrectionConsumer Consumer(Typo);
- if (MemberContext)
+ if (MemberContext) {
LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
- else if (SS && SS->isSet()) {
+
+ // Look in qualified interfaces.
+ if (OPT) {
+ for (ObjCObjectPointerType::qual_iterator
+ I = OPT->qual_begin(), E = OPT->qual_end();
+ I != E; ++I)
+ LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
+ }
+ } else if (SS && SS->isSet()) {
DeclContext *DC = computeDeclContext(*SS, EnteringContext);
if (!DC)
return false;
@@ -2180,10 +2341,22 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// have overloads of that name, though).
TypoCorrectionConsumer::iterator I = Consumer.begin();
DeclarationName BestName = (*I)->getDeclName();
+
+ // If we've found an Objective-C ivar or property, don't perform
+ // name lookup again; we'll just return the result directly.
+ NamedDecl *FoundBest = 0;
+ if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I))
+ FoundBest = *I;
++I;
for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) {
if (BestName != (*I)->getDeclName())
return false;
+
+ // FIXME: If there are both ivars and properties of the same name,
+ // don't return both because the callee can't handle two
+ // results. We really need to separate ivar lookup from property
+ // lookup to avoid this problem.
+ FoundBest = 0;
}
// BestName is the closest viable name to what the user
@@ -2198,8 +2371,16 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS,
// success if we found something that was not ambiguous.
Res.clear();
Res.setLookupName(BestName);
- if (MemberContext)
+
+ // If we found an ivar or property, add that result; no further
+ // lookup is required.
+ if (FoundBest)
+ Res.addDecl(FoundBest);
+ // If we're looking into the context of a member, perform qualified
+ // name lookup on the best name.
+ else if (MemberContext)
LookupQualifiedName(Res, MemberContext);
+ // Perform lookup as if we had just parsed the best name.
else
LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false,
EnteringContext);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 589208173669..6ec4d1b60018 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -145,15 +145,12 @@ ImplicitConversionRank StandardConversionSequence::getRank() const {
/// used as part of the ranking of standard conversion sequences
/// (C++ 13.3.3.2p4).
bool StandardConversionSequence::isPointerConversionToBool() const {
- QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
- QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
-
// Note that FromType has not necessarily been transformed by the
// array-to-pointer or function-to-pointer implicit conversions, so
// check for their presence as well as checking whether FromType is
// a pointer.
- if (ToType->isBooleanType() &&
- (FromType->isPointerType() || FromType->isBlockPointerType() ||
+ if (getToType()->isBooleanType() &&
+ (getFromType()->isPointerType() || getFromType()->isBlockPointerType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
@@ -167,8 +164,8 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
bool
StandardConversionSequence::
isPointerConversionToVoidPointer(ASTContext& Context) const {
- QualType FromType = QualType::getFromOpaquePtr(FromTypePtr);
- QualType ToType = QualType::getFromOpaquePtr(ToTypePtr);
+ QualType FromType = getFromType();
+ QualType ToType = getToType();
// Note that FromType has not necessarily been transformed by the
// array-to-pointer implicit conversion, so check for its presence
@@ -250,6 +247,9 @@ void ImplicitConversionSequence::DebugPrint() const {
case EllipsisConversion:
fprintf(stderr, "Ellipsis conversion");
break;
+ case AmbiguousConversion:
+ fprintf(stderr, "Ambiguous conversion");
+ break;
case BadConversion:
fprintf(stderr, "Bad conversion");
break;
@@ -258,6 +258,22 @@ void ImplicitConversionSequence::DebugPrint() const {
fprintf(stderr, "\n");
}
+void AmbiguousConversionSequence::construct() {
+ new (&conversions()) ConversionSet();
+}
+
+void AmbiguousConversionSequence::destruct() {
+ conversions().~ConversionSet();
+}
+
+void
+AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
+ FromTypePtr = O.FromTypePtr;
+ ToTypePtr = O.ToTypePtr;
+ new (&conversions()) ConversionSet(O.conversions());
+}
+
+
// IsOverload - Determine whether the given New declaration is an
// overload of the declarations in Old. This routine returns false if
// New and Old cannot be overloaded, e.g., if New has the same
@@ -432,14 +448,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
OverloadCandidateSet Conversions;
OverloadingResult UserDefResult = OR_Success;
if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard))
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.setStandard();
else if (getLangOptions().CPlusPlus &&
(UserDefResult = IsUserDefinedConversion(From, ToType,
ICS.UserDefined,
Conversions,
!SuppressUserConversions, AllowExplicit,
ForceRValue, UserCast)) == OR_Success) {
- ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
+ ICS.setUserDefined();
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
// type is given Exact Match rank, and a conversion of an
@@ -456,10 +472,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
(FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) {
// Turn this into a "standard" conversion sequence, so that it
// gets ranked with standard conversion sequences.
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
- ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
- ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
+ ICS.Standard.setFromType(From->getType());
+ ICS.Standard.setToType(ToType);
ICS.Standard.CopyConstructor = Constructor;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
@@ -473,17 +489,21 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
// 13.3.1.6 in all cases, only standard conversion sequences and
// ellipsis conversion sequences are allowed.
- if (SuppressUserConversions &&
- ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion)
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- } else {
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
- if (UserDefResult == OR_Ambiguous) {
- for (OverloadCandidateSet::iterator Cand = Conversions.begin();
- Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
- ICS.ConversionFunctionSet.push_back(Cand->Function);
+ if (SuppressUserConversions && ICS.isUserDefined()) {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType);
}
+ } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
+ ICS.setAmbiguous();
+ ICS.Ambiguous.setFromType(From->getType());
+ ICS.Ambiguous.setToType(ToType);
+ for (OverloadCandidateSet::iterator Cand = Conversions.begin();
+ Cand != Conversions.end(); ++Cand)
+ if (Cand->Viable)
+ ICS.Ambiguous.addConversion(Cand->Function);
+ } else {
+ ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
}
return ICS;
@@ -524,7 +544,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
SCS.setAsIdentityConversion();
SCS.Deprecated = false;
SCS.IncompatibleObjC = false;
- SCS.FromTypePtr = FromType.getAsOpaquePtr();
+ SCS.setFromType(FromType);
SCS.CopyConstructor = 0;
// There are no standard conversions for class types in C++, so
@@ -573,7 +593,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// conversion (4.4). (C++ 4.2p2)
SCS.Second = ICK_Identity;
SCS.Third = ICK_Qualification;
- SCS.ToTypePtr = ToType.getAsOpaquePtr();
+ SCS.setToType(ToType);
return true;
}
} else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) {
@@ -639,7 +659,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
} else if ((FromType->isIntegralType() || FromType->isEnumeralType()) &&
(ToType->isIntegralType() && !ToType->isEnumeralType())) {
// Integral conversions (C++ 4.7).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Integral_Conversion;
FromType = ToType.getUnqualifiedType();
} else if (FromType->isFloatingType() && ToType->isFloatingType()) {
@@ -656,7 +675,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
((FromType->isIntegralType() || FromType->isEnumeralType()) &&
ToType->isFloatingType())) {
// Floating-integral conversions (C++ 4.9).
- // FIXME: isIntegralType shouldn't be true for enums in C++.
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
} else if ((FromType->isComplexType() && ToType->isArithmeticType()) ||
@@ -726,7 +744,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
if (CanonFrom != CanonTo)
return false;
- SCS.ToTypePtr = FromType.getAsOpaquePtr();
+ SCS.setToType(FromType);
return true;
}
@@ -1546,8 +1564,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
// the argument of the constructor.
//
QualType ThisType = Constructor->getThisType(Context);
- if (Best->Conversions[0].ConversionKind ==
- ImplicitConversionSequence::EllipsisConversion)
+ if (Best->Conversions[0].isEllipsis())
User.EllipsisConversion = true;
else {
User.Before = Best->Conversions[0].Standard;
@@ -1555,9 +1572,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
}
User.ConversionFunction = Constructor;
User.After.setAsIdentityConversion();
- User.After.FromTypePtr
- = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr();
- User.After.ToTypePtr = ToType.getAsOpaquePtr();
+ User.After.setFromType(
+ ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setToType(ToType);
return OR_Success;
} else if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
@@ -1617,7 +1634,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
<< From->getType() << ToType << From->getSourceRange();
else
return false;
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &From, 1);
return true;
}
@@ -1637,18 +1654,28 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,
// conversion sequence than an ellipsis conversion sequence
// (13.3.3.1.3).
//
- if (ICS1.ConversionKind < ICS2.ConversionKind)
- return ImplicitConversionSequence::Better;
- else if (ICS2.ConversionKind < ICS1.ConversionKind)
- return ImplicitConversionSequence::Worse;
+ // C++0x [over.best.ics]p10:
+ // For the purpose of ranking implicit conversion sequences as
+ // described in 13.3.3.2, the ambiguous conversion sequence is
+ // treated as a user-defined sequence that is indistinguishable
+ // from any other user-defined conversion sequence.
+ if (ICS1.getKind() < ICS2.getKind()) {
+ if (!(ICS1.isUserDefined() && ICS2.isAmbiguous()))
+ return ImplicitConversionSequence::Better;
+ } else if (ICS2.getKind() < ICS1.getKind()) {
+ if (!(ICS2.isUserDefined() && ICS1.isAmbiguous()))
+ return ImplicitConversionSequence::Worse;
+ }
+
+ if (ICS1.isAmbiguous() || ICS2.isAmbiguous())
+ return ImplicitConversionSequence::Indistinguishable;
// Two implicit conversion sequences of the same form are
// indistinguishable conversion sequences unless one of the
// following rules apply: (C++ 13.3.3.2p3):
- if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion)
+ if (ICS1.isStandard())
return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard);
- else if (ICS1.ConversionKind ==
- ImplicitConversionSequence::UserDefinedConversion) {
+ else if (ICS1.isUserDefined()) {
// User-defined conversion sequence U1 is a better conversion
// sequence than another user-defined conversion sequence U2 if
// they contain the same user-defined conversion function or
@@ -1741,8 +1768,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// Both conversion sequences are conversions to void
// pointers. Compare the source types to determine if there's an
// inheritance relationship in their sources.
- QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
- QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
+ QualType FromType1 = SCS1.getFromType();
+ QualType FromType2 = SCS2.getFromType();
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -1798,8 +1825,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
// top-level cv-qualifiers, and the type to which the reference
// initialized by S2 refers is more cv-qualified than the type
// to which the reference initialized by S1 refers.
- QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType T1 = SCS1.getToType();
+ QualType T2 = SCS2.getToType();
T1 = Context.getCanonicalType(T1);
T2 = Context.getCanonicalType(T2);
Qualifiers T1Quals, T2Quals;
@@ -1929,10 +1956,10 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
ImplicitConversionSequence::CompareKind
Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2) {
- QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr);
- QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr);
- QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr);
- QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
+ QualType FromType1 = SCS1.getFromType();
+ QualType ToType1 = SCS1.getToType();
+ QualType FromType2 = SCS2.getFromType();
+ QualType ToType2 = SCS2.getToType();
// Adjust the types we're converting from via the array-to-pointer
// conversion, if we need to.
@@ -2105,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
CheckReferenceInit(From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
@@ -2163,7 +2191,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
ImplicitConversionSequence
-Sema::TryObjectArgumentInitialization(QualType FromType,
+Sema::TryObjectArgumentInitialization(QualType OrigFromType,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
QualType ClassType = Context.getTypeDeclType(ActingContext);
@@ -2177,9 +2205,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
// to exit early.
ImplicitConversionSequence ICS;
ICS.Standard.setAsIdentityConversion();
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ ICS.setBad();
// We need to have an object of class type.
+ QualType FromType = OrigFromType;
if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
@@ -2199,8 +2228,11 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
QualType FromTypeCanon = Context.getCanonicalType(FromType);
if (ImplicitParamType.getCVRQualifiers()
!= FromTypeCanon.getLocalCVRQualifiers() &&
- !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon))
+ !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
+ ICS.Bad.init(BadConversionSequence::bad_qualifiers,
+ OrigFromType, ImplicitParamType);
return ICS;
+ }
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
@@ -2209,13 +2241,15 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
ICS.Standard.Second = ICK_Identity;
else if (IsDerivedFrom(FromType, ClassType))
ICS.Standard.Second = ICK_Derived_To_Base;
- else
+ else {
+ ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType);
return ICS;
+ }
// Success. Mark this as a reference binding.
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
- ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr();
- ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr();
+ ICS.setStandard();
+ ICS.Standard.setFromType(FromType);
+ ICS.Standard.setToType(ImplicitParamType);
ICS.Standard.ReferenceBinding = true;
ICS.Standard.DirectBinding = true;
ICS.Standard.RRefBinding = false;
@@ -2244,7 +2278,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
ImplicitConversionSequence ICS
= TryObjectArgumentInitialization(From->getType(), Method,
Method->getParent());
- if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion)
+ if (ICS.isBad())
return Diag(From->getSourceRange().getBegin(),
diag::err_implicit_object_parameter_init)
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
@@ -2276,8 +2310,8 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
/// of the expression From to bool (C++0x [conv]p3).
bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
- if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting))
- return false;
+ if (!ICS.isBad())
+ return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
return Diag(From->getSourceRange().getBegin(),
@@ -2307,8 +2341,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Function) &&
- "Use AddConversionCandidate for conversion functions");
assert(!Function->getDescribedFunctionTemplate() &&
"Use AddTemplateOverloadCandidate for function templates");
@@ -2363,6 +2395,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
!Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2375,6 +2408,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2392,35 +2426,16 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
= TryCopyInitialization(Args[ArgIdx], ParamType,
SuppressUserConversions, ForceRValue,
/*InOverloadResolution=*/true);
- if (Candidate.Conversions[ArgIdx].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
- // 13.3.3.1-p10 If several different sequences of conversions exist that
- // each convert the argument to the parameter type, the implicit conversion
- // sequence associated with the parameter is defined to be the unique conversion
- // sequence designated the ambiguous conversion sequence. For the purpose of
- // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous
- // conversion sequence is treated as a user-defined sequence that is
- // indistinguishable from any other user-defined conversion sequence
- if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) {
- Candidate.Conversions[ArgIdx].ConversionKind =
- ImplicitConversionSequence::UserDefinedConversion;
- // Set the conversion function to one of them. As due to ambiguity,
- // they carry the same weight and is needed for overload resolution
- // later.
- Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction =
- Candidate.Conversions[ArgIdx].ConversionFunctionSet[0];
- }
- else {
- Candidate.Viable = false;
- break;
- }
+ if (Candidate.Conversions[ArgIdx].isBad()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx].setEllipsis();
}
}
}
@@ -2470,8 +2485,6 @@ void Sema::AddMethodCandidate(NamedDecl *Decl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions, bool ForceRValue) {
-
- // FIXME: use this
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
if (isa<UsingShadowDecl>(Decl))
@@ -2509,8 +2522,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
const FunctionProtoType* Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
- assert(!isa<CXXConversionDecl>(Method) &&
- "Use AddConversionCandidate for conversion functions");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
@@ -2534,6 +2545,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2546,6 +2558,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
if (NumArgs < MinRequiredArgs) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2560,9 +2573,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
// parameter.
Candidate.Conversions[0]
= TryObjectArgumentInitialization(ObjectType, Method, ActingContext);
- if (Candidate.Conversions[0].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
}
@@ -2580,17 +2593,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
= TryCopyInitialization(Args[ArgIdx], ParamType,
SuppressUserConversions, ForceRValue,
/*InOverloadResolution=*/true);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
}
@@ -2675,6 +2687,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
return;
@@ -2714,9 +2727,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
- Candidate.FinalConversion.FromTypePtr
- = Conversion->getConversionType().getAsOpaquePtr();
- Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
+ Candidate.FinalConversion.setFromType(Conversion->getConversionType());
+ Candidate.FinalConversion.setToType(ToType);
// Determine the implicit conversion sequence for the implicit
// object parameter.
@@ -2730,9 +2742,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
// in overload resolution.
if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base)
Candidate.Conversions[0].Standard.Second = ICK_Identity;
- if (Candidate.Conversions[0].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@@ -2744,6 +2756,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@@ -2774,13 +2787,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- switch (ICS.ConversionKind) {
+ switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
Candidate.FinalConversion = ICS.Standard;
break;
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
default:
@@ -2852,16 +2866,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// object parameter.
ImplicitConversionSequence ObjectInit
= TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext);
- if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) {
+ if (ObjectInit.isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
// The first conversion is actually a user-defined conversion whose
// first conversion is ObjectInit's standard conversion (which is
// effectively a reference binding). Record it as such.
- Candidate.Conversions[0].ConversionKind
- = ImplicitConversionSequence::UserDefinedConversion;
+ Candidate.Conversions[0].setUserDefined();
Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard;
Candidate.Conversions[0].UserDefined.EllipsisConversion = false;
Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion;
@@ -2877,6 +2891,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@@ -2885,6 +2900,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (NumArgs < NumArgsInProto) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@@ -2902,17 +2918,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
/*SuppressUserConversions=*/false,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
- if (Candidate.Conversions[ArgIdx + 1].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].ConversionKind
- = ImplicitConversionSequence::EllipsisConversion;
+ Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
}
@@ -3046,9 +3061,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
/*ForceRValue=*/false,
/*InOverloadResolution=*/false);
}
- if (Candidate.Conversions[ArgIdx].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
+ if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
}
@@ -4274,130 +4289,386 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
return OR_Success;
}
+namespace {
+
+enum OverloadCandidateKind {
+ oc_function,
+ oc_method,
+ oc_constructor,
+ oc_function_template,
+ oc_method_template,
+ oc_constructor_template,
+ oc_implicit_default_constructor,
+ oc_implicit_copy_constructor,
+ oc_implicit_copy_assignment
+};
+
+OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
+ FunctionDecl *Fn,
+ std::string &Description) {
+ bool isTemplate = false;
+
+ if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) {
+ isTemplate = true;
+ Description = S.getTemplateArgumentBindingsText(
+ FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs());
+ }
+
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
+ if (!Ctor->isImplicit())
+ return isTemplate ? oc_constructor_template : oc_constructor;
+
+ return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
+ : oc_implicit_default_constructor;
+ }
+
+ if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) {
+ // This actually gets spelled 'candidate function' for now, but
+ // it doesn't hurt to split it out.
+ if (!Meth->isImplicit())
+ return isTemplate ? oc_method_template : oc_method;
+
+ assert(Meth->isCopyAssignment()
+ && "implicit method is not copy assignment operator?");
+ return oc_implicit_copy_assignment;
+ }
+
+ return isTemplate ? oc_function_template : oc_function;
+}
+
+} // end anonymous namespace
+
+// Notes the location of an overload candidate.
+void Sema::NoteOverloadCandidate(FunctionDecl *Fn) {
+ std::string FnDesc;
+ OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
+ Diag(Fn->getLocation(), diag::note_ovl_candidate)
+ << (unsigned) K << FnDesc;
+}
+
+/// Diagnoses an ambiguous conversion. The partial diagnostic is the
+/// "lead" diagnostic; it will be given two arguments, the source and
+/// target types of the conversion.
+void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS,
+ SourceLocation CaretLoc,
+ const PartialDiagnostic &PDiag) {
+ Diag(CaretLoc, PDiag)
+ << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType();
+ for (AmbiguousConversionSequence::const_iterator
+ I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) {
+ NoteOverloadCandidate(*I);
+ }
+}
+
+namespace {
+
+void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
+ const ImplicitConversionSequence &Conv = Cand->Conversions[I];
+ assert(Conv.isBad());
+ assert(Cand->Function && "for now, candidate must be a function");
+ FunctionDecl *Fn = Cand->Function;
+
+ // There's a conversion slot for the object argument if this is a
+ // non-constructor method. Note that 'I' corresponds the
+ // conversion-slot index.
+ bool isObjectArgument = false;
+ if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
+ if (I == 0)
+ isObjectArgument = true;
+ else
+ I--;
+ }
+
+ std::string FnDesc;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+
+ Expr *FromExpr = Conv.Bad.FromExpr;
+ QualType FromTy = Conv.Bad.getFromType();
+ QualType ToTy = Conv.Bad.getToType();
+
+ // Do some hand-waving analysis to see if the non-viability is due to a
+ CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
+ CanQualType CToTy = S.Context.getCanonicalType(ToTy);
+ if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
+ CToTy = RT->getPointeeType();
+ else {
+ // TODO: detect and diagnose the full richness of const mismatches.
+ if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>())
+ if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>())
+ CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType();
+ }
+
+ if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
+ !CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
+ // It is dumb that we have to do this here.
+ while (isa<ArrayType>(CFromTy))
+ CFromTy = CFromTy->getAs<ArrayType>()->getElementType();
+ while (isa<ArrayType>(CToTy))
+ CToTy = CFromTy->getAs<ArrayType>()->getElementType();
+
+ Qualifiers FromQs = CFromTy.getQualifiers();
+ Qualifiers ToQs = CToTy.getQualifiers();
+
+ if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace()
+ << (unsigned) isObjectArgument << I+1;
+ return;
+ }
+
+ unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
+ assert(CVR && "unexpected qualifiers mismatch");
+
+ if (isObjectArgument) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << (CVR - 1);
+ } else {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << (CVR - 1) << I+1;
+ }
+ return;
+ }
+
+ // TODO: specialize more based on the kind of mismatch
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+}
+
+void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
+ unsigned NumFormalArgs) {
+ // TODO: treat calls to a missing default constructor as a special case
+
+ FunctionDecl *Fn = Cand->Function;
+ const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
+
+ unsigned MinParams = Fn->getMinRequiredArguments();
+
+ // at least / at most / exactly
+ unsigned mode, modeCount;
+ if (NumFormalArgs < MinParams) {
+ assert(Cand->FailureKind == ovl_fail_too_few_arguments);
+ if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic())
+ mode = 0; // "at least"
+ else
+ mode = 2; // "exactly"
+ modeCount = MinParams;
+ } else {
+ assert(Cand->FailureKind == ovl_fail_too_many_arguments);
+ if (MinParams != FnTy->getNumArgs())
+ mode = 1; // "at most"
+ else
+ mode = 2; // "exactly"
+ modeCount = FnTy->getNumArgs();
+ }
+
+ std::string Description;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
+ << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
+}
+
+void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ FunctionDecl *Fn = Cand->Function;
+
+ // Note deleted candidates, but only if they're viable.
+ if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) {
+ std::string FnDesc;
+ OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
+ << FnKind << FnDesc << Fn->isDeleted();
+ return;
+ }
+
+ // We don't really have anything else to say about viable candidates.
+ if (Cand->Viable) {
+ S.NoteOverloadCandidate(Fn);
+ return;
+ }
+
+ switch (Cand->FailureKind) {
+ case ovl_fail_too_many_arguments:
+ case ovl_fail_too_few_arguments:
+ return DiagnoseArityMismatch(S, Cand, NumArgs);
+
+ case ovl_fail_bad_deduction:
+ return S.NoteOverloadCandidate(Fn);
+
+ case ovl_fail_bad_conversion:
+ for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I)
+ if (Cand->Conversions[I].isBad())
+ return DiagnoseBadConversion(S, Cand, I);
+
+ // FIXME: this currently happens when we're called from SemaInit
+ // when user-conversion overload fails. Figure out how to handle
+ // those conditions and diagnose them well.
+ return S.NoteOverloadCandidate(Fn);
+ }
+}
+
+void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
+ // Desugar the type of the surrogate down to a function type,
+ // retaining as many typedefs as possible while still showing
+ // the function type (and, therefore, its parameter types).
+ QualType FnType = Cand->Surrogate->getConversionType();
+ bool isLValueReference = false;
+ bool isRValueReference = false;
+ bool isPointer = false;
+ if (const LValueReferenceType *FnTypeRef =
+ FnType->getAs<LValueReferenceType>()) {
+ FnType = FnTypeRef->getPointeeType();
+ isLValueReference = true;
+ } else if (const RValueReferenceType *FnTypeRef =
+ FnType->getAs<RValueReferenceType>()) {
+ FnType = FnTypeRef->getPointeeType();
+ isRValueReference = true;
+ }
+ if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
+ FnType = FnTypePtr->getPointeeType();
+ isPointer = true;
+ }
+ // Desugar down to a function type.
+ FnType = QualType(FnType->getAs<FunctionType>(), 0);
+ // Reconstruct the pointer/reference as appropriate.
+ if (isPointer) FnType = S.Context.getPointerType(FnType);
+ if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType);
+ if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType);
+
+ S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
+ << FnType;
+}
+
+void NoteBuiltinOperatorCandidate(Sema &S,
+ const char *Opc,
+ SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
+ assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
+ std::string TypeStr("operator");
+ TypeStr += Opc;
+ TypeStr += "(";
+ TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
+ if (Cand->Conversions.size() == 1) {
+ TypeStr += ")";
+ S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
+ } else {
+ TypeStr += ", ";
+ TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
+ TypeStr += ")";
+ S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
+ }
+}
+
+void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
+ OverloadCandidate *Cand) {
+ unsigned NoOperands = Cand->Conversions.size();
+ for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
+ const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ if (ICS.isBad()) break; // all meaningless after first invalid
+ if (!ICS.isAmbiguous()) continue;
+
+ S.DiagnoseAmbiguousConversion(ICS, OpLoc,
+ PDiag(diag::note_ambiguous_type_conversion));
+ }
+}
+
+struct CompareOverloadCandidatesForDisplay {
+ Sema &S;
+ CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
+
+ bool operator()(const OverloadCandidate *L,
+ const OverloadCandidate *R) {
+ // Order first by viability.
+ if (L->Viable) {
+ if (!R->Viable) return true;
+
+ // TODO: introduce a tri-valued comparison for overload
+ // candidates. Would be more worthwhile if we had a sort
+ // that could exploit it.
+ if (S.isBetterOverloadCandidate(*L, *R)) return true;
+ if (S.isBetterOverloadCandidate(*R, *L)) return false;
+ } else if (R->Viable)
+ return false;
+
+ // Put declared functions first.
+ if (L->Function) {
+ if (!R->Function) return true;
+ return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(),
+ R->Function->getLocation());
+ } else if (R->Function) return false;
+
+ // Then surrogates.
+ if (L->IsSurrogate) {
+ if (!R->IsSurrogate) return true;
+ return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(),
+ R->Surrogate->getLocation());
+ } else if (R->IsSurrogate) return false;
+
+ // And builtins just come in a jumble.
+ return false;
+ }
+};
+
+} // end anonymous namespace
+
/// PrintOverloadCandidates - When overload resolution fails, prints
/// diagnostic messages containing the candidates in the candidate
-/// set. If OnlyViable is true, only viable candidates will be printed.
+/// set.
void
Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
- bool OnlyViable,
+ OverloadCandidateDisplayKind OCD,
+ Expr **Args, unsigned NumArgs,
const char *Opc,
SourceLocation OpLoc) {
- OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- LastCand = CandidateSet.end();
- bool Reported = false;
- for (; Cand != LastCand; ++Cand) {
- if (Cand->Viable || !OnlyViable) {
- if (Cand->Function) {
- if (Cand->Function->isDeleted() ||
- Cand->Function->getAttr<UnavailableAttr>()) {
- // Deleted or "unavailable" function.
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
- << Cand->Function->isDeleted();
- } else if (FunctionTemplateDecl *FunTmpl
- = Cand->Function->getPrimaryTemplate()) {
- // Function template specialization
- // FIXME: Give a better reason!
- Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate)
- << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(),
- *Cand->Function->getTemplateSpecializationArgs());
- } else {
- // Normal function
- bool errReported = false;
- if (!Cand->Viable && Cand->Conversions.size() > 0) {
- for (int i = Cand->Conversions.size()-1; i >= 0; i--) {
- const ImplicitConversionSequence &Conversion =
- Cand->Conversions[i];
- if ((Conversion.ConversionKind !=
- ImplicitConversionSequence::BadConversion) ||
- Conversion.ConversionFunctionSet.size() == 0)
- continue;
- Diag(Cand->Function->getLocation(),
- diag::err_ovl_candidate_not_viable) << (i+1);
- errReported = true;
- for (int j = Conversion.ConversionFunctionSet.size()-1;
- j >= 0; j--) {
- FunctionDecl *Func = Conversion.ConversionFunctionSet[j];
- Diag(Func->getLocation(), diag::err_ovl_candidate);
- }
- }
- }
- if (!errReported)
- Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
- }
- } else if (Cand->IsSurrogate) {
- // Desugar the type of the surrogate down to a function type,
- // retaining as many typedefs as possible while still showing
- // the function type (and, therefore, its parameter types).
- QualType FnType = Cand->Surrogate->getConversionType();
- bool isLValueReference = false;
- bool isRValueReference = false;
- bool isPointer = false;
- if (const LValueReferenceType *FnTypeRef =
- FnType->getAs<LValueReferenceType>()) {
- FnType = FnTypeRef->getPointeeType();
- isLValueReference = true;
- } else if (const RValueReferenceType *FnTypeRef =
- FnType->getAs<RValueReferenceType>()) {
- FnType = FnTypeRef->getPointeeType();
- isRValueReference = true;
- }
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) {
- FnType = FnTypePtr->getPointeeType();
- isPointer = true;
- }
- // Desugar down to a function type.
- FnType = QualType(FnType->getAs<FunctionType>(), 0);
- // Reconstruct the pointer/reference as appropriate.
- if (isPointer) FnType = Context.getPointerType(FnType);
- if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
- if (isLValueReference) FnType = Context.getLValueReferenceType(FnType);
-
- Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
- << FnType;
- } else if (OnlyViable) {
- assert(Cand->Conversions.size() <= 2 &&
- "builtin-binary-operator-not-binary");
- std::string TypeStr("operator");
- TypeStr += Opc;
- TypeStr += "(";
- TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->Conversions.size() == 1) {
- TypeStr += ")";
- Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr;
- }
- else {
- TypeStr += ", ";
- TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString();
- TypeStr += ")";
- Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr;
- }
- }
- else if (!Cand->Viable && !Reported) {
- // Non-viability might be due to ambiguous user-defined conversions,
- // needed for built-in operators. Report them as well, but only once
- // as we have typically many built-in candidates.
- unsigned NoOperands = Cand->Conversions.size();
- for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
- const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
- if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion ||
- ICS.ConversionFunctionSet.empty())
- continue;
- if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>(
- Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) {
- QualType FromTy =
- QualType(
- static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0);
- Diag(OpLoc,diag::note_ambiguous_type_conversion)
- << FromTy << Func->getConversionType();
- }
- for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) {
- FunctionDecl *Func =
- Cand->Conversions[ArgIdx].ConversionFunctionSet[j];
- Diag(Func->getLocation(),diag::err_ovl_candidate);
- }
- }
- Reported = true;
+ // Sort the candidates by viability and position. Sorting directly would
+ // be prohibitive, so we make a set of pointers and sort those.
+ llvm::SmallVector<OverloadCandidate*, 32> Cands;
+ if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size());
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ LastCand = CandidateSet.end();
+ Cand != LastCand; ++Cand)
+ if (Cand->Viable || OCD == OCD_AllCandidates)
+ Cands.push_back(Cand);
+ std::sort(Cands.begin(), Cands.end(),
+ CompareOverloadCandidatesForDisplay(*this));
+
+ bool ReportedAmbiguousConversions = false;
+
+ llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E;
+ for (I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ OverloadCandidate *Cand = *I;
+
+ if (Cand->Function)
+ NoteFunctionCandidate(*this, Cand, Args, NumArgs);
+ else if (Cand->IsSurrogate)
+ NoteSurrogateCandidate(*this, Cand);
+
+ // This a builtin candidate. We do not, in general, want to list
+ // every possible builtin candidate.
+ else if (Cand->Viable) {
+ // Generally we only see ambiguities including viable builtin
+ // operators if overload resolution got screwed up by an
+ // ambiguous user-defined conversion.
+ //
+ // FIXME: It's quite possible for different conversions to see
+ // different ambiguities, though.
+ if (!ReportedAmbiguousConversions) {
+ NoteAmbiguousUserConversions(*this, OpLoc, Cand);
+ ReportedAmbiguousConversions = true;
}
+
+ // If this is a viable builtin, print it.
+ NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand);
}
}
}
@@ -4586,7 +4857,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
PDiag(),
PDiag(diag::err_addr_ovl_ambiguous)
<< TemplateMatches[0]->getDeclName(),
- PDiag(diag::err_ovl_template_candidate));
+ PDiag(diag::note_ovl_candidate)
+ << (unsigned) oc_function_template);
MarkDeclarationReferenced(From->getLocStart(), Result);
return Result;
}
@@ -4611,7 +4883,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
<< RemainingMatches[0]->getDeclName();
for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I)
- Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate);
+ NoteOverloadCandidate(RemainingMatches[I]);
return 0;
}
@@ -4681,7 +4953,6 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
// resulting template argument list is used to generate a single
// function template specialization, which is added to the set of
// overloaded functions considered.
- // FIXME: We don't really want to build the specialization here, do we?
FunctionDecl *Specialization = 0;
TemplateDeductionInfo Info(Context);
if (TemplateDeductionResult Result
@@ -4906,13 +5177,13 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
break;
case OR_Deleted:
@@ -4920,7 +5191,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
<< Best->Function->isDeleted()
<< ULE->getName()
<< Fn->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -5075,7 +5346,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -5084,7 +5355,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
<< Best->Function->isDeleted()
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
return ExprError();
}
@@ -5291,7 +5562,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing candidates!");
if (Result.isInvalid())
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return move(Result);
}
@@ -5300,7 +5571,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2,
BinaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -5309,9 +5580,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2);
return ExprError();
- }
+ }
// We matched a built-in operator; build it.
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
@@ -5411,22 +5682,23 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
case OR_No_Viable_Function: {
- // No viable function; try to create a built-in operation, which will
- // produce an error. Then, show the non-viable candidates.
- OwningExprResult Result =
- CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc);
- assert(Result.isInvalid() &&
- "C++ subscript operator overloading is missing candidates!");
- if (Result.isInvalid())
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false,
- "[]", LLoc);
- return move(Result);
+ if (CandidateSet.empty())
+ Diag(LLoc, diag::err_ovl_no_oper)
+ << Args[0]->getType() << /*subscript*/ 0
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ else
+ Diag(LLoc, diag::err_ovl_no_viable_subscript)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
+ "[]", LLoc);
+ return ExprError();
}
case OR_Ambiguous:
Diag(LLoc, diag::err_ovl_ambiguous_oper)
<< "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true,
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2,
"[]", LLoc);
return ExprError();
@@ -5434,7 +5706,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Diag(LLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted() << "[]"
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2,
+ "[]", LLoc);
return ExprError();
}
@@ -5518,14 +5791,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -5533,7 +5806,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
<< Best->Function->isDeleted()
<< DeclName << MemExprE->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
// FIXME: Leaking incoming expressions!
return ExprError();
}
@@ -5636,9 +5909,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- // FIXME: Look in base classes for more conversion operators!
const UnresolvedSet *Conversions
- = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
+ = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
for (UnresolvedSet::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -5674,17 +5946,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
break;
case OR_No_Viable_Function:
- Diag(Object->getSourceRange().getBegin(),
- diag::err_ovl_no_viable_object_call)
- << Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ if (CandidateSet.empty())
+ Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper)
+ << Object->getType() << /*call*/ 1
+ << Object->getSourceRange();
+ else
+ Diag(Object->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_object_call)
+ << Object->getType() << Object->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
case OR_Ambiguous:
Diag(Object->getSourceRange().getBegin(),
diag::err_ovl_ambiguous_object_call)
<< Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs);
break;
case OR_Deleted:
@@ -5692,7 +5969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
diag::err_ovl_deleted_object_call)
<< Best->Function->isDeleted()
<< Object->getType() << Object->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs);
break;
}
@@ -5873,20 +6150,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
else
Diag(OpLoc, diag::err_ovl_no_viable_oper)
<< "operator->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1);
return ExprError();
case OR_Ambiguous:
Diag(OpLoc, diag::err_ovl_ambiguous_oper)
<< "->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Base, 1);
return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< "->" << Base->getSourceRange();
- PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+ PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1);
return ExprError();
}
@@ -6020,9 +6297,14 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemExpr->getMemberLoc(),
Fn->getType(),
TemplateArgs);
- } else
- Base = new (Context) CXXThisExpr(SourceLocation(),
- MemExpr->getBaseType());
+ } else {
+ SourceLocation Loc = MemExpr->getMemberLoc();
+ if (MemExpr->getQualifier())
+ Loc = MemExpr->getQualifierRange().getBegin();
+ Base = new (Context) CXXThisExpr(Loc,
+ MemExpr->getBaseType(),
+ /*isImplicit=*/true);
+ }
} else
Base = MemExpr->getBase()->Retain();
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 3613d608834a..20add007f7c0 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_OVERLOAD_H
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -149,6 +150,15 @@ namespace clang {
/// conversions.
CXXConstructorDecl *CopyConstructor;
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+
void setAsIdentityConversion();
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
@@ -190,6 +200,93 @@ namespace clang {
void DebugPrint() const;
};
+ /// Represents an ambiguous user-defined conversion sequence.
+ struct AmbiguousConversionSequence {
+ typedef llvm::SmallVector<FunctionDecl*, 4> ConversionSet;
+
+ void *FromTypePtr;
+ void *ToTypePtr;
+ char Buffer[sizeof(ConversionSet)];
+
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+
+ ConversionSet &conversions() {
+ return *reinterpret_cast<ConversionSet*>(Buffer);
+ }
+
+ const ConversionSet &conversions() const {
+ return *reinterpret_cast<const ConversionSet*>(Buffer);
+ }
+
+ void addConversion(FunctionDecl *D) {
+ conversions().push_back(D);
+ }
+
+ typedef ConversionSet::iterator iterator;
+ iterator begin() { return conversions().begin(); }
+ iterator end() { return conversions().end(); }
+
+ typedef ConversionSet::const_iterator const_iterator;
+ const_iterator begin() const { return conversions().begin(); }
+ const_iterator end() const { return conversions().end(); }
+
+ void construct();
+ void destruct();
+ void copyFrom(const AmbiguousConversionSequence &);
+ };
+
+ /// BadConversionSequence - Records information about an invalid
+ /// conversion sequence.
+ struct BadConversionSequence {
+ enum FailureKind {
+ no_conversion,
+ unrelated_class,
+ suppressed_user,
+ bad_qualifiers
+ };
+
+ // This can be null, e.g. for implicit object arguments.
+ Expr *FromExpr;
+
+ FailureKind Kind;
+
+ private:
+ // The type we're converting from (an opaque QualType).
+ void *FromTy;
+
+ // The type we're converting to (an opaque QualType).
+ void *ToTy;
+
+ public:
+ void init(FailureKind K, Expr *From, QualType To) {
+ init(K, From->getType(), To);
+ FromExpr = From;
+ }
+ void init(FailureKind K, QualType From, QualType To) {
+ Kind = K;
+ FromExpr = 0;
+ setFromType(From);
+ setToType(To);
+ }
+
+ QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); }
+ QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); }
+
+ void setFromExpr(Expr *E) {
+ FromExpr = E;
+ setFromType(E->getType());
+ }
+ void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); }
+ };
+
/// ImplicitConversionSequence - Represents an implicit conversion
/// sequence, which may be a standard conversion sequence
/// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
@@ -197,18 +294,26 @@ namespace clang {
struct ImplicitConversionSequence {
/// Kind - The kind of implicit conversion sequence. BadConversion
/// specifies that there is no conversion from the source type to
- /// the target type. The enumerator values are ordered such that
- /// better implicit conversions have smaller values.
+ /// the target type. AmbiguousConversion represents the unique
+ /// ambiguous conversion (C++0x [over.best.ics]p10).
enum Kind {
StandardConversion = 0,
UserDefinedConversion,
+ AmbiguousConversion,
EllipsisConversion,
BadConversion
};
+ private:
/// ConversionKind - The kind of implicit conversion sequence.
Kind ConversionKind;
+ void setKind(Kind K) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ ConversionKind = K;
+ }
+
+ public:
union {
/// When ConversionKind == StandardConversion, provides the
/// details of the standard conversion sequence.
@@ -217,12 +322,58 @@ namespace clang {
/// When ConversionKind == UserDefinedConversion, provides the
/// details of the user-defined conversion sequence.
UserDefinedConversionSequence UserDefined;
+
+ /// When ConversionKind == AmbiguousConversion, provides the
+ /// details of the ambiguous conversion.
+ AmbiguousConversionSequence Ambiguous;
+
+ /// When ConversionKind == BadConversion, provides the details
+ /// of the bad conversion.
+ BadConversionSequence Bad;
};
+
+ ImplicitConversionSequence() : ConversionKind(BadConversion) {}
+ ~ImplicitConversionSequence() {
+ if (isAmbiguous()) Ambiguous.destruct();
+ }
+ ImplicitConversionSequence(const ImplicitConversionSequence &Other)
+ : ConversionKind(Other.ConversionKind)
+ {
+ switch (ConversionKind) {
+ case StandardConversion: Standard = Other.Standard; break;
+ case UserDefinedConversion: UserDefined = Other.UserDefined; break;
+ case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break;
+ case EllipsisConversion: break;
+ case BadConversion: Bad = Other.Bad; break;
+ }
+ }
+
+ ImplicitConversionSequence &
+ operator=(const ImplicitConversionSequence &Other) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ new (this) ImplicitConversionSequence(Other);
+ return *this;
+ }
- /// When ConversionKind == BadConversion due to multiple conversion
- /// functions, this will list those functions.
- llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet;
-
+ Kind getKind() const { return ConversionKind; }
+ bool isBad() const { return ConversionKind == BadConversion; }
+ bool isStandard() const { return ConversionKind == StandardConversion; }
+ bool isEllipsis() const { return ConversionKind == EllipsisConversion; }
+ bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; }
+ bool isUserDefined() const {
+ return ConversionKind == UserDefinedConversion;
+ }
+
+ void setBad() { setKind(BadConversion); }
+ void setStandard() { setKind(StandardConversion); }
+ void setEllipsis() { setKind(EllipsisConversion); }
+ void setUserDefined() { setKind(UserDefinedConversion); }
+ void setAmbiguous() {
+ if (isAmbiguous()) return;
+ ConversionKind = AmbiguousConversion;
+ Ambiguous.construct();
+ }
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -235,6 +386,13 @@ namespace clang {
void DebugPrint() const;
};
+ enum OverloadFailureKind {
+ ovl_fail_too_many_arguments,
+ ovl_fail_too_few_arguments,
+ ovl_fail_bad_conversion,
+ ovl_fail_bad_deduction
+ };
+
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate {
/// Function - The actual function that this candidate
@@ -275,11 +433,25 @@ namespace clang {
/// object argument.
bool IgnoreObjectArgument;
+ /// FailureKind - The reason why this candidate is not viable.
+ /// Actually an OverloadFailureKind.
+ unsigned char FailureKind;
+
/// FinalConversion - For a conversion function (where Function is
/// a CXXConversionDecl), the standard conversion that occurs
/// after the call to the overload candidate to convert the result
/// of calling the conversion function to the required type.
StandardConversionSequence FinalConversion;
+
+ /// hasAmbiguousConversion - Returns whether this overload
+ /// candidate requires an ambiguous conversion or not.
+ bool hasAmbiguousConversion() const {
+ for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator
+ I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ if (I->isAmbiguous()) return true;
+ }
+ return false;
+ }
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index b8928c36e7b8..7855a7f60935 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1157,7 +1157,8 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
MultiExprArg exprs,
ExprArg asmString,
MultiExprArg clobbers,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool MSAsm) {
unsigned NumClobbers = clobbers.size();
StringLiteral **Constraints =
reinterpret_cast<StringLiteral**>(constraints.get());
@@ -1261,9 +1262,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
asmString.release();
clobbers.release();
AsmStmt *NS =
- new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
- Names, Constraints, Exprs, AsmString, NumClobbers,
- Clobbers, RParenLoc);
+ new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs,
+ NumInputs, Names, Constraints, Exprs, AsmString,
+ NumClobbers, Clobbers, RParenLoc);
// Validate the asm string, ensuring it makes sense given the operands we
// have.
llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8c6aa6a7d4a9..2fad8325d4dd 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -80,6 +80,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
TypeTy *ObjectTypePtr,
bool EnteringContext,
TemplateTy &TemplateResult) {
+ assert(getLangOptions().CPlusPlus && "No template names in C!");
+
DeclarationName TName;
switch (Name.getKind()) {
@@ -141,6 +143,30 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
return TemplateKind;
}
+bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TemplateTy &SuggestedTemplate,
+ TemplateNameKind &SuggestedKind) {
+ // We can't recover unless there's a dependent scope specifier preceding the
+ // template name.
+ if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) ||
+ computeDeclContext(*SS))
+ return false;
+
+ // The code is missing a 'template' keyword prior to the dependent template
+ // name.
+ NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
+ Diag(IILoc, diag::err_template_kw_missing)
+ << Qualifier << II.getName()
+ << CodeModificationHint::CreateInsertion(IILoc, "template ");
+ SuggestedTemplate
+ = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
+ SuggestedKind = TNK_Dependent_template_name;
+ return true;
+}
+
void Sema::LookupTemplateName(LookupResult &Found,
Scope *S, const CXXScopeSpec &SS,
QualType ObjectType,
@@ -192,7 +218,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
ObjectTypeSearchedInScope = true;
}
} else if (isDependent) {
- // We cannot look into a dependent object type or
+ // We cannot look into a dependent object type or nested nme
+ // specifier.
return;
} else {
// Perform unqualified name lookup in the current scope.
@@ -203,7 +230,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
assert(!Found.isAmbiguous() &&
"Cannot handle template name-lookup ambiguities");
- if (Found.empty()) {
+ if (Found.empty() && !isDependent) {
// If we did not find any names, attempt to correct any typos.
DeclarationName Name = Found.getLookupName();
if (CorrectTypo(Found, S, &SS, LookupCtx)) {
@@ -219,6 +246,9 @@ void Sema::LookupTemplateName(LookupResult &Found,
<< Name << Found.getLookupName()
<< CodeModificationHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
+ if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
+ Diag(Template->getLocation(), diag::note_previous_decl)
+ << Template->getDeclName();
} else
Found.clear();
} else {
@@ -1578,15 +1608,19 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
EnteringContext, Template);
- if (TNK == TNK_Non_template) {
+ if (TNK == TNK_Non_template &&
+ isCurrentInstantiationWithDependentBases(SS)) {
+ // This is a dependent template.
+ } else if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
diag::err_template_kw_refers_to_non_template)
<< GetNameFromUnqualifiedId(Name)
<< Name.getSourceRange();
return TemplateTy();
+ } else {
+ // We found something; return it.
+ return Template;
}
-
- return Template;
}
NestedNameSpecifier *Qualifier
@@ -4537,8 +4571,10 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
Matches.clear();
+
Matches.push_back(Method);
- break;
+ if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
+ break;
}
}
}
@@ -4550,7 +4586,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateDeductionInfo Info(Context);
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl,
+ = DeduceTemplateArguments(FunTmpl,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
R, Specialization, Info)) {
// FIXME: Keep track of almost-matches?
@@ -4735,6 +4771,10 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFound:
DiagID = diag::err_typename_nested_not_found;
break;
+
+ case LookupResult::NotFoundInCurrentInstantiation:
+ // Okay, it's a member of an unknown instantiation.
+ return Context.getTypenameType(NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 21f79963bd89..7b433e901e33 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -542,13 +542,13 @@ DeduceTemplateArguments(ASTContext &Context,
// type [i]
case Type::DependentSizedArray: {
- const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
+ const ArrayType *ArrayArg = Context.getAsArrayType(Arg);
if (!ArrayArg)
return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
- = cast<DependentSizedArrayType>(Param);
+ = Context.getAsDependentSizedArrayType(Param);
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(Context, TemplateParams,
DependentArrayParm->getElementType(),
@@ -1312,20 +1312,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// \param FunctionTemplate the function template for which we are performing
/// template argument deduction.
///
-/// \param HasExplicitTemplateArgs whether any template arguments were
-/// explicitly specified.
-///
-/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the explicitly-specified template arguments.
-///
-/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the number of explicitly-specified template arguments in
-/// @p ExplicitTemplateArguments. This value may be zero.
+/// \param ExplicitTemplateArguments the explicit template arguments provided
+/// for this call.
///
/// \param Args the function call arguments
///
/// \param NumArgs the number of arguments in Args
///
+/// \param Name the name of the function being called. This is only significant
+/// when the function template is a conversion function template, in which
+/// case this routine will also perform template argument deduction based on
+/// the function to which
+///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
/// template argument deduction.
@@ -1336,7 +1334,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
/// \returns the result of template argument deduction.
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
Expr **Args, unsigned NumArgs,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
@@ -1475,8 +1473,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
return TDK_FailedOverloadResolution;
}
- // Get the type of the resolved argument.
+ // Get the type of the resolved argument, and adjust it per
+ // C++0x [temp.deduct.call]p3.
ArgType = ResolvedArg->getType();
+ if (!ParamWasReference && ArgType->isFunctionType())
+ ArgType = Context.getPointerType(ArgType);
if (ArgType->isPointerType() || ArgType->isMemberPointerType())
TDF |= TDF_IgnoreQualifiers;
@@ -2173,7 +2174,7 @@ MarkUsedTemplateParameters(Sema &SemaRef,
// FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
// find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
- if (!E)
+ if (!DRE)
return;
const NonTypeTemplateParmDecl *NTTP
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index d974f89bc609..2db0deb5098b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1060,6 +1060,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Exit the scope of this instantiation.
CurContext = PreviousContext;
+ // If this is a polymorphic C++ class without a key function, we'll
+ // have to mark all of the virtual members to allow emission of a vtable
+ // in this translation unit.
+ if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation))
+ ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation,
+ PointOfInstantiation));
+
if (!Invalid)
Consumer.HandleTagDeclDefinition(Instantiation);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ed30229e9523..9515834bb84a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -743,7 +743,8 @@ QualType Sema::BuildFunctionType(QualType T,
bool Variadic, unsigned Quals,
SourceLocation Loc, DeclarationName Entity) {
if (T->isArrayType() || T->isFunctionType()) {
- Diag(Loc, diag::err_func_returning_array_function) << T;
+ Diag(Loc, diag::err_func_returning_array_function)
+ << T->isFunctionType() << T;
return QualType();
}
@@ -896,13 +897,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
break;
case UnqualifiedId::IK_ConstructorName:
+ case UnqualifiedId::IK_ConstructorTemplateId:
case UnqualifiedId::IK_DestructorName:
- case UnqualifiedId::IK_ConversionFunctionId:
// Constructors and destructors don't have return types. Use
- // "void" instead. Conversion operators will check their return
- // types separately.
+ // "void" instead.
T = Context.VoidTy;
break;
+
+ case UnqualifiedId::IK_ConversionFunctionId:
+ // The result type of a conversion function is the type that it
+ // converts to.
+ T = GetTypeFromParser(D.getName().ConversionFunctionId);
+ break;
}
if (T.isNull())
@@ -1041,8 +1047,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
// C99 6.7.5.3p1: The return type may not be a function or array type.
- if (T->isArrayType() || T->isFunctionType()) {
- Diag(DeclType.Loc, diag::err_func_returning_array_function) << T;
+ // For conversion functions, we'll diagnose this particular error later.
+ if ((T->isArrayType() || T->isFunctionType()) &&
+ (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
+ Diag(DeclType.Loc, diag::err_func_returning_array_function)
+ << T->isFunctionType() << T;
T = Context.IntTy;
D.setInvalidType(true);
}
@@ -1351,6 +1360,20 @@ namespace {
cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc());
TL.copy(OldTL);
}
+ void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
+ TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ }
+ void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType);
+ TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ assert(DS.getTypeRep());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
+ TL.setUnderlyingTInfo(TInfo);
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
@@ -1461,34 +1484,6 @@ void LocInfoType::getAsStringInternal(std::string &Str,
" GetTypeFromParser");
}
-/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
-/// declarator
-QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
- ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
- QualType T = MDecl->getResultType();
- llvm::SmallVector<QualType, 16> ArgTys;
-
- // Add the first two invisible argument types for self and _cmd.
- if (MDecl->isInstanceMethod()) {
- QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
- selfTy = Context.getPointerType(selfTy);
- ArgTys.push_back(selfTy);
- } else
- ArgTys.push_back(Context.getObjCIdType());
- ArgTys.push_back(Context.getObjCSelType());
-
- for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
- E = MDecl->param_end(); PI != E; ++PI) {
- QualType ArgTy = (*PI)->getType();
- assert(!ArgTy.isNull() && "Couldn't parse type?");
- ArgTy = adjustParameterType(ArgTy);
- ArgTys.push_back(ArgTy);
- }
- T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
- MDecl->isVariadic(), 0);
- return T;
-}
-
/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that
/// may be similar (C++ 4.4), replaces T1 and T2 with the type that
/// they point to and return true. If T1 and T2 aren't pointer types
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
new file mode 100644
index 000000000000..7c19bf6e4fd4
--- /dev/null
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -0,0 +1,86 @@
+//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains semantic analysis implementation for target-specific
+// attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "TargetAttributesSema.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace clang;
+
+TargetAttributesSema::~TargetAttributesSema() {}
+bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ return false;
+}
+
+static void HandleMSP430InterruptAttr(Decl *d,
+ const AttributeList &Attr, Sema &S) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ return;
+ }
+
+ // FIXME: Check for decl - it should be void ()(void).
+
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt NumParams(32);
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << "interrupt" << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ unsigned Num = NumParams.getLimitedValue(255);
+ if ((Num & 1) || Num > 30) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << "interrupt" << (int)NumParams.getSExtValue()
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ d->addAttr(::new (S.Context) MSP430InterruptAttr(Num));
+ d->addAttr(::new (S.Context) UsedAttr());
+ }
+
+namespace {
+ class MSP430AttributesSema : public TargetAttributesSema {
+ public:
+ MSP430AttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const {
+ if (Attr.getName()->getName() == "interrupt") {
+ HandleMSP430InterruptAttr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
+const TargetAttributesSema &Sema::getTargetAttributesSema() const {
+ if (TheTargetAttributesSema)
+ return *TheTargetAttributesSema;
+
+ const llvm::Triple &Triple(Context.Target.getTriple());
+ switch (Triple.getArch()) {
+ default:
+ return *(TheTargetAttributesSema = new TargetAttributesSema);
+
+ case llvm::Triple::msp430:
+ return *(TheTargetAttributesSema = new MSP430AttributesSema);
+ }
+}
+
diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h
new file mode 100644
index 000000000000..8794e4013ec7
--- /dev/null
+++ b/lib/Sema/TargetAttributesSema.h
@@ -0,0 +1,27 @@
+//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_SEMA_TARGETSEMA_H
+#define CLANG_SEMA_TARGETSEMA_H
+
+namespace clang {
+ class Scope;
+ class Decl;
+ class Attr;
+ class Sema;
+
+ class TargetAttributesSema {
+ public:
+ virtual ~TargetAttributesSema();
+ virtual bool ProcessDeclAttribute(Scope *scope, Decl *D,
+ const AttributeList &Attr, Sema &S) const;
+ };
+}
+
+#endif
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 208c8851e596..445ef0dac797 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -975,12 +975,15 @@ public:
QualType BaseType = ((Expr*) Base.get())->getType();
- // FIXME: wait, this is re-performing lookup?
+ LookupResult R(getSema(), Member->getDeclName(), MemberLoc,
+ Sema::LookupMemberName);
+ R.addDecl(Member);
+ R.resolveKind();
+
return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
OpLoc, isArrow,
SS, FirstQualifierInScope,
- Member->getDeclName(), MemberLoc,
- ExplicitTemplateArgs);
+ R, ExplicitTemplateArgs);
}
/// \brief Build a new binary operator expression.
@@ -1344,9 +1347,11 @@ public:
/// semantic analysis. Subclasses may override this routine to provide
/// different behavior.
OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
- QualType ThisType) {
+ QualType ThisType,
+ bool isImplicit) {
return getSema().Owned(
- new (getSema().Context) CXXThisExpr(ThisLoc, ThisType));
+ new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
+ isImplicit));
}
/// \brief Build a new C++ throw expression.
@@ -1559,6 +1564,7 @@ public:
bool IsArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
+ NamedDecl *FirstQualifierInScope,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
@@ -1567,7 +1573,8 @@ public:
return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
OperatorLoc, IsArrow,
- SS, R, TemplateArgs);
+ SS, FirstQualifierInScope,
+ R, TemplateArgs);
}
/// \brief Build a new Objective-C @encode expression.
@@ -2617,18 +2624,16 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
TypeOfExprTypeLoc TL) {
- TypeOfExprType *T = TL.getTypePtr();
-
// typeof expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
- Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+ Sema::OwningExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
if (E.isInvalid())
return QualType();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
- E.get() != T->getUnderlyingExpr()) {
+ E.get() != TL.getUnderlyingExpr()) {
Result = getDerived().RebuildTypeOfExprType(move(E));
if (Result.isNull())
return QualType();
@@ -2636,7 +2641,9 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
else E.take();
TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setTypeofLoc(TL.getTypeofLoc());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
return Result;
}
@@ -2644,23 +2651,23 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
TypeOfTypeLoc TL) {
- TypeOfType *T = TL.getTypePtr();
-
- // FIXME: should be an inner type, or at least have a TypeSourceInfo.
- QualType Underlying = getDerived().TransformType(T->getUnderlyingType());
- if (Underlying.isNull())
+ TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
+ TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
+ if (!New_Under_TI)
return QualType();
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- Underlying != T->getUnderlyingType()) {
- Result = getDerived().RebuildTypeOfType(Underlying);
+ if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) {
+ Result = getDerived().RebuildTypeOfType(New_Under_TI->getType());
if (Result.isNull())
return QualType();
}
TypeOfTypeLoc NewTL = TLB.push<TypeOfTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setTypeofLoc(TL.getTypeofLoc());
+ NewTL.setLParenLoc(TL.getLParenLoc());
+ NewTL.setRParenLoc(TL.getRParenLoc());
+ NewTL.setUnderlyingTInfo(New_Under_TI);
return Result;
}
@@ -3711,6 +3718,12 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
SourceLocation FakeOperatorLoc
= SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+ // FIXME: to do this check properly, we will need to preserve the
+ // first-qualifier-in-scope here, just in case we had a dependent
+ // base (and therefore couldn't do the check) and a
+ // nested-name-qualifier (and therefore could do the lookup).
+ NamedDecl *FirstQualifierInScope = 0;
+
return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc,
E->isArrow(),
Qualifier,
@@ -3719,7 +3732,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Member,
(E->hasExplicitTemplateArgumentList()
? &TransArgs : 0),
- 0);
+ FirstQualifierInScope);
}
template<typename Derived>
@@ -4386,7 +4399,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
T == E->getType())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCXXThisExpr(E->getLocStart(), T);
+ return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit());
}
template<typename Derived>
@@ -5027,6 +5040,12 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
TransArgs.addArgument(Loc);
}
}
+
+ // FIXME: to do this check properly, we will need to preserve the
+ // first-qualifier-in-scope here, just in case we had a dependent
+ // base (and therefore couldn't do the check) and a
+ // nested-name-qualifier (and therefore could do the lookup).
+ NamedDecl *FirstQualifierInScope = 0;
return getDerived().RebuildUnresolvedMemberExpr(move(Base),
BaseType,
@@ -5034,6 +5053,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
Old->isArrow(),
Qualifier,
Old->getQualifierRange(),
+ FirstQualifierInScope,
R,
(Old->hasExplicitTemplateArgs()
? &TransArgs : 0));
diff --git a/test/Analysis/CFDateGC.m b/test/Analysis/CFDateGC.m
index 01cb4a461332..34bc3c0f199b 100644
--- a/test/Analysis/CFDateGC.m
+++ b/test/Analysis/CFDateGC.m
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -disable-free %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=basic %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -analyzer-constraints=range %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -verify -fobjc-gc -disable-free %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from
@@ -36,6 +36,8 @@ static __inline__ __attribute__((always_inline)) id NSMakeCollectable(CFTypeRef
// Test cases.
//===----------------------------------------------------------------------===//
+CFAbsoluteTime CFAbsoluteTimeGetCurrent();
+
CFAbsoluteTime f1_use_after_release() {
CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
CFDateRef date = CFDateCreate(0, t);
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index fb44309b1248..515b9f7f3de0 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -388,3 +388,19 @@ void test_synchronized(id x) {
}
}
@end
+
+void testOSCompareAndSwapXXBarrier_parameter(NSString **old) {
+ NSString *s = [[NSString alloc] init]; // no-warning
+ if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old))
+ [s release];
+ else
+ [*old release];
+}
+
+void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) {
+ NSString *s = [[NSString alloc] init]; // no-warning
+ if (!COMPARE_SWAP_BARRIER((intptr_t) 0, (intptr_t) s, (intptr_t*) old))
+ [s release];
+ else
+ return;
+}
diff --git a/test/Analysis/PR2599.m b/test/Analysis/PR2599.m
index e866ee6cb270..d26096129e33 100644
--- a/test/Analysis/PR2599.m
+++ b/test/Analysis/PR2599.m
@@ -53,6 +53,8 @@ extern NSString * const NSXMLParserErrorDomain ;
static char *lorem = "fooBarBaz";
+void NSLog(NSString *, ...);
+
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *tmp1 = NSSTRINGWRAPPER(lorem, 6); // no-warning
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 947f63ef48b6..ef398bb173be 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-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 *'.
@@ -11,6 +12,8 @@ typedef __darwin_socklen_t socklen_t;
struct sockaddr { sa_family_t sa_family; };
struct sockaddr_storage {};
+void getsockname();
+
void f(int sock) {
struct sockaddr_storage storage;
struct sockaddr* sockaddr = (struct sockaddr*)&storage;
@@ -45,3 +48,20 @@ void f2(const char *str) {
if(!cl)
cl = 'a';
}
+
+// Test cast VariableSizeArray to pointer does not crash.
+void *memcpy(void *, void const *, unsigned long);
+typedef unsigned char Byte;
+void doit(char *data, int len) {
+ if (len) {
+ Byte buf[len];
+ memcpy(buf, data, len);
+ }
+}
+
+// PR 6013 and 6035 - Test that a cast of a pointer to long and then to int does not crash SValuator.
+void pr6013_6035_test(void *p) {
+ unsigned int foo;
+ foo = ((long)(p));
+ (void) foo;
+}
diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c
index 63c9d0d97a44..91f2b2afebd2 100644
--- a/test/Analysis/dead-stores.c
+++ b/test/Analysis/dead-stores.c
@@ -17,6 +17,8 @@ void f2(void *b) {
// expected-note{{please include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
}
+int f();
+
void f3() {
int r;
if ((r = f()) != 0) { // no-warning
diff --git a/test/Analysis/misc-ps-ranges.m b/test/Analysis/misc-ps-ranges.m
index 760b4d743357..df7e97c46736 100644
--- a/test/Analysis/misc-ps-ranges.m
+++ b/test/Analysis/misc-ps-ranges.m
@@ -21,3 +21,40 @@ int main(int argc, char* argv[]) {
return *p; // no-warning
}
+
+// PR 5969: the comparison of argc < 3 || argc > 4 should constraint the switch
+// statement from having the 'default' branch taken. This previously reported a false
+// positive with the use of 'v'.
+
+int pr5969(int argc, char *argv[]) {
+
+ int v;
+
+ if ((argc < 3) || (argc > 4)) return 0;
+
+ switch(argc) {
+ case 3:
+ v = 33;
+ break;
+ case 4:
+ v = 44;
+ break;
+ }
+
+ return v; // no-warning
+}
+
+int pr5969_positive(int argc, char *argv[]) {
+
+ int v;
+
+ if ((argc < 3) || (argc > 4)) return 0;
+
+ switch(argc) {
+ case 3:
+ v = 33;
+ break;
+ }
+
+ return v; // expected-warning{{Undefined or garbage value returned to caller}}
+}
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index 225abb5aa19a..8b5813118787 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -34,6 +34,10 @@ int test3(Test3_Derived x) {
return test3_aux(x);
}
+//===---------------------------------------------------------------------===//
+// Test CFG support for C++ condition variables.
+//===---------------------------------------------------------------------===//
+
int test_init_in_condition_aux();
int test_init_in_condition() {
if (int x = test_init_in_condition_aux()) { // no-warning
@@ -89,3 +93,42 @@ int test_init_in_condition_for() {
*p = 0xDEADBEEF; // no-warning
return 0;
}
+
+//===---------------------------------------------------------------------===//
+// Test handling of 'this' pointer.
+//===---------------------------------------------------------------------===//
+
+class TestHandleThis {
+ int x;
+
+ TestHandleThis();
+ int foo();
+ int null_deref_negative();
+ int null_deref_positive();
+};
+
+int TestHandleThis::foo() {
+ // Assume that 'x' is initialized.
+ return x + 1; // no-warning
+}
+
+int TestHandleThis::null_deref_negative() {
+ x = 10;
+ if (x == 10) {
+ return 1;
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ return 0;
+}
+
+int TestHandleThis::null_deref_positive() {
+ x = 10;
+ if (x == 9) {
+ return 1;
+ }
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{null pointer}}
+ return 0;
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 7f29c99a44d7..a88c26c29ed7 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -55,7 +55,7 @@ void checkaccess_union() {
// Check our handling of fields being invalidated by function calls.
struct test2_struct { int x; int y; char* s; };
-void test2_helper(struct test2_struct* p);
+void test2_help(struct test2_struct* p);
char test2() {
struct test2_struct s;
@@ -387,7 +387,7 @@ void rdar_7332673_test1() {
char value[1];
if ( *(value) != 1 ) {} // expected-warning{{The left operand of '!=' is a garbage value}}
}
-void rdar_rdar_7332673_test2_aux(char *x);
+int rdar_7332673_test2_aux(char *x);
void rdar_7332673_test2() {
char *value;
if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{Pass-by-value argument in function call is undefined}}
@@ -631,7 +631,7 @@ typedef void (^RDar_7462324_Callback)(id obj);
//===----------------------------------------------------------------------===//
int rdar7468209_aux();
-void rdar7468209_aux2();
+void rdar7468209_aux_2();
void rdar7468209() {
__block int x = 0;
@@ -684,3 +684,49 @@ void pr4358(struct pr4358 *pnt) {
}
pr4358_aux(uninit); // no-warning
}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7526777>
+// Test handling fields of values returned from function calls or
+// message expressions.
+//===----------------------------------------------------------------------===//
+
+typedef struct testReturn_rdar_7526777 {
+ int x;
+ int y;
+} testReturn_rdar_7526777;
+
+@interface TestReturnStruct_rdar_7526777
+- (testReturn_rdar_7526777) foo;
+@end
+
+int test_return_struct(TestReturnStruct_rdar_7526777 *x) {
+ return [x foo].x;
+}
+
+testReturn_rdar_7526777 test_return_struct_2_aux_rdar_7526777();
+
+int test_return_struct_2_rdar_7526777() {
+ return test_return_struct_2_aux_rdar_7526777().x;
+}
+
+//===----------------------------------------------------------------------===//
+// <rdar://problem/7527292> Assertion failed: (Op == BinaryOperator::Add ||
+// Op == BinaryOperator::Sub)
+// This test case previously triggered an assertion failure due to a discrepancy
+// been the loaded/stored value in the array
+//===----------------------------------------------------------------------===//
+
+_Bool OSAtomicCompareAndSwapPtrBarrier( void *__oldValue, void *__newValue, void * volatile *__theValue );
+
+void rdar_7527292() {
+ static id Cache7527292[32];
+ for (signed long idx = 0;
+ idx < 32;
+ idx++) {
+ id v = Cache7527292[idx];
+ if (v && OSAtomicCompareAndSwapPtrBarrier(v, ((void*)0), (void * volatile *)(Cache7527292 + idx))) {
+ }
+ }
+}
+
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 53b9b6f4fa67..9543a98fe323 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1,8 +1,12 @@
// NOTE: Use '-fobjc-gc' to test the analysis being run twice, and multiple reports are not issued.
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
-// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -fobjc-gc -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=basic -analyzer-constraints=range -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=basic -verify -fblocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -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;
@@ -87,16 +91,16 @@ void r6268365() {
void divzeroassume(unsigned x, unsigned j) {
x /= j;
- if (j == 0) x /= 0; // no-warning
- if (j == 0) x /= j; // no-warning
- if (j == 0) x = x / 0; // no-warning
+ if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}}
+ if (j == 0) x /= j; // no static-analyzer warning
+ if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}}
}
void divzeroassumeB(unsigned x, unsigned j) {
x = x / j;
- if (j == 0) x /= 0; // no-warning
- if (j == 0) x /= j; // no-warning
- if (j == 0) x = x / 0; // no-warning
+ if (j == 0) x /= 0; // no static-analyzer warning expected-warning {{division by zero is undefined}}
+ if (j == 0) x /= j; // no static-analyzer warning
+ if (j == 0) x = x / 0; // no static-analyzer warning expected-warning {{division by zero is undefined}}
}
// InitListExpr processing
@@ -460,6 +464,8 @@ void test_block_cast() {
(void (^)(void *))test_block_cast_aux(); // expected-warning{{expression result unused}}
}
+int OSAtomicCompareAndSwap32Barrier();
+
// Test comparison of 'id' instance variable to a null void* constant after
// performing an OSAtomicCompareAndSwap32Barrier.
// This previously was a crash in RegionStoreManager.
@@ -493,6 +499,8 @@ void test_invalidate_cast_int() {
return;
}
+int ivar_getOffset();
+
// Reduced from a crash involving the cast of an Objective-C symbolic region to
// 'char *'
static NSNumber *test_ivar_offset(id self, SEL _cmd, Ivar inIvar) {
@@ -793,3 +801,13 @@ void test_bad_msg(TestBadArg *p) {
[p testBadArg:y]; // expected-warning{{Pass-by-value argument in message expression is undefined}}
}
+//===----------------------------------------------------------------------===//
+// PR 6033 - Test emitting the correct output in a warning where we use '%'
+// with operands that are undefined.
+//===----------------------------------------------------------------------===//
+
+int pr6033(int x) {
+ int y;
+ return x % y; // expected-warning{{The right operand of '%' is a garbage value}}
+}
+
diff --git a/test/Analysis/rdar-6442306-1.m b/test/Analysis/rdar-6442306-1.m
index 1eae5d779dd6..b3558a632147 100644
--- a/test/Analysis/rdar-6442306-1.m
+++ b/test/Analysis/rdar-6442306-1.m
@@ -13,6 +13,8 @@ typedef struct {
QuxSize size;
} __Request__SetPortalSize_t;
+double __Foo_READSWAP__double(double*);
+
static __inline__ bar_return_t
__Beeble_check__Request__SetPortalSize_t(__attribute__((__unused__)) __Request__SetPortalSize_t *In0P) {
if (In0P->Foo.int_rep != Foo_record.int_rep) {
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
new file mode 100644
index 000000000000..a641b8e8212f
--- /dev/null
+++ b/test/Analysis/reference.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify %s
+
+void f1() {
+ int const &i = 3;
+ int b = i;
+
+ int *p = 0;
+
+ if (b != 3)
+ *p = 1; // no-warning
+}
diff --git a/test/Analysis/retain-release-basic-store.m b/test/Analysis/retain-release-basic-store.m
index 58321bb388dc..2ef061a99885 100644
--- a/test/Analysis/retain-release-basic-store.m
+++ b/test/Analysis/retain-release-basic-store.m
@@ -86,6 +86,8 @@ struct foo {
NSDate* f;
};
+CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+
CFAbsoluteTime f4() {
struct foo x;
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index 35dc6e711081..3a0142b29550 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -93,6 +93,8 @@ typedef unsigned long NSUInteger;
// Test to see if we *issue* an error when we store the pointer
// to a struct. This differs from basic store.
+CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+
struct foo {
NSDate* f;
};
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index f5d985ebd448..691e2a2f58a5 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -881,6 +881,8 @@ void IOServiceAddMatchingNotification_wrapper(IONotificationPortRef notifyPort,
// Test of handling objects whose references "escape" to containers.
//===----------------------------------------------------------------------===//
+void CFDictionaryAddValue();
+
// <rdar://problem/6539791>
void rdar_6539791(CFMutableDictionaryRef y, void* key, void* val_key) {
CFMutableDictionaryRef x = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
diff --git a/test/Analysis/security-syntax-checks-no-emit.c b/test/Analysis/security-syntax-checks-no-emit.c
new file mode 100644
index 000000000000..fbfeb1a40413
--- /dev/null
+++ b/test/Analysis/security-syntax-checks-no-emit.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -analyze -warn-security-syntactic %s -verify
+
+// This file complements 'security-syntax-checks.m', but tests that we omit
+// specific checks on platforms where they don't make sense.
+
+// Omit the 'rand' check since 'arc4random' is not available on Linux.
+int rand(void);
+double drand48(void);
+double erand48(unsigned short[3]);
+long jrand48(unsigned short[3]);
+void lcong48(unsigned short[7]);
+long lrand48(void);
+long mrand48(void);
+long nrand48(unsigned short[3]);
+long random(void);
+int rand_r(unsigned *);
+
+void test_rand()
+{
+ unsigned short a[7];
+ unsigned b;
+
+ rand(); // no-warning
+ drand48(); // no-warning
+ erand48(a); // no-warning
+ jrand48(a); // no-warning
+ lcong48(a); // no-warning
+ lrand48(); // no-warning
+ mrand48(); // no-warning
+ nrand48(a); // no-warning
+ rand_r(&b); // no-warning
+ random(); // no-warning
+}
diff --git a/test/Analysis/stack-addr-ps.c b/test/Analysis/stack-addr-ps.c
index e58c7804ddba..315b9007d889 100644
--- a/test/Analysis/stack-addr-ps.c
+++ b/test/Analysis/stack-addr-ps.c
@@ -68,3 +68,10 @@ ComparatorBlock test_return_block_neg(void) {
return b; // no-warning
}
+// <rdar://problem/7523821>
+int *rdar_7523821_f2() {
+ int a[3];
+ return a; // expected-warning 2 {{ddress of stack memory associated with local variable 'a' returned}}
+};
+
+
diff --git a/test/Analysis/uninit-vals-ps-region.c b/test/Analysis/uninit-vals-ps-region.c
index ce86ad05320a..216856e549c7 100644
--- a/test/Analysis/uninit-vals-ps-region.c
+++ b/test/Analysis/uninit-vals-ps-region.c
@@ -20,6 +20,7 @@ void f4() {
// Test uninitialized value due to part of the structure being uninitialized.
struct TestUninit { int x; int y; };
struct TestUninit test_uninit_aux();
+void test_unit_aux2(int);
void test_uninit_pos() {
struct TestUninit v1 = { 0, 0 };
struct TestUninit v2 = test_uninit_aux();
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
new file mode 100644
index 000000000000..7ecedd5a6a0c
--- /dev/null
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct X0 {
+ X0 f1();
+ X0 f2();
+};
+
+template<typename T>
+struct X1 {
+ X1<T>(int);
+ (X1<T>)(float);
+ X1 f2();
+ X1 f2(int);
+ X1 f2(float);
+};
+
+// Error recovery: out-of-line constructors whose names have template arguments.
+template<typename T> X1<T>::X1<T>(int) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
+template<typename T> (X1<T>::X1<T>)(float) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
+
+// Error recovery: out-of-line constructor names intended to be types
+X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type wherever a constructor can be declared}}
+
+struct X0::X0 X0::f2() { return X0(); }
+
+template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
+template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
+template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
index f2dc64b80742..23da98ce7ee6 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
@@ -166,7 +166,8 @@ namespace test3 {
template <class T> struct C : A<T> {
using typename A<T>::type;
- using typename A<T>::hiding; // expected-error {{'typename' keyword used on a non-type}}
+ using typename A<T>::hiding; // expected-note {{declared at}} \
+ // expected-error {{'typename' keyword used on a non-type}}
using typename A<T>::union_member; // expected-error {{'typename' keyword used on a non-type}}
using typename A<T>::enumerator; // expected-error {{'typename' keyword used on a non-type}}
@@ -175,7 +176,7 @@ namespace test3 {
}
void test7() {
- Opaque0 _ = hiding; // expected-error {{expected '(' for function-style cast or type construction}}
+ Opaque0 _ = hiding; // expected-error {{does not refer to a value}}
}
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp
index 06c6695008e0..c16ba201df72 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp
@@ -1,9 +1,15 @@
// RUN: %clang_cc1 -verify %s
-// XFAIL: *
struct S {
typedef struct A {} A; // expected-note {{previous definition is here}}
typedef struct B B;
typedef A A; // expected-error {{redefinition of 'A'}}
+
+ struct C { };
+ typedef struct C OtherC;
+ typedef OtherC C;
+
+ typedef struct D { } D2;
+ typedef D2 D;
};
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
index a0904189161b..cf3db5175fa4 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-struct Base { }; // expected-note{{candidate function}}
-struct Derived : Base { }; // expected-note{{candidate function}}
+struct Base { }; // expected-note{{candidate is the implicit copy constructor}}
+struct Derived : Base { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
struct Unrelated { };
struct Derived2 : Base { };
struct Diamond : Derived, Derived2 { };
diff --git a/test/CXX/special/class.ctor/p1.cpp b/test/CXX/special/class.ctor/p1.cpp
new file mode 100644
index 000000000000..9500a7d2346d
--- /dev/null
+++ b/test/CXX/special/class.ctor/p1.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct X0 {
+ struct type { };
+
+ X0();
+ X0(int);
+ (X0)(float);
+ X0 (f0)(int);
+ X0 (f0)(type);
+
+ X0 f1();
+ X0 f1(double);
+};
+
+X0::X0() { }
+(X0::X0)(int) { }
+
+X0 (X0::f0)(int) { return X0(); }
+
+template<typename T>
+struct X1 {
+ struct type { };
+
+ X1<T>();
+ X1<T>(int);
+ (X1<T>)(float);
+ X1(float, float);
+ (X1)(double);
+ X1<T> (f0)(int);
+ X1<T> (f0)(type);
+ X1 (f1)(int);
+ X1 (f1)(type);
+
+ template<typename U> X1(U);
+ X1 f2();
+ X1 f2(int);
+};
+
+template<typename T> X1<T>::X1() { }
+template<typename T> (X1<T>::X1)(double) { }
+template<typename T> X1<T> X1<T>::f1(int) { return 0; }
+template<typename T> X1<T> (X1<T>::f1)(type) { return 0; }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
index aa53ebc58025..9fc4a5809f35 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
@@ -14,7 +14,7 @@ struct InitOkay {
InitOkay(int) { }
};
-struct CannotInit { }; // expected-note{{candidate function}}
+struct CannotInit { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
int &returnInt() { return X<int>::value; }
float &returnFloat() { return X<float>::value; }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index 3cefeb821e99..2eae1125c0db 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -12,7 +12,7 @@ struct X1 {
X1(int);
};
-struct X2 { }; // expected-note{{candidate function}}
+struct X2 { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
int& get_int() { return X0<int>::value; }
X1& get_X1() { return X0<X1>::value; }
diff --git a/test/CXX/temp/temp.decls/temp.mem/p5.cpp b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
new file mode 100644
index 000000000000..098ffa4dec75
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.mem/p5.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A {
+ template <class T> operator T*();
+};
+
+template <class T> A::operator T*() { return 0; }
+template <> A::operator char*(){ return 0; } // specialization
+template A::operator void*(); // explicit instantiation
+
+int main() {
+ A a;
+ int *ip;
+ ip = a.operator int*();
+}
+
+// PR5742
+namespace PR5742 {
+ template <class T> struct A { };
+ template <class T> struct B { };
+
+ struct S {
+ template <class T> operator T();
+ } s;
+
+ void f() {
+ s.operator A<A<int> >();
+ s.operator A<B<int> >();
+ s.operator A<B<A<int> > >();
+ }
+}
+
+// PR5762
+class Foo {
+ public:
+ template <typename T> operator T();
+
+ template <typename T>
+ T As() {
+ return this->operator T();
+ }
+
+ template <typename T>
+ T As2() {
+ return operator T();
+ }
+
+ int AsInt() {
+ return this->operator int();
+ }
+};
+
+template float Foo::As();
+template double Foo::As2();
+
+// Partial ordering with conversion function templates.
+struct X0 {
+ template<typename T> operator T*() {
+ T x;
+ x = 17; // expected-error{{read-only variable is not assignable}}
+ }
+
+ template<typename T> operator T*() const; // expected-note{{explicit instantiation refers here}}
+
+ template<typename T> operator const T*() const {
+ T x = T();
+ return x; // expected-error{{cannot initialize return object of type 'char const *' with an lvalue of type 'char'}}
+ }
+};
+
+template X0::operator const char*() const; // expected-note{{'X0::operator char const *<char>' requested here}}
+template X0::operator const int*(); // expected-note{{'X0::operator int const *<int const>' requested here}}
+template X0::operator float*() const; // expected-error{{explicit instantiation of undefined function template}}
+
+void test_X0(X0 x0, const X0 &x0c) {
+ x0.operator const int*();
+ x0.operator float *();
+ x0c.operator const char*();
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
index 2530f128a49d..8fb736ca0313 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
@@ -9,3 +9,36 @@ void g() {
// Z is deduced to be double
f("aa",3.0); // expected-error{{no matching}}
}
+
+// PR5910
+namespace PR5910 {
+ template <typename T>
+ void Func() {}
+
+ template <typename R>
+ void Foo(R (*fp)());
+
+ void Test() {
+ Foo(Func<int>);
+ }
+}
+
+// PR5949
+namespace PR5949 {
+ struct Bar;
+
+ template <class Container>
+ void quuz(const Container &cont) {
+ }
+
+ template<typename T>
+ int Foo(Bar *b, void (*Baz)(const T &t), T * = 0) {
+ return 0;
+ }
+
+ template<typename T>
+ int Quux(Bar *b, T * = 0)
+ {
+ return Foo<T>(b, quuz);
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
index 9fefbe1b0368..19962c534909 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
@@ -22,12 +22,14 @@ void test_f1(int i, const int ci, volatile int vi) {
template<typename T, unsigned N> struct B { };
template<typename T, unsigned N> B<T, N> g0(T (&array)[N]);
+template<typename T, unsigned N> B<T, N> g0b(const T (&array)[N]);
void test_g0() {
int array0[5];
B<int, 5> b0 = g0(array0);
const int array1[] = { 1, 2, 3};
B<const int, 3> b1 = g0(array1);
+ B<int, 3> b2 = g0b(array1);
}
template<typename T> B<T, 0> g1(const A<T>&);
@@ -48,6 +50,19 @@ void test_f2(int i, const int ci, volatile int vi) {
A<volatile int> a2 = f2(vi);
}
+// PR5913
+template <typename T, int N>
+void Foo(const T (&a)[N]) {
+ T x;
+ x = 0;
+}
+
+const int a[1] = { 0 };
+
+void Test() {
+ Foo(a);
+}
+
// - The transformed A can be another pointer or pointer to member type that
// can be converted to the deduced A via a qualification conversion (4.4).
template<typename T> A<T> f3(T * * const * const);
diff --git a/test/CXX/temp/temp.param/p3.cpp b/test/CXX/temp/temp.param/p3.cpp
index 67d648ea97bb..8fcc2dc85957 100644
--- a/test/CXX/temp/temp.param/p3.cpp
+++ b/test/CXX/temp/temp.param/p3.cpp
@@ -15,7 +15,7 @@ template<template<class T> class Y> struct X1 {
// could be interpreted as either a non-type template-parameter or a
// type-parameter (because its identifier is the name of an already
// existing class) is taken as a type-parameter. For example,
-class T { /* ... */ }; // expected-note{{candidate function}}
+class T { /* ... */ }; // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
int i;
template<class T, T i> struct X2 {
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
index 6e7f80842ec0..a5ecf5fcd9d2 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct NonDefaultConstructible {
- NonDefaultConstructible(const NonDefaultConstructible&); // expected-note{{candidate function}}
+ NonDefaultConstructible(const NonDefaultConstructible&); // expected-note{{candidate constructor}}
};
template<typename T, typename U>
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
index 3eaf89689a25..772aef6b585a 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-struct IntHolder { // expected-note{{here}} // expected-note 2{{candidate function}}
- IntHolder(int); // expected-note 2{{candidate function}}
+struct IntHolder { // expected-note{{here}} // expected-note 2{{candidate constructor (the implicit copy constructor)}}
+ IntHolder(int); // expected-note 2{{candidate constructor}}
};
template<typename T, typename U>
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
index 626bdf181503..b42633924e82 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1.cpp
@@ -48,8 +48,8 @@ template void X1<int>::f<>(int&, int*); // expected-note{{instantiation}}
// Explicitly instantiate members of a class template
struct Incomplete; // expected-note{{forward declaration}}
-struct NonDefaultConstructible { // expected-note{{candidate function}}
- NonDefaultConstructible(int); // expected-note{{candidate function}}
+struct NonDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor) not viable}}
+ NonDefaultConstructible(int); // expected-note{{candidate constructor}}
};
template<typename T, typename U>
diff --git a/test/CodeCompletion/Inputs/macros.h b/test/CodeCompletion/Inputs/macros.h
new file mode 100644
index 000000000000..98b5ac6510a1
--- /dev/null
+++ b/test/CodeCompletion/Inputs/macros.h
@@ -0,0 +1,4 @@
+#define FOO
+#define BAR(X, Y) X, Y
+#define IDENTITY(X) X
+#define WIBBLE(...)
diff --git a/test/CodeCompletion/enum-switch-case-qualified.cpp b/test/CodeCompletion/enum-switch-case-qualified.cpp
index d441269336fd..b9efcb43ed2b 100644
--- a/test/CodeCompletion/enum-switch-case-qualified.cpp
+++ b/test/CodeCompletion/enum-switch-case-qualified.cpp
@@ -22,11 +22,11 @@ void test(enum N::C::Color color) {
switch (color) {
case
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:8 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: Blue : 0 : [#enum M::N::C::Color#]N::C::Blue
- // CHECK-CC1-NEXT: Green : 0 : [#enum M::N::C::Color#]N::C::Green
- // CHECK-CC1-NEXT: Indigo : 0 : [#enum M::N::C::Color#]N::C::Indigo
- // CHECK-CC1-NEXT: Orange : 0 : [#enum M::N::C::Color#]N::C::Orange
- // CHECK-CC1-NEXT: Red : 0 : [#enum M::N::C::Color#]N::C::Red
- // CHECK-CC1-NEXT: Violet : 0 : [#enum M::N::C::Color#]N::C::Violet
- // CHECK-CC1: Yellow : 0 : [#enum M::N::C::Color#]N::C::Yellow
+ // CHECK-CC1: Blue : [#enum M::N::C::Color#]N::C::Blue
+ // CHECK-CC1-NEXT: Green : [#enum M::N::C::Color#]N::C::Green
+ // CHECK-CC1-NEXT: Indigo : [#enum M::N::C::Color#]N::C::Indigo
+ // CHECK-CC1-NEXT: Orange : [#enum M::N::C::Color#]N::C::Orange
+ // CHECK-CC1-NEXT: Red : [#enum M::N::C::Color#]N::C::Red
+ // CHECK-CC1-NEXT: Violet : [#enum M::N::C::Color#]N::C::Violet
+ // CHECK-CC1: Yellow : [#enum M::N::C::Color#]N::C::Yellow
diff --git a/test/CodeCompletion/enum-switch-case.c b/test/CodeCompletion/enum-switch-case.c
index 1a7c58fc1e25..082072600ffe 100644
--- a/test/CodeCompletion/enum-switch-case.c
+++ b/test/CodeCompletion/enum-switch-case.c
@@ -20,9 +20,9 @@ void test(enum Color color) {
break;
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:19:10 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: Blue : 0
- // CHECK-CC1-NEXT: Green : 0
- // CHECK-CC1-NEXT: Indigo : 0
- // CHECK-CC1-NEXT: Orange : 0
- // CHECK-CC1-NEXT: Violet : 0
+ // CHECK-CC1: Blue
+ // CHECK-CC1-NEXT: Green
+ // CHECK-CC1-NEXT: Indigo
+ // CHECK-CC1-NEXT: Orange
+ // CHECK-CC1-NEXT: Violet
diff --git a/test/CodeCompletion/enum-switch-case.cpp b/test/CodeCompletion/enum-switch-case.cpp
index ee8facae0dd3..412f5f2f074d 100644
--- a/test/CodeCompletion/enum-switch-case.cpp
+++ b/test/CodeCompletion/enum-switch-case.cpp
@@ -20,9 +20,9 @@ void test(enum N::Color color) {
case
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:21:8 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: Blue : 0 : [#enum N::Color#]N::Blue
- // CHECK-CC1-NEXT: Green : 0 : [#enum N::Color#]N::Green
- // CHECK-CC1-NEXT: Indigo : 0 : [#enum N::Color#]N::Indigo
- // CHECK-CC1-NEXT: Orange : 0 : [#enum N::Color#]N::Orange
- // CHECK-CC1-NEXT: Violet : 0 : [#enum N::Color#]N::Violet
+ // CHECK-CC1: Blue : [#enum N::Color#]N::Blue
+ // CHECK-CC1-NEXT: Green : [#enum N::Color#]N::Green
+ // CHECK-CC1-NEXT: Indigo : [#enum N::Color#]N::Indigo
+ // CHECK-CC1-NEXT: Orange : [#enum N::Color#]N::Orange
+ // CHECK-CC1-NEXT: Violet : [#enum N::Color#]N::Violet
diff --git a/test/CodeCompletion/macros.c b/test/CodeCompletion/macros.c
index 0ba2f065c4ea..6330d25172c0 100644
--- a/test/CodeCompletion/macros.c
+++ b/test/CodeCompletion/macros.c
@@ -1,8 +1,3 @@
-#define FOO
-#define BAR(X, Y) X, Y
-#define IDENTITY(X) X
-#define WIBBLE(...)
-
enum Color {
Red, Green, Blue
};
@@ -13,24 +8,31 @@ struct Point {
};
void test(struct Point *p) {
- // RUN: %clang_cc1 -fsyntax-only -code-completion-macros -code-completion-at=%s:17:14 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s
switch (p->IDENTITY(color)) {
- // RUN: %clang_cc1 -fsyntax-only -code-completion-macros -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC2 %s
+ // RUN: %clang_cc1 -include %S/Inputs/macros.h -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s
case
}
- // CC1: color
- // CC1: x
- // CC1: y
- // CC1: z
+
+ // Run the same tests, this time with macros loaded from the PCH file.
+ // RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/macros.h
+ // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:12:14 %s -o - | FileCheck -check-prefix=CC1 %s
+ // RUN: %clang_cc1 -include-pch %t -fsyntax-only -code-completion-macros -code-completion-at=%s:14:9 %s -o - | FileCheck -check-prefix=CC2 %s
+
// CC1: BAR(<#X#>, <#Y#>)
+ // CC1: color
// CC1: FOO
// CC1: IDENTITY(<#X#>)
// CC1: WIBBLE
- // CC2: Blue
- // CC2: Green
- // CC2: Red
+ // CC1: x
+ // CC1: y
+ // CC1: z
+
// CC2: BAR(<#X#>, <#Y#>)
+ // CC2: Blue
// CC2: FOO
+ // CC2: Green
// CC2: IDENTITY(<#X#>)
+ // CC2: Red
// CC2: WIBBLE
}
diff --git a/test/CodeCompletion/member-access.cpp b/test/CodeCompletion/member-access.cpp
index 7d1637c2726f..8f772c065279 100644
--- a/test/CodeCompletion/member-access.cpp
+++ b/test/CodeCompletion/member-access.cpp
@@ -28,15 +28,15 @@ public:
void test(const Proxy &p) {
p->
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
- // CHECK-CC1: member1 : 0 : [#int#][#Base1::#]member1
- // CHECK-CC1: member1 : 0 : [#int#][#Base2::#]member1
- // CHECK-CC1: member2 : 0 : [#float#][#Base1::#]member2
- // CHECK-CC1: member3 : 0
- // CHECK-CC1: member4 : 0
- // CHECK-CC1: memfun1 : 0 : [#void#][#Base3::#]memfun1(<#float#>)
- // CHECK-CC1: memfun1 : 0 : [#void#][#Base3::#]memfun1(<#double#>)[# const#]
- // CHECK-CC1: memfun2 : 0 : [#void#][#Base3::#]memfun2(<#int#>)
- // CHECK-CC1: memfun3 : 0 : [#int#]memfun3(<#int#>)
- // CHECK-CC1: memfun1 : 0 (Hidden) : [#void#]Base2::memfun1(<#int#>)
- // CHECK-CC1: Base1 : 3 : Base1::
+ // CHECK-CC1: Base1 : Base1::
+ // CHECK-CC1: member1 : [#int#][#Base1::#]member1
+ // CHECK-CC1: member1 : [#int#][#Base2::#]member1
+ // CHECK-CC1: member2 : [#float#][#Base1::#]member2
+ // CHECK-CC1: member3
+ // CHECK-CC1: member4
+ // CHECK-CC1: memfun1 : [#void#][#Base3::#]memfun1(<#float#>)
+ // CHECK-CC1: memfun1 : [#void#][#Base3::#]memfun1(<#double#>)[# const#]
+ // CHECK-CC1: memfun1 (Hidden) : [#void#]Base2::memfun1(<#int#>)
+ // CHECK-CC1: memfun2 : [#void#][#Base3::#]memfun2(<#int#>)
+ // CHECK-CC1: memfun3 : [#int#]memfun3(<#int#>)
diff --git a/test/CodeCompletion/namespace-alias.cpp b/test/CodeCompletion/namespace-alias.cpp
index 45116621474c..efbf99637285 100644
--- a/test/CodeCompletion/namespace-alias.cpp
+++ b/test/CodeCompletion/namespace-alias.cpp
@@ -12,9 +12,9 @@ namespace N2 {
namespace New =
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:13:18 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: I1 : 1
- // CHECK-CC1: I4 : 1
- // CHECK-CC1: I5 : 1
- // CHECK-CC1: N2 : 3
- // CHECK-CC1-NEXT: N4 : 3
+ // CHECK-CC1: I1
+ // CHECK-CC1: I4
+ // CHECK-CC1: I5
+ // CHECK-CC1: N2
+ // CHECK-CC1-NEXT: N4
diff --git a/test/CodeCompletion/namespace.cpp b/test/CodeCompletion/namespace.cpp
index 8a421122b0a6..ecd848039a87 100644
--- a/test/CodeCompletion/namespace.cpp
+++ b/test/CodeCompletion/namespace.cpp
@@ -9,6 +9,6 @@ namespace N2 {
namespace
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: I1 : 0
- // CHECK-CC1-NEXT: I5 : 0
+ // CHECK-CC1: I1
+ // CHECK-CC1-NEXT: I5
diff --git a/test/CodeCompletion/nested-name-specifier.cpp b/test/CodeCompletion/nested-name-specifier.cpp
index 643418accd07..e09a14b4cb46 100644
--- a/test/CodeCompletion/nested-name-specifier.cpp
+++ b/test/CodeCompletion/nested-name-specifier.cpp
@@ -11,7 +11,7 @@ namespace N {
N::
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:12:4 %s -o - | FileCheck -check-prefix=CC1 %s
-// CHECK-CC1: A : 0
-// CHECK-CC1: B : 0
-// CHECK-CC1: M : 0
+// CHECK-CC1: A
+// CHECK-CC1: B
+// CHECK-CC1: M
diff --git a/test/CodeCompletion/objc-message.m b/test/CodeCompletion/objc-message.m
index a1ae271bbead..a7b111f59ed7 100644
--- a/test/CodeCompletion/objc-message.m
+++ b/test/CodeCompletion/objc-message.m
@@ -24,12 +24,12 @@ void func() {
[obj xx];
}
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: categoryClassMethod : 0
-// CHECK-CC1: classMethod1:withKeyword: : 0
-// CHECK-CC1: classMethod2 : 0
-// CHECK-CC1: new : 0
-// CHECK-CC1: protocolClassMethod : 0
+// CHECK-CC1: categoryClassMethod
+// CHECK-CC1: classMethod1:withKeyword:
+// CHECK-CC1: classMethod2
+// CHECK-CC1: new
+// CHECK-CC1: protocolClassMethod
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:24:8 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: categoryInstanceMethod : 0
-// CHECK-CC2: instanceMethod1 : 0
-// CHECK-CC2: protocolInstanceMethod : 0
+// CHECK-CC2: categoryInstanceMethod
+// CHECK-CC2: instanceMethod1
+// CHECK-CC2: protocolInstanceMethod
diff --git a/test/CodeCompletion/operator.cpp b/test/CodeCompletion/operator.cpp
index eef7fbd17ba5..05cd7684ad2c 100644
--- a/test/CodeCompletion/operator.cpp
+++ b/test/CodeCompletion/operator.cpp
@@ -9,9 +9,9 @@ void f() {
operator
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: Float : 0
- // CHECK-CC1: + : 0
- // CHECK-CC1: short : 0
- // CHECK-CC1: Integer : 2
- // CHECK-CC1: T : 2
- // CHECK-CC1: N : 6
+ // CHECK-CC1: +
+ // CHECK-CC1: Float
+ // CHECK-CC1: Integer
+ // CHECK-CC1: N
+ // CHECK-CC1: short
+ // CHECK-CC1: T
diff --git a/test/CodeCompletion/ordinary-name.c b/test/CodeCompletion/ordinary-name.c
index 7f5a05ff75aa..1580d01fd315 100644
--- a/test/CodeCompletion/ordinary-name.c
+++ b/test/CodeCompletion/ordinary-name.c
@@ -5,7 +5,6 @@ typedef struct t TYPEDEF;
void foo() {
int y;
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
- // CHECK-CC1: y : 0
- // CHECK-CC1: foo : 2
- // CHECK-NOT-CC1: y : 2
- // CHECK-CC1-NEXT: TYPEDEF : 2
+ // CHECK-CC1: foo
+ // CHECK-CC1: y
+ // CHECK-CC1: TYPEDEF
diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp
new file mode 100644
index 000000000000..d938c79eae33
--- /dev/null
+++ b/test/CodeCompletion/ordinary-name.cpp
@@ -0,0 +1,171 @@
+struct X { int x; };
+void z(int);
+typedef struct t TYPEDEF;
+
+void foo() {
+ int y = 17;
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+ // CHECK-CC1: COMPLETION: bool
+ // CHECK-CC1-NEXT: COMPLETION: char
+ // CHECK-CC1-NEXT: COMPLETION: class
+ // CHECK-CC1-NEXT: COMPLETION: const
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : const_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC1: COMPLETION: Pattern : delete <#expression#>
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : delete[] <#expression#>
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : do{<#statements#>
+ // CHECK-CC1: COMPLETION: double
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : dynamic_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC1-NEXT: COMPLETION: enum
+ // CHECK-CC1-NEXT: COMPLETION: extern
+ // CHECK-CC1-NEXT: COMPLETION: false
+ // CHECK-CC1-NEXT: COMPLETION: float
+ // CHECK-CC1-NEXT: COMPLETION: foo : [#void#]foo()
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){<#statements#>
+ // CHECK-CC1: COMPLETION: Pattern : goto <#identifier#>;
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : if(<#condition#>){<#statements#>
+ // CHECK-CC1: COMPLETION: int
+ // CHECK-CC1-NEXT: COMPLETION: long
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : new <#type-id#>(<#expressions#>)
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : new <#type-id#>[<#size#>](<#expressions#>)
+ // CHECK-CC1-NEXT: COMPLETION: operator
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : reinterpret_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : return;
+ // CHECK-CC1-NEXT: COMPLETION: short
+ // CHECK-CC1-NEXT: COMPLETION: signed
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-CC1-NEXT: COMPLETION: static
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : static_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC1-NEXT: COMPLETION: struct
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : switch(<#condition#>){
+ // CHECK-CC1: COMPLETION: t : t
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : throw <#expression#>
+ // CHECK-CC1-NEXT: COMPLETION: true
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : try{<#statements#>
+ // CHECK-CC1: COMPLETION: TYPEDEF : TYPEDEF
+ // CHECK-CC1-NEXT: COMPLETION: typedef
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : typeid(<#expression-or-type#>)
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : typename <#qualified-id#>
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
+ // CHECK-CC1-NEXT: COMPLETION: union
+ // CHECK-CC1-NEXT: COMPLETION: unsigned
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : using namespace <#identifier#>;
+ // CHECK-CC1-NEXT: COMPLETION: void
+ // CHECK-CC1-NEXT: COMPLETION: volatile
+ // CHECK-CC1-NEXT: COMPLETION: wchar_t
+ // CHECK-CC1-NEXT: COMPLETION: Pattern : while(<#condition#>){<#statements#>
+ // CHECK-CC1: COMPLETION: X : X
+ // CHECK-CC1-NEXT: COMPLETION: y : [#int#]y
+ // CHECK-CC1-NEXT: COMPLETION: z : [#void#]z(<#int#>)
+
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+ // CHECK-CC2: COMPLETION: Pattern : asm(<#string-literal#>);
+ // CHECK-CC2-NEXT: COMPLETION: bool
+ // CHECK-CC2-NEXT: COMPLETION: char
+ // CHECK-CC2-NEXT: COMPLETION: class
+ // CHECK-CC2-NEXT: COMPLETION: const
+ // CHECK-CC2-NEXT: COMPLETION: double
+ // CHECK-CC2-NEXT: COMPLETION: enum
+ // CHECK-CC2-NEXT: COMPLETION: extern
+ // CHECK-CC2-NEXT: COMPLETION: float
+ // CHECK-CC2-NEXT: COMPLETION: inline
+ // CHECK-CC2-NEXT: COMPLETION: int
+ // CHECK-CC2-NEXT: COMPLETION: long
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : namespace <#identifier#>{<#declarations#>
+ // CHECK-CC2: COMPLETION: Pattern : namespace <#identifier#> = <#identifier#>;
+ // CHECK-CC2-NEXT: COMPLETION: operator
+ // CHECK-CC2-NEXT: COMPLETION: short
+ // CHECK-CC2-NEXT: COMPLETION: signed
+ // CHECK-CC2-NEXT: COMPLETION: static
+ // CHECK-CC2-NEXT: COMPLETION: struct
+ // CHECK-CC2-NEXT: COMPLETION: t : t
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : template <#declaration#>;
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : template<<#parameters#>>
+ // CHECK-CC2-NEXT: COMPLETION: TYPEDEF : TYPEDEF
+ // CHECK-CC2-NEXT: COMPLETION: typedef
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : typename <#qualified-id#>
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
+ // CHECK-CC2-NEXT: COMPLETION: union
+ // CHECK-CC2-NEXT: COMPLETION: unsigned
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : using namespace <#identifier#>;
+ // CHECK-CC2-NEXT: COMPLETION: Pattern : using <#qualified-id#>;
+ // CHECK-CC2-NEXT: COMPLETION: void
+ // CHECK-CC2-NEXT: COMPLETION: volatile
+ // CHECK-CC2-NEXT: COMPLETION: wchar_t
+ // CHECK-CC2-NEXT: COMPLETION: X : X
+
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+ // CHECK-CC3: COMPLETION: bool
+ // CHECK-CC3-NEXT: COMPLETION: char
+ // CHECK-CC3-NEXT: COMPLETION: class
+ // CHECK-CC3-NEXT: COMPLETION: const
+ // CHECK-CC3-NEXT: COMPLETION: double
+ // CHECK-CC3-NEXT: COMPLETION: enum
+ // CHECK-CC3-NEXT: COMPLETION: explicit
+ // CHECK-CC3-NEXT: COMPLETION: extern
+ // CHECK-CC3-NEXT: COMPLETION: float
+ // CHECK-CC3-NEXT: COMPLETION: friend
+ // CHECK-CC3-NEXT: COMPLETION: inline
+ // CHECK-CC3-NEXT: COMPLETION: int
+ // CHECK-CC3-NEXT: COMPLETION: long
+ // CHECK-CC3-NEXT: COMPLETION: mutable
+ // CHECK-CC3-NEXT: COMPLETION: operator
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : private:
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : protected:
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : public:
+ // CHECK-CC3-NEXT: COMPLETION: short
+ // CHECK-CC3-NEXT: COMPLETION: signed
+ // CHECK-CC3-NEXT: COMPLETION: static
+ // CHECK-CC3-NEXT: COMPLETION: struct
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : template<<#parameters#>>
+ // CHECK-CC3-NEXT: COMPLETION: typedef
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : typename <#qualified-id#>
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
+ // CHECK-CC3-NEXT: COMPLETION: union
+ // CHECK-CC3-NEXT: COMPLETION: unsigned
+ // CHECK-CC3-NEXT: COMPLETION: Pattern : using <#qualified-id#>;
+ // CHECK-CC3-NEXT: COMPLETION: virtual
+ // CHECK-CC3-NEXT: COMPLETION: void
+ // CHECK-CC3-NEXT: COMPLETION: volatile
+ // CHECK-CC3-NEXT: COMPLETION: wchar_t
+ // CHECK-CC3-NEXT: COMPLETION: X : X
+
+ // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+ // CHECK-CC4: COMPLETION: bool
+ // CHECK-CC4-NEXT: COMPLETION: char
+ // CHECK-CC4-NEXT: COMPLETION: class
+ // CHECK-CC4-NEXT: COMPLETION: const
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : const_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : delete <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : delete[] <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: double
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : dynamic_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC4-NEXT: COMPLETION: enum
+ // CHECK-CC4-NEXT: COMPLETION: false
+ // CHECK-CC4-NEXT: COMPLETION: float
+ // CHECK-CC4-NEXT: COMPLETION: foo : [#void#]foo()
+ // CHECK-CC4-NEXT: COMPLETION: int
+ // CHECK-CC4-NEXT: COMPLETION: long
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : new <#type-id#>(<#expressions#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : new <#type-id#>[<#size#>](<#expressions#>)
+ // CHECK-CC4-NEXT: COMPLETION: operator
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : reinterpret_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC4-NEXT: COMPLETION: short
+ // CHECK-CC4-NEXT: COMPLETION: signed
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : sizeof(<#expression-or-type#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : static_cast<<#type-id#>>(<#expression#>)
+ // CHECK-CC4-NEXT: COMPLETION: struct
+ // CHECK-CC4-NEXT: COMPLETION: t : t
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : throw <#expression#>
+ // CHECK-CC4-NEXT: COMPLETION: true
+ // CHECK-CC4-NEXT: COMPLETION: TYPEDEF : TYPEDEF
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : typeid(<#expression-or-type#>)
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : typename <#qualified-id#>
+ // CHECK-CC4-NEXT: COMPLETION: Pattern : typeof(<#expression-or-type#>)
+ // CHECK-CC4-NEXT: COMPLETION: union
+ // CHECK-CC4-NEXT: COMPLETION: unsigned
+ // CHECK-CC4-NEXT: COMPLETION: void
+ // CHECK-CC4-NEXT: COMPLETION: volatile
+ // CHECK-CC4-NEXT: COMPLETION: wchar_t
+ // CHECK-CC4-NEXT: COMPLETION: X : X
+ // CHECK-CC4-NEXT: COMPLETION: y : [#int#]y
+ // CHECK-CC4-NEXT: COMPLETION: z : [#void#]z(<#int#>)
diff --git a/test/CodeCompletion/tag.c b/test/CodeCompletion/tag.c
index 554d38100b6d..6ad29880666e 100644
--- a/test/CodeCompletion/tag.c
+++ b/test/CodeCompletion/tag.c
@@ -8,5 +8,5 @@ void test() {
enum X { x };
enum
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: X : 0
- // CHECK-CC1: Y : 2
+ // CHECK-CC1: X
+ // CHECK-CC1: Y
diff --git a/test/CodeCompletion/tag.cpp b/test/CodeCompletion/tag.cpp
index 17fb0140a0c9..03fc0fda2ec5 100644
--- a/test/CodeCompletion/tag.cpp
+++ b/test/CodeCompletion/tag.cpp
@@ -16,10 +16,12 @@ namespace N {
void test() {
class
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: Y : 2
- // CHECK-CC1: Z : 2
- // CHECK-CC1: A : 4
- // CHECK-CC1: X : 4
- // CHECK-CC1: Y : 4
- // CHECK-CC1: M : 9 : M::
- // CHECK-CC1: N : 9 : N::
+ // FIXME: the redundant Y is really annoying... it needs qualification to
+ // actually be useful. Here, it just looks redundant :(
+ // CHECK-CC1: A
+ // CHECK-CC1: M : M::
+ // CHECK-CC1: N : N::
+ // CHECK-CC1: X
+ // CHECK-CC1: Y
+ // CHECK-CC1: Y
+ // CHECK-CC1: Z
diff --git a/test/CodeCompletion/truncation.c b/test/CodeCompletion/truncation.c
index c7706354183d..134139d78bdf 100644
--- a/test/CodeCompletion/truncation.c
+++ b/test/CodeCompletion/truncation.c
@@ -3,9 +3,9 @@
struct
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s
-// CHECK-CC1: X : 1
-// CHECK-CC1-NEXT: Y : 1
+// CHECK-CC1: X
+// CHECK-CC1-NEXT: Y
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:3:8 -o - %s | FileCheck -check-prefix=CC2 %s
-// CHECK-CC2: X : 1
-// CHECK-CC2: Xa : 1
-// CHECK-CC2: Y : 1
+// CHECK-CC2: X
+// CHECK-CC2: Xa
+// CHECK-CC2: Y
diff --git a/test/CodeCompletion/using-namespace.cpp b/test/CodeCompletion/using-namespace.cpp
index f8f31d8c1a0d..eb1c2bd50e67 100644
--- a/test/CodeCompletion/using-namespace.cpp
+++ b/test/CodeCompletion/using-namespace.cpp
@@ -13,8 +13,8 @@ namespace N2 {
void foo() {
using namespace
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: I1 : 2
- // CHECK-CC1: I4 : 2
- // CHECK-CC1: I5 : 2
- // CHECK-CC1: N2 : 4
- // CHECK-CC1-NEXT: N4 : 4
+ // CHECK-CC1: I1
+ // CHECK-CC1: I4
+ // CHECK-CC1: I5
+ // CHECK-CC1: N2
+ // CHECK-CC1-NEXT: N4
diff --git a/test/CodeCompletion/using.cpp b/test/CodeCompletion/using.cpp
index ba4c9ce507d5..b84aa26be95b 100644
--- a/test/CodeCompletion/using.cpp
+++ b/test/CodeCompletion/using.cpp
@@ -15,10 +15,10 @@ namespace N2 {
using
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CC1 %s
- // CHECK-CC1: I1 : 2
- // CHECK-CC1: I4 : 2
- // CHECK-CC1: I5 : 2
- // CHECK-CC1: N2 : 4
- // CHECK-CC1: N3 : 4
- // CHECK-CC1-NEXT: N4 : 4
+ // CHECK-CC1: I1
+ // CHECK-CC1: I4
+ // CHECK-CC1: I5
+ // CHECK-CC1: N2
+ // CHECK-CC1: N3
+ // CHECK-CC1-NEXT: N4
diff --git a/test/CodeGen/annotate.c b/test/CodeGen/annotate.c
new file mode 100644
index 000000000000..84d564a61f71
--- /dev/null
+++ b/test/CodeGen/annotate.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+__attribute((annotate("foo"))) char foo;
+void a(char *a) {
+ __attribute__((annotate("bar"))) static char bar;
+}
+
+// CHECK: @llvm.global.annotations = appending global [2 x %0]
diff --git a/test/CodeGen/complex.c b/test/CodeGen/complex.c
index 8d9c68d074ef..ca606109f8b2 100644
--- a/test/CodeGen/complex.c
+++ b/test/CodeGen/complex.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm < %s
+// RUN: %clang_cc1 -emit-llvm-only %s
int main(void)
{
@@ -39,6 +39,25 @@ void test3() {
g1 = D + g1;
}
+__complex__ int ci1, ci2;
+__complex__ short cs;
+int i;
+void test3int() {
+ ci1 = ci1 + ci2;
+ ci1 = ci1 - ci2;
+ ci1 = ci1 * ci2;
+ ci1 = +-~ci1;
+
+ i = __real ci1;
+
+ cs += i;
+ // FIXME: Currently unsupported!
+ //D += cf;
+ cs /= ci1;
+ ci1 = ci1 + i;
+ ci1 = i + ci1;
+}
+
void t1() {
(__real__ cf) = 4.0;
}
@@ -59,3 +78,14 @@ void t5() {
float _Complex x = t4();
}
+void t6() {
+ g1++;
+ g1--;
+ ++g1;
+ --g1;
+ ci1++;
+ ci1--;
+ ++ci1;
+ --ci1;
+}
+
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index 6215323881fc..daa18265a49f 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -emit-llvm-only %s
typedef __attribute__(( ext_vector_type(4) )) float float4;
typedef __attribute__(( ext_vector_type(2) )) float float2;
@@ -151,3 +151,12 @@ int4 test11a();
int test11() {
return test11a().x;
}
+
+int4 test12(int4 V) {
+ V.xyz = V.zyx;
+ return V;
+}
+
+int4 test13(int4 *V) {
+ return V->zyxw;
+}
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index fe12f4a08a52..a96176afe5be 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s -triple i386-unknown-unknown
+// RUN: %clang_cc1 -fmath-errno -emit-llvm -o %t %s -triple i386-unknown-unknown
// RUN: grep "declare " %t | count 6
// RUN: grep "declare " %t | grep "@llvm." | count 1
-// RUN: %clang_cc1 -fno-math-errno -emit-llvm -o %t %s -triple i386-unknown-unknown
+// RUN: %clang_cc1 -emit-llvm -o %t %s -triple i386-unknown-unknown
// RUN: grep "declare " %t | count 6
// RUN: grep "declare " %t | grep -v "@llvm." | count 0
diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c
index 4947c19a5de8..3920ec5934de 100644
--- a/test/CodeGen/object-size.c
+++ b/test/CodeGen/object-size.c
@@ -14,98 +14,108 @@ char *gp;
int gi, gj;
void test1() {
- // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 4), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 59)
+ // CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 4), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 59)
strcpy(&gbuf[4], "Hi there");
}
void test2() {
- // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 63)
+ // CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 63)
strcpy(gbuf, "Hi there");
}
void test3() {
- // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i64 1, i64 37), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
+ // CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i64 1, i64 37), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy(&gbuf[100], "Hi there");
}
void test4() {
- // CHECK: %call = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 -1), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
+ // CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 -1), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy((char*)(void*)&gbuf[-1], "Hi there");
}
void test5() {
- // CHECK: %tmp = load i8** @gp
- // CHECK-NEXT:%0 = call i64 @llvm.objectsize.i64(i8* %tmp, i1 false)
- // CHECK-NEXT:%cmp = icmp ne i64 %0, -1
+ // CHECK: = load i8** @gp
+ // CHECK-NEXT:= call i64 @llvm.objectsize.i64(i8* %{{.*}}, i1 false)
strcpy(gp, "Hi there");
}
void test6() {
char buf[57];
- // CHECK: %call = call i8* @__strcpy_chk(i8* %arrayidx, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 53)
+ // CHECK: = call i8* @__strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 53)
strcpy(&buf[4], "Hi there");
}
void test7() {
int i;
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy((++i, gbuf), "Hi there");
}
void test8() {
char *buf[50];
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(buf[++gi], "Hi there");
}
void test9() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %0, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy((char *)((++gi) + gj), "Hi there");
}
char **p;
void test10() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(*(++p), "Hi there");
}
void test11() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp = gbuf, "Hi there");
}
void test12() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %ptrincdec, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(++gp, "Hi there");
}
void test13() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp++, "Hi there");
}
void test14() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %ptrincdec, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(--gp, "Hi there");
}
void test15() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{..*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp--, "Hi there");
}
void test16() {
// CHECK-NOT: __strcpy_chk
- // CHECK: %call = call i8* @__inline_strcpy_chk(i8* %tmp1, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp += 1, "Hi there");
}
+
+void test17() {
+ // CHECK: store i32 -1
+ gi = __builtin_object_size(gp++, 0);
+ // CHECK: store i32 -1
+ gi = __builtin_object_size(gp++, 1);
+ // CHECK: store i32 0
+ gi = __builtin_object_size(gp++, 2);
+ // CHECK: store i32 0
+ gi = __builtin_object_size(gp++, 3);
+}
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 8fd86414862c..1b214b77bee7 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -15,6 +15,9 @@ class C {
virtual void bar3() __attribute__((aligned(1024)));
} c;
+// CHECK:.align 1, 0x90
+// CHECK-NEXT:.globl __ZN1CC1Ev
+
void C::bar1() { }
// CHECK:.align 1, 0x90
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
index eca07d866bfc..a1b7a09aa347 100644
--- a/test/CodeGenCXX/condition.cpp
+++ b/test/CodeGenCXX/condition.cpp
@@ -39,10 +39,10 @@ void if_destruct(int z) {
// CHECK: call void @_ZN1XC1Ev
if (X x = X())
Y y;
- // CHECK: if.then
+ // CHECK: br
// CHECK: call void @_ZN1YC1Ev
// CHECK: call void @_ZN1YD1Ev
- // CHECK: if.end
+ // CHECK: br
// CHECK: call void @_ZN1XD1Ev
}
@@ -59,12 +59,12 @@ void switch_destruct(int z) {
break;
default:
- // CHECK: sw.default:
+ // CHECK: {{sw.default:|:3}}
// CHECK: store i32 19
z = 19;
break;
}
- // CHECK: sw.epilog:
+ // CHECK: {{sw.epilog:|:4}}
// CHECK: call void @_ZN16ConvertibleToIntD1Ev
// CHECK: store i32 20
z = 20;
@@ -74,18 +74,18 @@ int foo();
void while_destruct(int z) {
// CHECK: define void @_Z14while_destructi
- // CHECK: while.cond:
+ // CHECK: {{while.cond:|:1}}
while (X x = X()) {
// CHECK: call void @_ZN1XC1Ev
- // CHECK: while.body:
+ // CHECK: {{while.body:|:3}}
// CHECK: store i32 21
z = 21;
- // CHECK: while.cleanup:
+ // CHECK: {{while.cleanup:|:4}}
// CHECK: call void @_ZN1XD1Ev
}
- // CHECK: while.end
+ // CHECK: {{while.end|:6}}
// CHECK: store i32 22
z = 22;
}
@@ -94,16 +94,16 @@ 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: {{for.cond:|:1}}
// CHECK: call void @_ZN1XC1Ev
- // CHECK: for.body:
+ // CHECK: {{for.body:|:3}}
// CHECK: store i32 23
z = 23;
- // CHECK: for.inc:
- // CHECK: br label %for.cond.cleanup
- // CHECK: for.cond.cleanup:
+ // CHECK: {{for.inc:|:4}}
+ // CHECK: br label %{{for.cond.cleanup|7}}
+ // CHECK: {{for.cond.cleanup:|:7}}
// CHECK: call void @_ZN1XD1Ev
- // CHECK: for.end:
+ // CHECK: {{for.end:|:9}}
// CHECK: call void @_ZN1YD1Ev
// CHECK: store i32 24
z = 24;
diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp
index a3576fdc72fe..a3f38a6984ac 100644
--- a/test/CodeGenCXX/constructor-template.cpp
+++ b/test/CodeGenCXX/constructor-template.cpp
@@ -44,10 +44,10 @@ int main() {
delete node;
}
-// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC2Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev:
// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev:
-// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC1Ev:
+// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC2Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev:
// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev:
diff --git a/test/CodeGenCXX/copy-assign-synthesis-3.cpp b/test/CodeGenCXX/copy-assign-synthesis-3.cpp
index 0c876d02ec56..73c2261cddc1 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-3.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-3.cpp
@@ -9,6 +9,8 @@ struct B {
float b;
int (A::*c)();
_Complex float d;
+ int e[10];
+ A f[2];
};
void a(B& x, B& y) {
x = y;
diff --git a/test/CodeGenCXX/default-constructor-default-argument.cpp b/test/CodeGenCXX/default-constructor-default-argument.cpp
index 971757d241b4..f2c7f6d12a34 100644
--- a/test/CodeGenCXX/default-constructor-default-argument.cpp
+++ b/test/CodeGenCXX/default-constructor-default-argument.cpp
@@ -5,4 +5,4 @@ struct A { A(int x = 2); };
struct B : public A {};
B x;
-// CHECK: call void @_ZN1AC1Ei
+// CHECK: call void @_ZN1AC2Ei
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
index 098458d35d5c..71167a204fbb 100644
--- a/test/CodeGenCXX/default-destructor-synthesis.cpp
+++ b/test/CodeGenCXX/default-destructor-synthesis.cpp
@@ -45,15 +45,14 @@ M gm;
int main() {M m1;}
-// CHECK-LP64: callq __ZN1MC1Ev
-// CHECK-LP64: callq __ZN1MD1Ev
// CHECK-LP64: .globl __ZN1MD1Ev
// CHECK-LP64-NEXT: .weak_definition __ZN1MD1Ev
// CHECK-LP64-NEXT: __ZN1MD1Ev:
+// CHECK-LP64: callq __ZN1MC1Ev
+// CHECK-LP64: callq __ZN1MD1Ev
-
-// CHECK-LP32: call L__ZN1MC1Ev
-// CHECK-LP32: call L__ZN1MD1Ev
// CHECK-LP32: .globl __ZN1MD1Ev
// CHECK-LP32-NEXT: .weak_definition __ZN1MD1Ev
// CHECK-LP32-NEXT:__ZN1MD1Ev:
+// CHECK-LP32: call L__ZN1MC1Ev
+// CHECK-LP32: call L__ZN1MD1Ev
diff --git a/test/CodeGenCXX/deferred-global-init.cpp b/test/CodeGenCXX/deferred-global-init.cpp
new file mode 100644
index 000000000000..570147905548
--- /dev/null
+++ b/test/CodeGenCXX/deferred-global-init.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// PR5967
+
+extern void* foo;
+static void* const a = foo;
+void* bar() { return a; }
+
+// CHECK: @a = internal global i8* null
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: load i8** @foo
+// CHECK: ret void
+
+// CHECK: define internal void @__cxx_global_initialization
+// CHECK: call void @__cxx_global_var_init()
+// CHECK: ret void
diff --git a/test/CodeGenCXX/delete-two-arg.cpp b/test/CodeGenCXX/delete-two-arg.cpp
index d6bdb098844f..5358747fed7b 100644
--- a/test/CodeGenCXX/delete-two-arg.cpp
+++ b/test/CodeGenCXX/delete-two-arg.cpp
@@ -3,4 +3,4 @@
struct A { void operator delete(void*,__typeof(sizeof(int))); int x; };
void a(A* x) { delete x; }
-// CHECK: call void @_ZN1AdlEPvj(i8* %0, i32 4)
+// CHECK: call void @_ZN1AdlEPvj(i8* %{{.*}}, i32 4)
diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp
index a2d116a89872..054b972bb158 100644
--- a/test/CodeGenCXX/dyncast.cpp
+++ b/test/CodeGenCXX/dyncast.cpp
@@ -59,356 +59,355 @@ void test1() {
}
// CHECK-LL: define void @_Z5test1v() nounwind {
-// CHECK-LL-NEXT:entry:
-// CHECK-LL-NEXT: %bp = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: %ap = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: %dp = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: %ap37 = alloca %class.test1_A*, align 8
-// CHECK-LL-NEXT: %dp53 = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: %ep1 = alloca %class.test1_E*, align 8
-// CHECK-LL-NEXT: %cdp = alloca %class.test1_D*, align 8
-// CHECK-LL-NEXT: %ep = alloca %class.test1_E*, align 8
-// CHECK-LL-NEXT: %vp = alloca i8*, align 8
-// CHECK-LL-NEXT: %cvp = alloca i8*, align 8
-// CHECK-LL-NEXT: br i1 false, label %cast.null, label %cast.notnull
-// CHECK-LL: cast.notnull:
-// CHECK-LL-NEXT: br label %cast.end
-// CHECK-LL: cast.null:
-// CHECK-LL-NEXT: br label %cast.end
-// CHECK-LL: cast.end:
-// CHECK-LL-NEXT: %0 = phi %class.test1_A* [ bitcast (%class.test1_D* @test1_d to %class.test1_A*), %cast.notnull ], [ null, %cast.null ]
-// CHECK-LL-NEXT: store %class.test1_A* %0, %class.test1_A** %bp
-// CHECK-LL-NEXT: br i1 false, label %cast.null2, label %cast.notnull1
-// CHECK-LL: cast.notnull1:
-// CHECK-LL-NEXT: %vtable = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: %vbase.offset.ptr = getelementptr i8* %vtable, i64 -24
-// CHECK-LL-NEXT: %1 = bitcast i8* %vbase.offset.ptr to i64*
-// CHECK-LL-NEXT: %vbase.offset = load i64* %1
-// CHECK-LL-NEXT: %add.ptr = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 %vbase.offset
-// CHECK-LL-NEXT: %2 = bitcast i8* %add.ptr to %class.test1_A*
-// CHECK-LL-NEXT: br label %cast.end3
-// CHECK-LL: cast.null2:
-// CHECK-LL-NEXT: br label %cast.end3
-// CHECK-LL: cast.end3:
-// CHECK-LL-NEXT: %3 = phi %class.test1_A* [ %2, %cast.notnull1 ], [ null, %cast.null2 ]
-// CHECK-LL-NEXT: store %class.test1_A* %3, %class.test1_A** %ap
-// CHECK-LL-NEXT: %tmp = load %class.test1_A** %bp
-// CHECK-LL-NEXT: %4 = icmp ne %class.test1_A* %tmp, null
-// 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 (%0* @_ZTI7test1_B to i8*), i8* bitcast (%1* @_ZTI7test1_D to i8*), i64 -1) ; <i8*> [#uses=1]
-// CHECK-LL-NEXT: %8 = bitcast i8* %7 to %class.test1_D*
-// CHECK-LL-NEXT: br label %10
-// CHECK-LL: ; <label>:9
-// CHECK-LL-NEXT: br label %10
-// CHECK-LL: ; <label>:10
-// CHECK-LL-NEXT: %11 = phi %class.test1_D* [ %8, %5 ], [ null, %9 ]
-// CHECK-LL-NEXT: store %class.test1_D* %11, %class.test1_D** %dp
-// CHECK-LL-NEXT: %tmp4 = load %class.test1_D** %dp
-// CHECK-LL-NEXT: %cmp = icmp eq %class.test1_D* %tmp4, null
-// CHECK-LL-NEXT: br i1 %cmp, label %if.then, label %if.else
-// CHECK-LL: if.then:
-// CHECK-LL-NEXT: %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 1)
-// CHECK-LL-NEXT: br label %if.end
-// CHECK-LL: if.else:
-// CHECK-LL-NEXT: %call5 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 1)
-// CHECK-LL-NEXT: br label %if.end
-// CHECK-LL: if.end:
-// CHECK-LL-NEXT: %tmp6 = load %class.test1_A** %bp
-// CHECK-LL-NEXT: %12 = icmp ne %class.test1_A* %tmp6, null
-// 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 ({{.*}} @_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
-// CHECK-LL-NEXT: br label %18
-// CHECK-LL: ; <label>:18
-// CHECK-LL-NEXT: %19 = phi %class.test1_A* [ %16, %13 ], [ null, %17 ]
-// CHECK-LL-NEXT: store %class.test1_A* %19, %class.test1_A** %ap
-// CHECK-LL-NEXT: %tmp7 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: %cmp8 = icmp eq %class.test1_A* %tmp7, null
-// CHECK-LL-NEXT: br i1 %cmp8, label %if.then9, label %if.else11
-// CHECK-LL: if.then9:
-// CHECK-LL-NEXT: %call10 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 2)
-// CHECK-LL-NEXT: br label %if.end13
-// CHECK-LL: if.else11:
-// CHECK-LL-NEXT: %call12 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 2)
-// CHECK-LL-NEXT: br label %if.end13
-// CHECK-LL: if.end13:
-// CHECK-LL-NEXT: %tmp14 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: %20 = icmp ne %class.test1_A* %tmp14, null
-// 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({{.*}} %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
-// CHECK-LL-NEXT: br label %26
-// CHECK-LL: ; <label>:26
-// CHECK-LL-NEXT: %27 = phi %class.test1_A* [ %24, %21 ], [ null, %25 ]
-// CHECK-LL-NEXT: store %class.test1_A* %27, %class.test1_A** %bp
-// CHECK-LL-NEXT: %tmp15 = load %class.test1_A** %bp
-// CHECK-LL-NEXT: %cmp16 = icmp eq %class.test1_A* %tmp15, null
-// CHECK-LL-NEXT: br i1 %cmp16, label %if.then17, label %if.else19
-// CHECK-LL: if.then17:
-// CHECK-LL-NEXT: %call18 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 3)
-// CHECK-LL-NEXT: br label %if.end21
-// CHECK-LL: if.else19:
-// CHECK-LL-NEXT: %call20 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 3)
-// CHECK-LL-NEXT: br label %if.end21
-// CHECK-LL: if.end21:
-// CHECK-LL-NEXT: br i1 false, label %cast.null27, label %cast.notnull22
-// CHECK-LL: cast.notnull22:
-// CHECK-LL-NEXT: %vtable23 = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: %vbase.offset.ptr24 = getelementptr i8* %vtable23, i64 -24
-// CHECK-LL-NEXT: %28 = bitcast i8* %vbase.offset.ptr24 to i64*
-// CHECK-LL-NEXT: %vbase.offset25 = load i64* %28
-// CHECK-LL-NEXT: %add.ptr26 = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 %vbase.offset25
-// CHECK-LL-NEXT: %29 = bitcast i8* %add.ptr26 to %class.test1_A*
-// CHECK-LL-NEXT: br label %cast.end28
-// CHECK-LL: cast.null27:
-// CHECK-LL-NEXT: br label %cast.end28
-// CHECK-LL: cast.end28:
-// CHECK-LL-NEXT: %30 = phi %class.test1_A* [ %29, %cast.notnull22 ], [ null, %cast.null27 ]
-// CHECK-LL-NEXT: store %class.test1_A* %30, %class.test1_A** %ap
-// CHECK-LL-NEXT: %tmp29 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: %cmp30 = icmp ne %class.test1_A* %tmp29, null
-// CHECK-LL-NEXT: br i1 %cmp30, label %if.then31, label %if.else33
-// CHECK-LL: if.then31:
-// CHECK-LL-NEXT: %call32 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 4)
-// CHECK-LL-NEXT: br label %if.end35
-// CHECK-LL: if.else33:
-// CHECK-LL-NEXT: %call34 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 4)
-// CHECK-LL-NEXT: br label %if.end35
-// CHECK-LL: if.end35:
-// CHECK-LL-NEXT: br i1 false, label %cast.null43, label %cast.notnull38
-// CHECK-LL: cast.notnull38:
-// CHECK-LL-NEXT: %vtable39 = load i8** bitcast (%class.test1_F* @test1_f to i8**)
-// CHECK-LL-NEXT: %vbase.offset.ptr40 = getelementptr i8* %vtable39, i64 -24
-// CHECK-LL-NEXT: %31 = bitcast i8* %vbase.offset.ptr40 to i64*
-// CHECK-LL-NEXT: %vbase.offset41 = load i64* %31
-// CHECK-LL-NEXT: %add.ptr42 = getelementptr i8* getelementptr inbounds (%class.test1_F* @test1_f, i32 0, i32 0, i32 0), i64 %vbase.offset41
-// CHECK-LL-NEXT: %32 = bitcast i8* %add.ptr42 to %class.test1_A*
-// CHECK-LL-NEXT: br label %cast.end44
-// CHECK-LL: cast.null43:
-// CHECK-LL-NEXT: br label %cast.end44
-// CHECK-LL: cast.end44:
-// CHECK-LL-NEXT: %33 = phi %class.test1_A* [ %32, %cast.notnull38 ], [ null, %cast.null43 ]
-// CHECK-LL-NEXT: store %class.test1_A* %33, %class.test1_A** %ap37
-// CHECK-LL-NEXT: %tmp45 = load %class.test1_A** %ap37
-// CHECK-LL-NEXT: %cmp46 = icmp ne %class.test1_A* %tmp45, null
-// CHECK-LL-NEXT: br i1 %cmp46, label %if.then47, label %if.else49
-// CHECK-LL: if.then47:
-// CHECK-LL-NEXT: %call48 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 6)
-// CHECK-LL-NEXT: br label %if.end51
-// CHECK-LL: if.else49:
-// CHECK-LL-NEXT: %call50 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 6)
-// CHECK-LL-NEXT: br label %if.end51
-// CHECK-LL: if.end51:
-// CHECK-LL-NEXT: %tmp54 = load %class.test1_A** %ap37
-// CHECK-LL-NEXT: %34 = icmp ne %class.test1_A* %tmp54, null
-// 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 ({{.*}} @_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
-// CHECK-LL-NEXT: br label %40
-// CHECK-LL: ; <label>:40
-// CHECK-LL-NEXT: %41 = phi %class.test1_D* [ %38, %35 ], [ null, %39 ]
-// CHECK-LL-NEXT: store %class.test1_D* %41, %class.test1_D** %dp53
-// CHECK-LL-NEXT: %tmp55 = load %class.test1_D** %dp53
-// CHECK-LL-NEXT: %cmp56 = icmp eq %class.test1_D* %tmp55, null
-// CHECK-LL-NEXT: br i1 %cmp56, label %if.then57, label %if.else59
-// CHECK-LL: if.then57:
-// CHECK-LL-NEXT: %call58 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 7)
-// CHECK-LL-NEXT: br label %if.end61
-// CHECK-LL: if.else59:
-// CHECK-LL-NEXT: %call60 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 7)
-// CHECK-LL-NEXT: br label %if.end61
-// CHECK-LL: if.end61:
-// CHECK-LL-NEXT: %tmp63 = load %class.test1_A** %ap37
-// CHECK-LL-NEXT: %42 = icmp ne %class.test1_A* %tmp63, null
-// 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 ({{.*}} @_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
-// CHECK-LL-NEXT: br label %48
-// CHECK-LL: ; <label>:48
-// CHECK-LL-NEXT: %49 = phi %class.test1_E* [ %46, %43 ], [ null, %47 ]
-// CHECK-LL-NEXT: store %class.test1_E* %49, %class.test1_E** %ep1
-// CHECK-LL-NEXT: %tmp64 = load %class.test1_E** %ep1
-// CHECK-LL-NEXT: %cmp65 = icmp ne %class.test1_E* %tmp64, null
-// CHECK-LL-NEXT: br i1 %cmp65, label %if.then66, label %if.else68
-// CHECK-LL: if.then66:
-// CHECK-LL-NEXT: %call67 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 8)
-// CHECK-LL-NEXT: br label %if.end70
-// CHECK-LL: if.else68:
-// CHECK-LL-NEXT: %call69 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 8)
-// CHECK-LL-NEXT: br label %if.end70
-// CHECK-LL: if.end70:
-// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** %dp
-// CHECK-LL-NEXT: %tmp71 = load %class.test1_D** %dp
-// CHECK-LL-NEXT: %cmp72 = icmp eq %class.test1_D* %tmp71, @test1_d
-// CHECK-LL-NEXT: br i1 %cmp72, label %if.then73, label %if.else75
-// CHECK-LL: if.then73:
-// CHECK-LL-NEXT: %call74 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 9)
-// CHECK-LL-NEXT: br label %if.end77
-// CHECK-LL: if.else75:
-// CHECK-LL-NEXT: %call76 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 9)
-// CHECK-LL-NEXT: br label %if.end77
-// CHECK-LL: if.end77:
-// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** %cdp
-// CHECK-LL-NEXT: %tmp79 = load %class.test1_D** %cdp
-// CHECK-LL-NEXT: %cmp80 = icmp eq %class.test1_D* %tmp79, @test1_d
-// CHECK-LL-NEXT: br i1 %cmp80, label %if.then81, label %if.else83
-// CHECK-LL: if.then81:
-// CHECK-LL-NEXT: %call82 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 10)
-// CHECK-LL-NEXT: br label %if.end85
-// CHECK-LL: if.else83:
-// CHECK-LL-NEXT: %call84 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 10)
-// CHECK-LL-NEXT: br label %if.end85
-// 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 ({{.*}}* @_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
-// CHECK-LL-NEXT: br label %54
-// CHECK-LL: ; <label>:54
-// CHECK-LL-NEXT: %55 = phi %class.test1_D* [ %52, %50 ], [ null, %53 ]
-// CHECK-LL-NEXT: store %class.test1_D* %55, %class.test1_D** %dp
-// CHECK-LL-NEXT: %tmp86 = load %class.test1_D** %dp
-// CHECK-LL-NEXT: %cmp87 = icmp eq %class.test1_D* %tmp86, null
-// CHECK-LL-NEXT: br i1 %cmp87, label %if.then88, label %if.else90
-// CHECK-LL: if.then88:
-// CHECK-LL-NEXT: %call89 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 11)
-// CHECK-LL-NEXT: br label %if.end92
-// CHECK-LL: if.else90:
-// CHECK-LL-NEXT: %call91 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 11)
-// CHECK-LL-NEXT: br label %if.end92
-// CHECK-LL: if.end92:
-// CHECK-LL-NEXT: br i1 false, label %cast.null98, label %cast.notnull93
-// CHECK-LL: cast.notnull93:
-// CHECK-LL-NEXT: %vtable94 = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: %vbase.offset.ptr95 = getelementptr i8* %vtable94, i64 -24
-// CHECK-LL-NEXT: %56 = bitcast i8* %vbase.offset.ptr95 to i64*
-// CHECK-LL-NEXT: %vbase.offset96 = load i64* %56
-// CHECK-LL-NEXT: %add.ptr97 = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 %vbase.offset96
-// CHECK-LL-NEXT: %57 = bitcast i8* %add.ptr97 to %class.test1_A*
-// CHECK-LL-NEXT: br label %cast.end99
-// CHECK-LL: cast.null98:
-// CHECK-LL-NEXT: br label %cast.end99
-// CHECK-LL: cast.end99:
-// CHECK-LL-NEXT: %58 = phi %class.test1_A* [ %57, %cast.notnull93 ], [ null, %cast.null98 ]
-// CHECK-LL-NEXT: store %class.test1_A* %58, %class.test1_A** %ap
-// CHECK-LL-NEXT: %tmp100 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: br i1 false, label %cast.null106, label %cast.notnull101
-// CHECK-LL: cast.notnull101:
-// CHECK-LL-NEXT: %vtable102 = load i8** bitcast (%class.test1_D* @test1_d to i8**)
-// CHECK-LL-NEXT: %vbase.offset.ptr103 = getelementptr i8* %vtable102, i64 -24
-// CHECK-LL-NEXT: %59 = bitcast i8* %vbase.offset.ptr103 to i64*
-// CHECK-LL-NEXT: %vbase.offset104 = load i64* %59
-// CHECK-LL-NEXT: %add.ptr105 = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 %vbase.offset104
-// CHECK-LL-NEXT: %60 = bitcast i8* %add.ptr105 to %class.test1_A*
-// CHECK-LL-NEXT: br label %cast.end107
-// CHECK-LL: cast.null106:
-// CHECK-LL-NEXT: br label %cast.end107
-// CHECK-LL: cast.end107:
-// CHECK-LL-NEXT: %61 = phi %class.test1_A* [ %60, %cast.notnull101 ], [ null, %cast.null106 ]
-// CHECK-LL-NEXT: %cmp108 = icmp eq %class.test1_A* %tmp100, %61
-// CHECK-LL-NEXT: br i1 %cmp108, label %if.then109, label %if.else111
-// CHECK-LL: if.then109:
-// CHECK-LL-NEXT: %call110 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 12)
-// CHECK-LL-NEXT: br label %if.end113
-// CHECK-LL: if.else111:
-// CHECK-LL-NEXT: %call112 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 12)
-// CHECK-LL-NEXT: br label %if.end113
-// CHECK-LL: if.end113:
-// CHECK-LL-NEXT: br i1 false, label %cast.null116, label %cast.notnull115
-// CHECK-LL: cast.notnull115:
-// CHECK-LL-NEXT: br label %cast.end117
-// CHECK-LL: cast.null116:
-// CHECK-LL-NEXT: br label %cast.end117
-// CHECK-LL: cast.end117:
-// CHECK-LL-NEXT: %62 = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %cast.notnull115 ], [ null, %cast.null116 ]
-// CHECK-LL-NEXT: store %class.test1_E* %62, %class.test1_E** %ep
-// CHECK-LL-NEXT: %tmp118 = load %class.test1_E** %ep
-// CHECK-LL-NEXT: br i1 false, label %cast.null120, label %cast.notnull119
-// CHECK-LL: cast.notnull119:
-// CHECK-LL-NEXT: br label %cast.end121
-// CHECK-LL: cast.null120:
-// CHECK-LL-NEXT: br label %cast.end121
-// CHECK-LL: cast.end121:
-// CHECK-LL-NEXT: %63 = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %cast.notnull119 ], [ null, %cast.null120 ]
-// CHECK-LL-NEXT: %cmp122 = icmp eq %class.test1_E* %tmp118, %63
-// CHECK-LL-NEXT: br i1 %cmp122, label %if.then123, label %if.else125
-// CHECK-LL: if.then123:
-// CHECK-LL-NEXT: %call124 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 13)
-// CHECK-LL-NEXT: br label %if.end127
-// CHECK-LL: if.else125:
-// CHECK-LL-NEXT: %call126 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 13)
-// CHECK-LL-NEXT: br label %if.end127
-// CHECK-LL: if.end127:
-// CHECK-LL-NEXT: %tmp129 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: %64 = icmp ne %class.test1_A* %tmp129, null
-// CHECK-LL-NEXT: br i1 %64, label %65, label %70
-// CHECK-LL: ; <label>:65
-// CHECK-LL-NEXT: %66 = bitcast %class.test1_A* %tmp129 to i64**
-// CHECK-LL-NEXT: %vtable130 = load i64** %66
-// CHECK-LL-NEXT: %67 = getelementptr inbounds i64* %vtable130, i64 -2
-// CHECK-LL-NEXT: %"offset to top" = load i64* %67
-// CHECK-LL-NEXT: %68 = bitcast %class.test1_A* %tmp129 to i8*
-// CHECK-LL-NEXT: %69 = getelementptr inbounds i8* %68, i64 %"offset to top"
-// CHECK-LL-NEXT: br label %71
-// CHECK-LL: ; <label>:70
-// CHECK-LL-NEXT: br label %71
-// CHECK-LL: ; <label>:71
-// CHECK-LL-NEXT: %72 = phi i8* [ %69, %65 ], [ null, %70 ]
-// CHECK-LL-NEXT: store i8* %72, i8** %vp
-// CHECK-LL-NEXT: %tmp131 = load i8** %vp
-// CHECK-LL-NEXT: %cmp132 = icmp eq i8* %tmp131, getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
-// CHECK-LL-NEXT: br i1 %cmp132, label %if.then133, label %if.else135
-// CHECK-LL: if.then133:
-// CHECK-LL-NEXT: %call134 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 14)
-// CHECK-LL-NEXT: br label %if.end137
-// CHECK-LL: if.else135:
-// CHECK-LL-NEXT: %call136 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 14)
-// CHECK-LL-NEXT: br label %if.end137
-// CHECK-LL: if.end137:
-// CHECK-LL-NEXT: %tmp139 = load %class.test1_A** %ap
-// CHECK-LL-NEXT: %73 = icmp ne %class.test1_A* %tmp139, null
-// CHECK-LL-NEXT: br i1 %73, label %74, label %79
-// CHECK-LL: ; <label>:74
-// CHECK-LL-NEXT: %75 = bitcast %class.test1_A* %tmp139 to i64**
-// CHECK-LL-NEXT: %vtable140 = load i64** %75
-// CHECK-LL-NEXT: %76 = getelementptr inbounds i64* %vtable140, i64 -2
-// CHECK-LL-NEXT: %"offset to top141" = load i64* %76
-// CHECK-LL-NEXT: %77 = bitcast %class.test1_A* %tmp139 to i8*
-// CHECK-LL-NEXT: %78 = getelementptr inbounds i8* %77, i64 %"offset to top141"
-// CHECK-LL-NEXT: br label %80
-// CHECK-LL: ; <label>:79
-// CHECK-LL-NEXT: br label %80
-// CHECK-LL: ; <label>:80
-// CHECK-LL-NEXT: %81 = phi i8* [ %78, %74 ], [ null, %79 ]
-// CHECK-LL-NEXT: store i8* %81, i8** %cvp
-// CHECK-LL-NEXT: %tmp142 = load i8** %cvp
-// CHECK-LL-NEXT: %cmp143 = icmp eq i8* %tmp142, getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
-// CHECK-LL-NEXT: br i1 %cmp143, label %if.then144, label %if.else146
-// CHECK-LL: if.then144:
-// CHECK-LL-NEXT: %call145 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 15)
-// CHECK-LL-NEXT: br label %if.end148
-// CHECK-LL: if.else146:
-// CHECK-LL-NEXT: %call147 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 15)
-// CHECK-LL-NEXT: br label %if.end148
-// CHECK-LL: if.end148:
+// CHECK-LL: [[bp:%.*]] = alloca %class.test1_A*, align 8
+// CHECK-LL-NEXT: [[ap:%.*]] = alloca %class.test1_A*, align 8
+// CHECK-LL-NEXT: [[dp:%.*]] = alloca %class.test1_D*, align 8
+// CHECK-LL-NEXT: [[ap37:%.*]] = alloca %class.test1_A*, align 8
+// CHECK-LL-NEXT: [[dp53:%.*]] = alloca %class.test1_D*, align 8
+// CHECK-LL-NEXT: [[ep1:%.*]] = alloca %class.test1_E*, align 8
+// CHECK-LL-NEXT: [[cdp:%.*]] = alloca %class.test1_D*, align 8
+// CHECK-LL-NEXT: [[ep:%.*]] = alloca %class.test1_E*, align 8
+// CHECK-LL-NEXT: [[vp:%.*]] = alloca i8*, align 8
+// CHECK-LL-NEXT: [[cvp:%.*]] = alloca i8*, align 8
+// CHECK-LL-NEXT: br i1 false, label %[[castnull:.*]], label %[[castnotnull:.*]]
+// CHECK-LL: [[castnotnull]]
+// CHECK-LL-NEXT: br label %[[castend:.*]]
+// CHECK-LL: [[castnull]]
+// CHECK-LL-NEXT: br label %[[castend]]
+// CHECK-LL: [[castend]]
+// CHECK-LL-NEXT: [[v0:%.*]] = phi %class.test1_A* [ bitcast (%class.test1_D* @test1_d to %class.test1_A*), %[[castnotnull]] ], [ null, %[[castnull]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v0]], %class.test1_A** [[bp]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull2:.*]], label %[[castnotnull1:.*]]
+// CHECK-LL: [[castnotnull1]]
+// CHECK-LL-NEXT: [[vtable:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
+// CHECK-LL-NEXT: [[vbaseoffsetptr:%.*]] = getelementptr i8* [[vtable]], i64 -24
+// CHECK-LL-NEXT: [[v1:%.*]] = bitcast i8* [[vbaseoffsetptr]] to i64*
+// CHECK-LL-NEXT: [[vbaseoffset:%.*]] = load i64* [[v1]]
+// CHECK-LL-NEXT: [[addptr:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset:.*]]
+// CHECK-LL-NEXT: [[v2:%.*]] = bitcast i8* [[addptr]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[castend3:.*]]
+// CHECK-LL: [[castnull2]]
+// CHECK-LL-NEXT: br label %[[castend3]]
+// CHECK-LL: [[castend3]]
+// CHECK-LL-NEXT: [[v3:%.*]] = phi %class.test1_A* [ [[v2]], %[[castnotnull1]] ], [ null, %[[castnull2]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v3]], %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[tmp:%.*]] = load %class.test1_A** [[bp]]
+// CHECK-LL-NEXT: [[v4:%.*]] = icmp ne %class.test1_A* [[tmp]], null
+// CHECK-LL-NEXT: br i1 [[v4]], label %[[v5:.*]], label %[[v9:.*]]
+// CHECK-LL: ; <label>:[[v5]]
+// CHECK-LL-NEXT: [[v6:%.*]] = bitcast %class.test1_A* [[tmp]] to i8*
+// CHECK-LL-NEXT: [[v7:%.*]] = call i8* @__dynamic_cast(i8* [[v6]], i8* bitcast (%0* @_ZTI7test1_B to i8*), i8* bitcast (%1* @_ZTI7test1_D to i8*), i64 -1) ; <i8*> [#uses=1]
+// CHECK-LL-NEXT: [[v8:%.*]] = bitcast i8* [[v7]] to %class.test1_D*
+// CHECK-LL-NEXT: br label %[[v10:.*]]
+// CHECK-LL: ; <label>:[[v9]]
+// CHECK-LL-NEXT: br label %[[v10]]
+// CHECK-LL: ; <label>:[[v10]]
+// CHECK-LL-NEXT: [[v11:%.*]] = phi %class.test1_D* [ [[v8]], %[[v5]] ], [ null, %[[v9]] ]
+// CHECK-LL-NEXT: store %class.test1_D* [[v11]], %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[tmp4:%.*]] = load %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[cmp:%.*]] = icmp eq %class.test1_D* [[tmp4]], null
+// CHECK-LL-NEXT: br i1 [[cmp]], label %[[ifthen:.*]], label %[[ifelse:.*]]
+// CHECK-LL: [[ifthen]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 1)
+// CHECK-LL-NEXT: br label %[[ifend:.*]]
+// CHECK-LL: [[ifelse]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 1)
+// CHECK-LL-NEXT: br label %[[ifend]]
+// CHECK-LL: [[ifend]]
+// CHECK-LL-NEXT: [[tmp6:%.*]] = load %class.test1_A** [[bp]]
+// CHECK-LL-NEXT: [[v12:%.*]] = icmp ne %class.test1_A* [[tmp6]], null
+// CHECK-LL-NEXT: br i1 [[v12]], label %[[v13:.*]], label %[[v17:.*]]
+// CHECK-LL: ; <label>:[[v13]]
+// CHECK-LL-NEXT: [[v14:%.*]] = bitcast %class.test1_A* [[tmp6]] to i8*
+// CHECK-LL-NEXT: [[v15:%.*]] = call i8* @__dynamic_cast(i8* [[v14]], i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i64 -1)
+// CHECK-LL-NEXT: [[v16:%.*]] = bitcast i8* [[v15]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[v18:.*]]
+// CHECK-LL: ; <label>:[[v17]]
+// CHECK-LL-NEXT: br label %[[v18]]
+// CHECK-LL: ; <label>:[[v18]]
+// CHECK-LL-NEXT: [[v19:%.*]] = phi %class.test1_A* [ [[v16]], %[[v13]] ], [ null, %[[v17]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v19]], %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[tmp7:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[cmp8:%.*]] = icmp eq %class.test1_A* [[tmp7]], null
+// CHECK-LL-NEXT: br i1 [[cmp8]], label %[[ifthen9:.*]], label %[[ifelse11:.*]]
+// CHECK-LL: [[ifthen9]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 2)
+// CHECK-LL-NEXT: br label %[[ifend13:.*]]
+// CHECK-LL: [[ifelse11]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 2)
+// CHECK-LL-NEXT: br label %[[ifend13]]
+// CHECK-LL: [[ifend13]]
+// CHECK-LL-NEXT: [[tmp14:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[v20:%.*]] = icmp ne %class.test1_A* [[tmp14]], null
+// CHECK-LL-NEXT: br i1 [[v20]], label %[[v21:.*]], label %[[v25:.*]]
+// CHECK-LL: ; <label>:[[v21]]
+// CHECK-LL-NEXT: [[v22:%.*]] = bitcast %class.test1_A* [[tmp14]] to i8*
+// CHECK-LL-NEXT: [[v23:%.*]] = call i8* @__dynamic_cast({{.*}} [[v22]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_B to i8*), i64 -1)
+// CHECK-LL-NEXT: [[v24:%.*]] = bitcast i8* [[v23]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[v26:.*]]
+// CHECK-LL: ; <label>:[[v25]]
+// CHECK-LL-NEXT: br label %[[v26]]
+// CHECK-LL: ; <label>:[[v26]]
+// CHECK-LL-NEXT: [[v27:%.*]] = phi %class.test1_A* [ [[v24]], %[[v21]] ], [ null, %[[v25]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v27]], %class.test1_A** [[bp]]
+// CHECK-LL-NEXT: [[tmp15:%.*]] = load %class.test1_A** [[bp]]
+// CHECK-LL-NEXT: [[cmp16:%.*]] = icmp eq %class.test1_A* [[tmp15]], null
+// CHECK-LL-NEXT: br i1 [[cmp16]], label %[[ifthen17:.*]], label %[[ifelse19:.*]]
+// CHECK-LL: [[ifthen17]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 3)
+// CHECK-LL-NEXT: br label %[[ifend21:.*]]
+// CHECK-LL: [[ifelse19]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 3)
+// CHECK-LL-NEXT: br label %[[ifend21]]
+// CHECK-LL: [[ifend21]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull27:.*]], label %[[castnotnull22:.*]]
+// CHECK-LL: [[castnotnull22]]
+// CHECK-LL-NEXT: [[vtable23:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
+// CHECK-LL-NEXT: [[vbaseoffsetptr24:%.*]] = getelementptr i8* [[vtable23]], i64 -24
+// CHECK-LL-NEXT: [[v28:%.*]] = bitcast i8* [[vbaseoffsetptr24]] to i64*
+// CHECK-LL-NEXT: [[vbaseoffset25:%.*]] = load i64* [[v28]]
+// CHECK-LL-NEXT: [[addptr26:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset25]]
+// CHECK-LL-NEXT: [[v29:%.*]] = bitcast i8* [[addptr26]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[castend28:.*]]
+// CHECK-LL: [[castnull27]]
+// CHECK-LL-NEXT: br label %[[castend28]]
+// CHECK-LL: [[castend28]]
+// CHECK-LL-NEXT: [[v30:%.*]] = phi %class.test1_A* [ [[v29]], %[[castnotnull22]] ], [ null, %[[castnull27]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v30]], %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[tmp29:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[cmp30:%.*]] = icmp ne %class.test1_A* [[tmp29]], null
+// CHECK-LL-NEXT: br i1 [[cmp30]], label %[[ifthen31:.*]], label %[[ifelse33:.*]]
+// CHECK-LL: [[ifthen31]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 4)
+// CHECK-LL-NEXT: br label %[[ifend35:.*]]
+// CHECK-LL: [[ifelse33]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 4)
+// CHECK-LL-NEXT: br label %[[ifend35]]
+// CHECK-LL: [[ifend35]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull43:.*]], label %[[castnotnull38:.*]]
+// CHECK-LL: [[castnotnull38]]
+// CHECK-LL-NEXT: [[vtable39:%.*]] = load i8** bitcast (%class.test1_F* @test1_f to i8**)
+// CHECK-LL-NEXT: [[vbaseoffsetptr40:%.*]] = getelementptr i8* [[vtable39]], i64 -24
+// CHECK-LL-NEXT: [[v31:%.*]] = bitcast i8* [[vbaseoffsetptr40]] to i64*
+// CHECK-LL-NEXT: [[vbaseoffset41:%.*]] = load i64* [[v31]]
+// CHECK-LL-NEXT: [[addptr42:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_F* @test1_f, i32 0, i32 0, i32 0), i64 [[vbaseoffset41]]
+// CHECK-LL-NEXT: [[v32:%.*]] = bitcast i8* [[addptr42]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[castend44:.*]]
+// CHECK-LL: [[castnull43]]
+// CHECK-LL-NEXT: br label %[[castend44]]
+// CHECK-LL: [[castend44]]
+// CHECK-LL-NEXT: [[v33:%.*]] = phi %class.test1_A* [ [[v32]], %[[castnotnull38]] ], [ null, %[[castnull43]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v33]], %class.test1_A** [[ap37]]
+// CHECK-LL-NEXT: [[tmp45:%.*]] = load %class.test1_A** [[ap37]]
+// CHECK-LL-NEXT: [[cmp46:%.*]] = icmp ne %class.test1_A* [[tmp45]], null
+// CHECK-LL-NEXT: br i1 [[cmp46]], label %[[ifthen47:.*]], label %[[ifelse49:.*]]
+// CHECK-LL: [[ifthen47]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 6)
+// CHECK-LL-NEXT: br label %[[ifend51:.*]]
+// CHECK-LL: [[ifelse49]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 6)
+// CHECK-LL-NEXT: br label %[[ifend51]]
+// CHECK-LL: [[ifend51]]
+// CHECK-LL-NEXT: [[tmp54:%.*]] = load %class.test1_A** [[ap37]]
+// CHECK-LL-NEXT: [[v34:%.*]] = icmp ne %class.test1_A* [[tmp54]], null
+// CHECK-LL-NEXT: br i1 [[v34]], label %[[v35:.*]], label %[[v39:.*]]
+// CHECK-LL: ; <label>:[[v35]]
+// CHECK-LL-NEXT: [[v36:%.*]] = bitcast %class.test1_A* [[tmp54]] to i8*
+// CHECK-LL-NEXT: [[v37:%.*]] = call i8* @__dynamic_cast(i8* [[v36]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
+// CHECK-LL-NEXT: [[v38:%.*]] = bitcast i8* [[v37]] to %class.test1_D*
+// CHECK-LL-NEXT: br label %[[v40:.*]]
+// CHECK-LL: ; <label>:[[v39]]
+// CHECK-LL-NEXT: br label %[[v40]]
+// CHECK-LL: ; <label>:[[v40]]
+// CHECK-LL-NEXT: [[v41:%.*]] = phi %class.test1_D* [ [[v38]], %[[v35]] ], [ null, %[[v39]] ]
+// CHECK-LL-NEXT: store %class.test1_D* [[v41]], %class.test1_D** [[dp53]]
+// CHECK-LL-NEXT: [[tmp55:%.*]] = load %class.test1_D** [[dp53]]
+// CHECK-LL-NEXT: [[cmp56:%.*]] = icmp eq %class.test1_D* [[tmp55]], null
+// CHECK-LL-NEXT: br i1 [[cmp56]], label %[[ifthen57:.*]], label %[[ifelse59:.*]]
+// CHECK-LL: [[ifthen57]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 7)
+// CHECK-LL-NEXT: br label %[[ifend61:.*]]
+// CHECK-LL: [[ifelse59]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 7)
+// CHECK-LL-NEXT: br label %[[ifend61]]
+// CHECK-LL: [[ifend61]]
+// CHECK-LL-NEXT: [[tmp63:%.*]] = load %class.test1_A** [[ap37]]
+// CHECK-LL-NEXT: [[v42:%.*]] = icmp ne %class.test1_A* [[tmp63]], null
+// CHECK-LL-NEXT: br i1 [[v42]], label %[[v43:.*]], label %[[v47:.*]]
+// CHECK-LL: ; <label>:[[v43]]
+// CHECK-LL-NEXT: [[v44:%.*]] = bitcast %class.test1_A* [[tmp63]] to i8*
+// CHECK-LL-NEXT: [[v45:%.*]] = call i8* @__dynamic_cast(i8* [[v44]], i8* bitcast ({{.*}} @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_E to i8*), i64 -1)
+// CHECK-LL-NEXT: [[v46:%.*]] = bitcast i8* [[v45]] to %class.test1_E*
+// CHECK-LL-NEXT: br label %[[v48:.*]]
+// CHECK-LL: ; <label>:[[v47]]
+// CHECK-LL-NEXT: br label %[[v48]]
+// CHECK-LL: ; <label>:[[v48]]
+// CHECK-LL-NEXT: [[v49:%.*]] = phi %class.test1_E* [ [[v46]], %[[v43]] ], [ null, %[[v47]] ]
+// CHECK-LL-NEXT: store %class.test1_E* [[v49]], %class.test1_E** [[ep1]]
+// CHECK-LL-NEXT: [[tmp64:%.*]] = load %class.test1_E** [[ep1]]
+// CHECK-LL-NEXT: [[cmp65:%.*]] = icmp ne %class.test1_E* [[tmp64]], null
+// CHECK-LL-NEXT: br i1 [[cmp65]], label %[[ifthen66:.*]], label %[[ifelse68:.*]]
+// CHECK-LL: [[ifthen66]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 8)
+// CHECK-LL-NEXT: br label %[[ifend70:.*]]
+// CHECK-LL: [[ifelse68]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 8)
+// CHECK-LL-NEXT: br label %[[ifend70]]
+// CHECK-LL: [[ifend70]]
+// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[tmp71:%.*]] = load %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[cmp72:%.*]] = icmp eq %class.test1_D* [[tmp71]], @test1_d
+// CHECK-LL-NEXT: br i1 [[cmp72]], label %[[ifthen73:.*]], label %[[ifelse75:.*]]
+// CHECK-LL: [[ifthen73]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 9)
+// CHECK-LL-NEXT: br label %[[ifend77:.*]]
+// CHECK-LL: [[ifelse75]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 9)
+// CHECK-LL-NEXT: br label %[[ifend77]]
+// CHECK-LL: [[ifend77]]
+// CHECK-LL-NEXT: store %class.test1_D* @test1_d, %class.test1_D** [[cdp]]
+// CHECK-LL-NEXT: [[tmp79:%.*]] = load %class.test1_D** [[cdp]]
+// CHECK-LL-NEXT: [[cmp80:%.*]] = icmp eq %class.test1_D* [[tmp79]], @test1_d
+// CHECK-LL-NEXT: br i1 [[cmp80]], label %[[ifthen81:.*]], label %[[ifelse83:.*]]
+// CHECK-LL: [[ifthen81]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 10)
+// CHECK-LL-NEXT: br label %[[ifend85:.*]]
+// CHECK-LL: [[ifelse83]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 10)
+// CHECK-LL-NEXT: br label %[[ifend85]]
+// CHECK-LL: [[ifend85]]
+// CHECK-LL-NEXT: br i1 false, label %[[v50:.*]], label %[[v53:.*]]
+// CHECK-LL: ; <label>:[[v50]]
+// CHECK-LL-NEXT: [[v51:%.*]] = call i8* @__dynamic_cast(i8* null, i8* bitcast ({{.*}}* @_ZTI7test1_A to i8*), i8* bitcast ({{.*}} @_ZTI7test1_D to i8*), i64 -1)
+// CHECK-LL-NEXT: [[v52:%.*]] = bitcast i8* [[v51]] to %class.test1_D*
+// CHECK-LL-NEXT: br label %[[v54:.*]]
+// CHECK-LL: ; <label>:[[v53]]
+// CHECK-LL-NEXT: br label %[[v54]]
+// CHECK-LL: ; <label>:[[v54]]
+// CHECK-LL-NEXT: [[v55:%.*]] = phi %class.test1_D* [ [[v52]], %[[v50]] ], [ null, %[[v53]] ]
+// CHECK-LL-NEXT: store %class.test1_D* [[v55]], %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[tmp86:%.*]] = load %class.test1_D** [[dp]]
+// CHECK-LL-NEXT: [[cmp87:%.*]] = icmp eq %class.test1_D* [[tmp86]], null
+// CHECK-LL-NEXT: br i1 [[cmp87]], label %[[ifthen88:.*]], label %[[ifelse90:.*]]
+// CHECK-LL: [[ifthen88]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 11)
+// CHECK-LL-NEXT: br label %[[ifend92:.*]]
+// CHECK-LL: [[ifelse90]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 11)
+// CHECK-LL-NEXT: br label %[[ifend92]]
+// CHECK-LL: [[ifend92]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull98:.*]], label %[[castnotnull93:.*]]
+// CHECK-LL: [[castnotnull93]]
+// CHECK-LL-NEXT: [[vtable94:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
+// CHECK-LL-NEXT: [[vbaseoffsetptr95:%.*]] = getelementptr i8* [[vtable94]], i64 -24
+// CHECK-LL-NEXT: [[v56:%.*]] = bitcast i8* [[vbaseoffsetptr95]] to i64*
+// CHECK-LL-NEXT: [[vbaseoffset96:%.*]] = load i64* [[v56]]
+// CHECK-LL-NEXT: [[addptr97:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset96]]
+// CHECK-LL-NEXT: [[v57:%.*]] = bitcast i8* [[addptr97]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[castend99:.*]]
+// CHECK-LL: [[castnull98]]
+// CHECK-LL-NEXT: br label %[[castend99]]
+// CHECK-LL: [[castend99]]
+// CHECK-LL-NEXT: [[v58:%.*]] = phi %class.test1_A* [ [[v57]], %[[castnotnull93]] ], [ null, %[[castnull98]] ]
+// CHECK-LL-NEXT: store %class.test1_A* [[v58]], %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[tmp100:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull106:.*]], label %[[castnotnull101:.*]]
+// CHECK-LL: [[castnotnull101]]
+// CHECK-LL-NEXT: [[vtable102:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**)
+// CHECK-LL-NEXT: [[vbaseoffsetptr103:%.*]] = getelementptr i8* [[vtable102]], i64 -24
+// CHECK-LL-NEXT: [[v59:%.*]] = bitcast i8* [[vbaseoffsetptr103]] to i64*
+// CHECK-LL-NEXT: [[vbaseoffset104:%.*]] = load i64* [[v59]]
+// CHECK-LL-NEXT: [[addptr105:%.*]] = getelementptr i8* getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0), i64 [[vbaseoffset104]]
+// CHECK-LL-NEXT: [[v60:%.*]] = bitcast i8* [[addptr105]] to %class.test1_A*
+// CHECK-LL-NEXT: br label %[[castend107:.*]]
+// CHECK-LL: [[castnull106]]
+// CHECK-LL-NEXT: br label %[[castend107]]
+// CHECK-LL: [[castend107]]
+// CHECK-LL-NEXT: [[v61:%.*]] = phi %class.test1_A* [ [[v60]], %[[castnotnull101]] ], [ null, %[[castnull106]] ]
+// CHECK-LL-NEXT: [[cmp108:%.*]] = icmp eq %class.test1_A* [[tmp100]], [[v61]]
+// CHECK-LL-NEXT: br i1 [[cmp108]], label %[[ifthen109:.*]], label %[[ifelse111:.*]]
+// CHECK-LL: [[ifthen109]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 12)
+// CHECK-LL-NEXT: br label %[[ifend113:.*]]
+// CHECK-LL: [[ifelse111]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 12)
+// CHECK-LL-NEXT: br label %[[ifend113]]
+// CHECK-LL: [[ifend113]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull116:.*]], label %[[castnotnull115:.*]]
+// CHECK-LL: [[castnotnull115]]
+// CHECK-LL-NEXT: br label %[[castend117:.*]]
+// CHECK-LL: [[castnull116]]
+// CHECK-LL-NEXT: br label %[[castend117]]
+// CHECK-LL: [[castend117]]
+// CHECK-LL-NEXT: [[v62:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull115]] ], [ null, %[[castnull116]] ]
+// CHECK-LL-NEXT: store %class.test1_E* [[v62]], %class.test1_E** [[ep]]
+// CHECK-LL-NEXT: [[tmp118:%.*]] = load %class.test1_E** [[ep]]
+// CHECK-LL-NEXT: br i1 false, label %[[castnull120:.*]], label %[[castnotnull119:.*]]
+// CHECK-LL: [[castnotnull119]]
+// CHECK-LL-NEXT: br label %[[castend121:.*]]
+// CHECK-LL: [[castnull120]]
+// CHECK-LL-NEXT: br label %[[castend121]]
+// CHECK-LL: [[castend121]]
+// CHECK-LL-NEXT: [[v63:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull119]] ], [ null, %[[castnull120]] ]
+// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], [[v63]]
+// CHECK-LL-NEXT: br i1 [[cmp122]], label %[[ifthen123:.*]], label %[[ifelse125:.*]]
+// CHECK-LL: [[ifthen123]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 13)
+// CHECK-LL-NEXT: br label %[[ifend127:.*]]
+// CHECK-LL: [[ifelse125]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 13)
+// CHECK-LL-NEXT: br label %[[ifend127]]
+// CHECK-LL: [[ifend127]]
+// CHECK-LL-NEXT: [[tmp129:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[v64:%.*]] = icmp ne %class.test1_A* [[tmp129]], null
+// CHECK-LL-NEXT: br i1 [[v64]], label %[[v65:.*]], label %[[v70:.*]]
+// CHECK-LL: ; <label>:[[v65]]
+// CHECK-LL-NEXT: [[v66:%.*]] = bitcast %class.test1_A* [[tmp129]] to i64**
+// CHECK-LL-NEXT: [[vtable130:%.*]] = load i64** [[v66]]
+// CHECK-LL-NEXT: [[v67:%.*]] = getelementptr inbounds i64* [[vtable130]], i64 -2
+// CHECK-LL-NEXT: [[offsettotop:%.*]] = load i64* [[v67]]
+// CHECK-LL-NEXT: [[v68:%.*]] = bitcast %class.test1_A* [[tmp129]] to i8*
+// CHECK-LL-NEXT: [[v69:%.*]] = getelementptr inbounds i8* [[v68]], i64 [[offsettotop]]
+// CHECK-LL-NEXT: br label %[[v71:.*]]
+// CHECK-LL: ; <label>:[[v70]]
+// CHECK-LL-NEXT: br label %[[v71]]
+// CHECK-LL: ; <label>:[[v71]]
+// CHECK-LL-NEXT: [[v72:%.*]] = phi i8* [ [[v69]], %[[v65]] ], [ null, %[[v70]] ]
+// CHECK-LL-NEXT: store i8* [[v72]], i8** [[vp]]
+// CHECK-LL-NEXT: [[tmp131:%.*]] = load i8** [[vp]]
+// CHECK-LL-NEXT: [[cmp132:%.*]] = icmp eq i8* [[tmp131]], getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
+// CHECK-LL-NEXT: br i1 [[cmp132]], label %[[ifthen133:.*]], label %[[ifelse135:.*]]
+// CHECK-LL: [[ifthen133]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 14)
+// CHECK-LL-NEXT: br label %[[ifend137:.*]]
+// CHECK-LL: [[ifelse135]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 14)
+// CHECK-LL-NEXT: br label %[[ifend137]]
+// CHECK-LL: [[ifend137]]
+// CHECK-LL-NEXT: [[tmp139:%.*]] = load %class.test1_A** [[ap]]
+// CHECK-LL-NEXT: [[v73:%.*]] = icmp ne %class.test1_A* [[tmp139]], null
+// CHECK-LL-NEXT: br i1 [[v73]], label %[[v74:.*]], label %[[v79:.*]]
+// CHECK-LL: ; <label>:[[v74]]
+// CHECK-LL-NEXT: [[v75:%.*]] = bitcast %class.test1_A* [[tmp139]] to i64**
+// CHECK-LL-NEXT: [[vtable140:%.*]] = load i64** [[v75]]
+// CHECK-LL-NEXT: [[v76:%.*]] = getelementptr inbounds i64* [[vtable140]], i64 -2
+// CHECK-LL-NEXT: [[offsettotop141:%.*]] = load i64* [[v76]]
+// CHECK-LL-NEXT: [[v77:%.*]] = bitcast %class.test1_A* [[tmp139]] to i8*
+// CHECK-LL-NEXT: [[v78:%.*]] = getelementptr inbounds i8* [[v77]], i64 [[offsettotop141]]
+// CHECK-LL-NEXT: br label %[[v80:.*]]
+// CHECK-LL: ; <label>:[[v79]]
+// CHECK-LL-NEXT: br label %[[v80]]
+// CHECK-LL: ; <label>:[[v80]]
+// CHECK-LL-NEXT: [[v81:%.*]] = phi i8* [ [[v78]], %[[v74]] ], [ null, %[[v79]] ]
+// CHECK-LL-NEXT: store i8* [[v81]], i8** [[cvp]]
+// CHECK-LL-NEXT: [[tmp142:%.*]] = load i8** [[cvp]]
+// CHECK-LL-NEXT: [[cmp143:%.*]] = icmp eq i8* [[tmp142]], getelementptr inbounds (%class.test1_D* @test1_d, i32 0, i32 0, i32 0)
+// CHECK-LL-NEXT: br i1 [[cmp143]], label %[[ifthen144:.*]], label %[[ifelse146:.*]]
+// CHECK-LL: [[ifthen144]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 15)
+// CHECK-LL-NEXT: br label %[[ifend148:.*]]
+// CHECK-LL: [[ifelse146]]
+// CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 15)
+// CHECK-LL-NEXT: br label %[[ifend148]]
+// CHECK-LL: [[ifend148]]
// CHECK-LL-NEXT: ret void
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index dd798f4ca32e..d233525f0a48 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -10,14 +10,13 @@ void test1() {
}
// CHECK: define void @_Z5test1v() nounwind {
-// CHECK-NEXT:entry:
-// CHECK-NEXT: %exception.ptr = alloca i8*
-// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* %exception, i8** %exception.ptr
-// 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: %{{exception.ptr|1}} = alloca i8*
+// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{exception.ptr|1}}
+// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test1_D*
+// CHECK-NEXT: %{{tmp|4}} = bitcast %struct.test1_D* %{{0|3}} to i8*
+// CHECK-NEXT: call void @llvm.memcpy.i64(i8* %{{tmp|4}}, i8* bitcast (%struct.test1_D* @d1 to i8*), i64 8, i32 8)
+// CHECK-NEXT: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -33,14 +32,13 @@ void test2() {
}
// CHECK: define void @_Z5test2v() nounwind {
-// CHECK-NEXT:entry:
-// CHECK-NEXT: %exception.ptr = alloca i8*
-// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 16)
-// CHECK-NEXT: store i8* %exception, i8** %exception.ptr
-// CHECK-NEXT: %0 = bitcast i8* %exception to %struct.test2_D*
-// CHECK: invoke void @_ZN7test2_DC1ERKS_(%struct.test2_D* %0, %struct.test2_D* @d2)
-// CHECK-NEXT: to label %invoke.cont unwind label %terminate.handler
-// CHECK: call void @__cxa_throw(i8* %exception, i8* bitcast (%0* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK: %{{exception.ptr|1}} = alloca i8*
+// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 16)
+// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{\1}}
+// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test2_D*
+// CHECK: invoke void @_ZN7test2_DC1ERKS_(%struct.test2_D* %{{0|3}}, %struct.test2_D* @d2)
+// CHECK-NEXT: to label %{{invoke.cont|8}} unwind label %{{terminate.handler|4}}
+// CHECK: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%{{0|3}}* @_ZTI7test2_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -55,13 +53,12 @@ void test3() {
}
// CHECK: define void @_Z5test3v() nounwind {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: %exception.ptr = alloca i8*
-// CHECK-NEXT: %exception = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* %exception, i8** %exception.ptr
-// 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: %{{exception.ptr|1}} = alloca i8*
+// CHECK-NEXT: %{{exception|2}} = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: store i8* %{{exception|2}}, i8** %{{exception.ptr|1}}
+// CHECK-NEXT: %{{0|3}} = bitcast i8* %{{exception|2}} to %struct.test3_D**
+// CHECK-NEXT: store %struct.test3_D* null, %struct.test3_D**
+// CHECK-NEXT: call void @__cxa_throw(i8* %{{exception|2}}, i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -70,6 +67,5 @@ void test4() {
}
// CHECK: define void @_Z5test4v() nounwind {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: call void @__cxa_rethrow() noreturn
+// CHECK: call void @__cxa_rethrow() noreturn
// CHECK-NEXT: unreachable
diff --git a/test/CodeGenCXX/expr.cpp b/test/CodeGenCXX/expr.cpp
index 6d641dcb622d..d92cfb46a454 100644
--- a/test/CodeGenCXX/expr.cpp
+++ b/test/CodeGenCXX/expr.cpp
@@ -10,3 +10,7 @@ void test1() {
char *xpto;
while ( true && xpto[0] );
}
+
+// PR5514
+int a;
+void test2() { ++a+=10; }
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index e8770dfec3e8..5947587eec32 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -308,4 +308,9 @@ template class Alloc<char>;
}
// CHECK: define void @_Z1fU13block_pointerFiiiE
-void f(int (^)(int, int)) { } \ No newline at end of file
+void f(int (^)(int, int)) { }
+
+// PR5869
+// CHECK: define internal void @_ZL2f2v
+static void f2() {}
+void f3() { f2(); }
diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp
index 149b5603ad7c..2454ddab774a 100644
--- a/test/CodeGenCXX/member-function-pointers.cpp
+++ b/test/CodeGenCXX/member-function-pointers.cpp
@@ -128,3 +128,14 @@ namespace BoolMemberPointer {
}
}
+// PR5940
+namespace PR5940 {
+ class foo {
+ public:
+ virtual void baz(void);
+ };
+
+ void foo::baz(void) {
+ void (foo::*ptr)(void) = &foo::baz;
+ }
+}
diff --git a/test/CodeGenCXX/reference-init.cpp b/test/CodeGenCXX/reference-init.cpp
index 1bfb28a66a03..6c2c6a301681 100644
--- a/test/CodeGenCXX/reference-init.cpp
+++ b/test/CodeGenCXX/reference-init.cpp
@@ -7,3 +7,10 @@ struct nsXPTParamInfo {
void a(XPTParamDescriptor *params) {
const nsXPTParamInfo& paramInfo = params[0];
}
+
+// CodeGen of reference initialized const arrays.
+namespace PR5911 {
+ template <typename T, int N> int f(const T (&a)[N]) { return N; }
+ int iarr[] = { 1 };
+ int test() { return f(iarr); }
+}
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index 259fd03e7aff..f7f4c9f15c8f 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -153,7 +153,7 @@ void test12_foo() {
// CHECK-LPLL64: call void %
// CHECK-LPLL64: call void %
// CHECK-LPLL64: call void %
-// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %tmp11)
+// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}})
struct test6_B2 { virtual void funcB2(); char b[1000]; };
@@ -769,55 +769,53 @@ struct test16_D : test16_NV1, virtual test16_B2 {
// FIXME: This is the wrong thunk, but until these issues are fixed, better
// than nothing.
// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
-// CHECK-LPLL64:entry:
-// CHECK-LPLL64: %retval = alloca %class.test8_D*
+// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D*
// CHECK-LPLL64: %.addr = alloca %class.test8_D*
// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr
-// CHECK-LPLL64: %this = load %class.test8_D** %.addr
-// CHECK-LPLL64: %1 = bitcast %class.test8_D* %this to i8*
-// CHECK-LPLL64: %2 = getelementptr inbounds i8* %1, i64 -16
-// CHECK-LPLL64: %3 = bitcast i8* %2 to %class.test8_D*
-// CHECK-LPLL64: %4 = bitcast %class.test8_D* %3 to i8*
-// CHECK-LPLL64: %5 = bitcast %class.test8_D* %3 to i64**
-// CHECK-LPLL64: %vtable = load i64** %5
-// CHECK-LPLL64: %6 = getelementptr inbounds i64* %vtable, i64 -9
-// CHECK-LPLL64: %7 = load i64* %6
-// CHECK-LPLL64: %8 = getelementptr i8* %4, i64 %7
-// CHECK-LPLL64: %9 = bitcast i8* %8 to %class.test8_D*
-// CHECK-LPLL64: %call = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %9)
-// CHECK-LPLL64: store %class.test8_D* %call, %class.test8_D** %retval
-// CHECK-LPLL64: %10 = load %class.test8_D** %retval
-// CHECK-LPLL64: ret %class.test8_D* %10
+// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr
+// CHECK-LPLL64: %{{1|4}} = bitcast %class.test8_D* %{{this|3}} to i8*
+// CHECK-LPLL64: %{{2|5}} = getelementptr inbounds i8* %{{1|4}}, i64 -16
+// CHECK-LPLL64: %{{3|6}} = bitcast i8* %{{2|5}} to %class.test8_D*
+// CHECK-LPLL64: %{{4|7}} = bitcast %class.test8_D* %{{3|6}} to i8*
+// CHECK-LPLL64: %{{5|8}} = bitcast %class.test8_D* %3 to i64**
+// CHECK-LPLL64: %{{vtable|9}} = load i64** %{{5|8}}
+// CHECK-LPLL64: %{{6|10}} = getelementptr inbounds i64* %{{vtable|9}}, i64 -9
+// CHECK-LPLL64: %{{7|11}} = load i64* %{{6|10}}
+// CHECK-LPLL64: %{{8|12}} = getelementptr i8* %{{4|7}}, i64 %{{7|11}}
+// CHECK-LPLL64: %{{9|13}} = bitcast i8* %{{8|12}} to %class.test8_D*
+// CHECK-LPLL64: %{{call|14}} = call %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D* %{{9|13}})
+// CHECK-LPLL64: store %class.test8_D* %{{call|14}}, %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64: %{{10|15}} = load %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64: ret %class.test8_D* %{{10|15}}
// CHECK-LPLL64:}
-// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*)
-// CHECK-LPLL64:entry:
-// CHECK-LPLL64: %retval = alloca %class.test8_D*
+// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%{{class.test8_D|.*}}*)
+// CHECK-LPLL64: %{{retval|2}} = alloca %class.test8_D*
// CHECK-LPLL64: %.addr = alloca %class.test8_D*
// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %.addr
-// CHECK-LPLL64: %this = load %class.test8_D** %.addr
-// CHECK-LPLL64: %call = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %this)
-// CHECK-LPLL64: %1 = icmp ne %class.test8_D* %call, null
-// CHECK-LPLL64: br i1 %1, label %2, label %12
-// CHECK-LPLL64:; <label>:2
-// CHECK-LPLL64: %3 = bitcast %class.test8_D* %call to i8*
-// CHECK-LPLL64: %4 = getelementptr inbounds i8* %3, i64 16
-// CHECK-LPLL64: %5 = bitcast i8* %4 to %class.test8_D*
-// CHECK-LPLL64: %6 = bitcast %class.test8_D* %5 to i8*
-// CHECK-LPLL64: %7 = bitcast %class.test8_D* %5 to i64**
-// CHECK-LPLL64: %vtable = load i64** %7
-// CHECK-LPLL64: %8 = getelementptr inbounds i64* %vtable, i64 -4
-// CHECK-LPLL64: %9 = load i64* %8
-// CHECK-LPLL64: %10 = getelementptr i8* %6, i64 %9
-// CHECK-LPLL64: %11 = bitcast i8* %10 to %class.test8_D*
-// CHECK-LPLL64: br label %13
-// CHECK-LPLL64:; <label>:12
-// CHECK-LPLL64: br label %13
-// CHECK-LPLL64:; <label>:13
-// CHECK-LPLL64: %14 = phi %class.test8_D* [ %11, %2 ], [ %call, %12 ]
-// CHECK-LPLL64: store %class.test8_D* %14, %class.test8_D** %retval
-// CHECK-LPLL64: %15 = load %class.test8_D** %retval
-// CHECK-LPLL64: ret %class.test8_D* %15
+// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %.addr
+// CHECK-LPLL64: %{{call|4}} = call %class.test8_D* @_ZN8test16_D4foo1Ev(%class.test8_D* %{{this|3}})
+// CHECK-LPLL64: %{{1|5}} = icmp ne %class.test8_D* %{{call|4}}, null
+// CHECK-LPLL64: br i1 %{{1|5}}, label %{{2|6}}, label %{{12|17}}
+// CHECK-LPLL64:; <label>:{{2|6}}
+// CHECK-LPLL64: %{{3|7}} = bitcast %class.test8_D* %{{call|4}} to i8*
+// CHECK-LPLL64: %{{4|8}} = getelementptr inbounds i8* %{{3|7}}, i64 16
+// CHECK-LPLL64: %{{5|9}} = bitcast i8* %4 to %class.test8_D*
+// CHECK-LPLL64: %{{6|10}} = bitcast %class.test8_D* %{{5|9}} to i8*
+// CHECK-LPLL64: %{{7|11}} = bitcast %class.test8_D* %{{5|9}} to i64**
+// CHECK-LPLL64: %{{vtable|12}} = load i64** %{{7|11}}
+// CHECK-LPLL64: %{{8|13}} = getelementptr inbounds i64* %vtable, i64 -4
+// CHECK-LPLL64: %{{9|14}} = load i64* %{{8|13}}
+// CHECK-LPLL64: %{{10|15}} = getelementptr i8* %{{6|10}}, i64 %{{9|14}}
+// CHECK-LPLL64: %{{11|16}} = bitcast i8* %{{10|15}} to %class.test8_D*
+// CHECK-LPLL64: br label %{{13|18}}
+// CHECK-LPLL64:; <label>:{{12|17}}
+// CHECK-LPLL64: br label %{{13|18}}
+// CHECK-LPLL64:; <label>:{{13|18}}
+// CHECK-LPLL64: %{{14|19}} = phi %class.test8_D* [ %{{11|16}}, %{{2|6}} ], [ %{{call|4}}, %{{12|17}} ]
+// CHECK-LPLL64: store %class.test8_D* %{{14|19}}, %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64: %{{15|20}} = load %class.test8_D** %{{retval|2}}
+// CHECK-LPLL64: ret %class.test8_D* %{{15|20}}
// CHECK-LPLL64:}
diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp
index ecfcad232029..01ca1442f2c4 100644
--- a/test/CodeGenCXX/virtual-destructor-calls.cpp
+++ b/test/CodeGenCXX/virtual-destructor-calls.cpp
@@ -8,15 +8,15 @@ struct B : A {
virtual ~B();
};
+// Complete dtor.
+// CHECK: define void @_ZN1BD1Ev
+// CHECK: call void @_ZN1AD2Ev
+
// Deleting dtor.
// CHECK: define void @_ZN1BD0Ev
// CHECK: call void @_ZN1AD2Ev
// check: call void @_ZdlPv
-// Complete dtor.
-// CHECK: define void @_ZN1BD1Ev
-// CHECK: call void @_ZN1AD2Ev
-
// Base dtor.
// CHECK: define void @_ZN1BD2Ev
// CHECK: call void @_ZN1AD2Ev
diff --git a/test/CodeGenCXX/vtable-key-function.cpp b/test/CodeGenCXX/vtable-key-function.cpp
index 90e8ea66f769..97a546f8c932 100644
--- a/test/CodeGenCXX/vtable-key-function.cpp
+++ b/test/CodeGenCXX/vtable-key-function.cpp
@@ -13,3 +13,21 @@ struct A {
A::A() { }
A::A(int) { }
}
+
+// Make sure that we don't assert when building the vtable for a class
+// template specialization or explicit instantiation with a key
+// function.
+template<typename T>
+struct Base {
+ virtual ~Base();
+};
+
+template<typename T>
+struct Derived : public Base<T> { };
+
+template<>
+struct Derived<char> : public Base<char> {
+ virtual void anchor();
+};
+
+void Derived<char>::anchor() { }
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index 6d3cf240096b..63e17431c467 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -30,6 +30,55 @@ void D::f() { }
static struct : D { } e;
+// The destructor is the key function.
+template<typename T>
+struct E {
+ virtual ~E();
+};
+
+template<typename T> E<T>::~E() { }
+
+// Anchor is the key function
+template<>
+struct E<char> {
+ virtual void anchor();
+};
+
+void E<char>::anchor() { }
+
+template struct E<short>;
+extern template struct E<int>;
+
+void use_E() {
+ E<int> ei;
+ (void)ei;
+ E<long> el;
+ (void)el;
+}
+
+// No key function
+template<typename T>
+struct F {
+ virtual void foo() { }
+};
+
+// No key function
+template<>
+struct F<char> {
+ virtual void foo() { }
+};
+
+template struct F<short>;
+extern template struct F<int>;
+
+void use_F(F<char> &fc) {
+ F<int> fi;
+ (void)fi;
+ F<long> fl;
+ (void)fl;
+ fc.foo();
+}
+
// B has a key function that is not defined in this translation unit so its vtable
// has external linkage.
// CHECK: @_ZTV1B = external constant
@@ -45,6 +94,50 @@ static struct : D { } e;
// CHECK: @_ZTI1D = constant
// CHECK: @_ZTV1D = constant
+// E<char> is an explicit specialization with a key function defined
+// in this translation unit, so its vtable should have external
+// linkage.
+// CHECK: @_ZTS1EIcE = constant
+// CHECK: @_ZTI1EIcE = constant
+// CHECK: @_ZTV1EIcE = constant
+
+// E<short> is an explicit template instantiation with a key function
+// defined in this translation unit, so its vtable should have
+// weak_odr linkage.
+// CHECK: @_ZTS1EIsE = weak_odr constant
+// CHECK: @_ZTI1EIsE = weak_odr constant
+// CHECK: @_ZTV1EIsE = weak_odr constant
+
+// F<short> is an explicit template instantiation without a key
+// function, so its vtable should have weak_odr linkage
+// CHECK: @_ZTS1FIsE = weak_odr constant
+// CHECK: @_ZTI1FIsE = weak_odr constant
+// CHECK: @_ZTV1FIsE = weak_odr constant
+
+// E<long> is an implicit template instantiation with a key function
+// defined in this translation unit, so its vtable should have
+// weak_odr linkage.
+// CHECK: @_ZTS1EIlE = weak_odr constant
+// CHECK: @_ZTI1EIlE = weak_odr constant
+// CHECK: @_ZTV1EIlE = weak_odr constant
+
+// F<long> is an implicit template instantiation with no key function,
+// so its vtable should have weak_odr linkage.
+// CHECK: @_ZTS1FIlE = weak_odr constant
+// CHECK: @_ZTI1FIlE = weak_odr constant
+// CHECK: @_ZTV1FIlE = weak_odr constant
+
+// F<int> is an explicit template instantiation declaration without a
+// key function, so its vtable should have weak_odr linkage.
+// CHECK: @_ZTS1FIiE = weak_odr constant
+// CHECK: @_ZTI1FIiE = weak_odr constant
+// CHECK: @_ZTV1FIiE = weak_odr constant
+
+// E<int> is an explicit template instantiation declaration. It has a
+// key function that is not instantiated, so we should only reference
+// its vtable, not define it.
+// CHECK: @_ZTV1EIiE = external constant
+
// The anonymous struct for e has no linkage, so the vtable should have
// internal linkage.
// CHECK: @"_ZTS3$_0" = internal constant
@@ -56,3 +149,5 @@ static struct : D { } e;
// CHECK: @_ZTSN12_GLOBAL__N_11AE = internal constant
// CHECK: @_ZTIN12_GLOBAL__N_11AE = internal constant
// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant
+
+
diff --git a/test/Coverage/ast-printing.c b/test/Coverage/ast-printing.c
index 182bd4d1b25a..bbbc366eb711 100644
--- a/test/Coverage/ast-printing.c
+++ b/test/Coverage/ast-printing.c
@@ -2,5 +2,6 @@
// RUN: %clang_cc1 -ast-print %s
// RUN: %clang_cc1 -ast-dump %s
// RUN: %clang_cc1 -ast-print-xml -o %t %s
+// RUN: %clang_cc1 -print-decl-contexts %s
#include "c-language-features.inc"
diff --git a/test/Coverage/ast-printing.cpp b/test/Coverage/ast-printing.cpp
index e86e799a8f6e..ce0a5693b046 100644
--- a/test/Coverage/ast-printing.cpp
+++ b/test/Coverage/ast-printing.cpp
@@ -2,5 +2,7 @@
// RUN: %clang_cc1 -ast-print %s
// RUN: %clang_cc1 -ast-dump %s
// FIXME: %clang_cc1 -ast-print-xml -o %t %s
+// RUN: %clang_cc1 -print-decl-contexts %s
+// RUN: %clang_cc1 -dump-record-layouts %s
#include "cxx-language-features.inc"
diff --git a/test/Coverage/c-language-features.inc b/test/Coverage/c-language-features.inc
index bcf4127299f0..3548132500f9 100644
--- a/test/Coverage/c-language-features.inc
+++ b/test/Coverage/c-language-features.inc
@@ -179,3 +179,12 @@ void f8(x)
// Function which inputs an array
void f9(int x[]) { }
+
+// Object literals.
+void f10() {
+ struct f10_s0 {
+ char iv0[10];
+ } x;
+
+ x = (struct f10_s0) { .iv0 = "name" };
+}
diff --git a/test/Driver/analyze.c b/test/Driver/analyze.c
index 2f850bc73dde..359b0e005b25 100644
--- a/test/Driver/analyze.c
+++ b/test/Driver/analyze.c
@@ -6,4 +6,3 @@
// CHECK: "-analyze"
// CHECK: "-target-feature" "+sse"
-// CHECK: "-fno-math-errno"
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index c4ea430fdf31..f1d67597777a 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -1,11 +1,11 @@
-// RUN: %clang -### -S -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
-// RUN: %clang -### -S -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fno-math-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -S -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
// RUN: %clang -### -fshort-enums %s 2>&1 | FileCheck -check-prefix=CHECK-SHORT-ENUMS %s
// CHECK-OPTIONS1: -fblocks
// CHECK-OPTIONS1: -fpascal-strings
-// CHECK-OPTIONS2: -fno-math-errno
+// CHECK-OPTIONS2: -fmath-errno
// CHECK-OPTIONS2: -fno-builtin
// CHECK-OPTIONS2: -fshort-wchar
// CHECK-OPTIONS2: -fno-common
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 07775517809f..72e3d658e7b6 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -1,17 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x c -
+// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x c -
struct Point {
float x, y;
};
struct Rectangle {
- struct Point top_left, bottom_right;
+ struct Point top_left, // expected-note{{'top_left' declared here}}
+ bottom_right;
};
enum Color { Red, Green, Blue };
struct Window {
- struct Rectangle bounds;
+ struct Rectangle bounds; // expected-note{{'bounds' declared here}}
enum Color color;
};
diff --git a/test/FixIt/typo.cpp b/test/FixIt/typo.cpp
index 12bfc712f3ee..c0570258c53b 100644
--- a/test/FixIt/typo.cpp
+++ b/test/FixIt/typo.cpp
@@ -1,15 +1,15 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ -
+// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ -
namespace std {
- template<typename T> class basic_string {
- int find(const char *substr);
- static const int npos = -1;
+ template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}}
+ int find(const char *substr); // expected-note{{'find' declared here}}
+ static const int npos = -1; // expected-note{{'npos' declared here}}
};
- typedef basic_string<char> string;
+ typedef basic_string<char> string; // expected-note 2{{'string' declared here}}
}
-namespace otherstd {
+namespace otherstd { // expected-note 2{{'otherstd' declared here}}
using namespace std;
}
@@ -21,8 +21,9 @@ tring str2; // expected-error{{unknown type name 'tring'; did you mean 'string'?
::other_std::string str3; // expected-error{{no member named 'other_std' in the global namespace; did you mean 'otherstd'?}}
-float area(float radius, float pi) {
- return radious * pi; // expected-error{{use of undeclared identifier 'radious'; did you mean 'radius'?}}
+float area(float radius, // expected-note{{'radius' declared here}}
+ float pi) {
+ return radious * pi; // expected-error{{did you mean 'radius'?}}
}
bool test_string(std::string s) {
@@ -35,9 +36,19 @@ bool test_string(std::string s) {
}
struct Base { };
-struct Derived : public Base {
- int member;
+struct Derived : public Base { // expected-note{{base class 'struct Base' specified here}}
+ int member; // expected-note 3{{'member' declared here}}
Derived() : base(), // expected-error{{initializer 'base' does not name a non-static data member or base class; did you mean the base class 'Base'?}}
ember() { } // expected-error{{initializer 'ember' does not name a non-static data member or base class; did you mean the member 'member'?}}
+
+ int getMember() const {
+ return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}}
+ }
+
+ int &getMember();
};
+
+int &Derived::getMember() {
+ return ember; // expected-error{{use of undeclared identifier 'ember'; did you mean 'member'?}}
+}
diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m
index 251684949ef2..4c3ee5f60bc8 100644
--- a/test/FixIt/typo.m
+++ b/test/FixIt/typo.m
@@ -1,9 +1,89 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -fixit -o - | %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c -
+// FIXME: the test below isn't testing quite what we want...
+// RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c -
@interface NSString
++ (int)method:(int)x;
@end
void test() {
+ // FIXME: not providing fix-its
NSstring *str = @"A string"; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}}
}
+
+@protocol P1
+@property int *sprop; // expected-note{{'sprop' declared here}}
+@end
+
+@interface A
+{
+ int his_ivar; // expected-note 2{{'his_ivar' declared here}}
+ float wibble;
+}
+
+@property int his_prop; // expected-note{{'his_prop' declared here}}
+@end
+
+@interface B : A <P1>
+{
+ int her_ivar; // expected-note 2{{'her_ivar' declared here}}
+}
+
+@property int her_prop; // expected-note{{'her_prop' declared here}}
+- (void)inst_method1:(int)a;
++ (void)class_method1;
+@end
+
+@implementation A
+@synthesize his_prop = his_ivar;
+@end
+
+@implementation B
+@synthesize her_prop = her_ivar;
+
+-(void)inst_method1:(int)a {
+ herivar = a; // expected-error{{use of undeclared identifier 'herivar'; did you mean 'her_ivar'?}}
+ hisivar = a; // expected-error{{use of undeclared identifier 'hisivar'; did you mean 'his_ivar'?}}
+ self->herivar = a; // expected-error{{'B' does not have a member named 'herivar'; did you mean 'her_ivar'?}}
+ self->hisivar = a; // expected-error{{'B' does not have a member named 'hisivar'; did you mean 'his_ivar'?}}
+ self.hisprop = 0; // expected-error{{property 'hisprop' not found on object of type 'B *'; did you mean 'his_prop'?}}
+ self.herprop = 0; // expected-error{{property 'herprop' not found on object of type 'B *'; did you mean 'her_prop'?}}
+ self.s_prop = 0; // expected-error{{property 's_prop' not found on object of type 'B *'; did you mean 'sprop'?}}
+}
+
++(void)class_method1 {
+}
+@end
+
+void test_message_send(B* b) {
+ // FIXME: Not providing fix-its
+ [NSstring method:17]; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}}
+}
+
+@interface Collide // expected-note{{'Collide' declared here}}
+{
+@public
+ int value; // expected-note{{'value' declared here}}
+}
+
+@property int value; // expected-note{{'value' declared here}}
+@end
+
+@implementation Collide
+@synthesize value = value;
+@end
+
+void test2(Collide *a) {
+ a.valu = 17; // expected-error{{property 'valu' not found on object of type 'Collide *'; did you mean 'value'?}}
+ a->vale = 17; // expected-error{{'Collide' does not have a member named 'vale'; did you mean 'value'?}}
+}
+
+@interface Derived : Collid // expected-error{{cannot find interface declaration for 'Collid', superclass of 'Derived'; did you mean 'Collide'?}}
+@end
+
+@protocol NetworkSocket // expected-note{{'NetworkSocket' declared here}}
+- (int)send:(void*)buffer bytes:(int)bytes;
+@end
+
+@interface IPv8 <Network_Socket> // expected-error{{cannot find protocol declaration for 'Network_Socket'; did you mean 'NetworkSocket'?}}
+@end
diff --git a/test/Frontend/macros.c b/test/Frontend/macros.c
new file mode 100644
index 000000000000..317079709c63
--- /dev/null
+++ b/test/Frontend/macros.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -DA= -DB=1 -verify -fsyntax-only %s
+
+int a[(B A) == 1 ? 1 : -1];
+
diff --git a/test/Index/TestClassDecl.m b/test/Index/TestClassDecl.m
index 5cccf9264c7f..fb97de15b11a 100644
--- a/test/Index/TestClassDecl.m
+++ b/test/Index/TestClassDecl.m
@@ -19,8 +19,8 @@ void function(Foo * arg)
// CHECK-scan: {start_line=8 start_col=1 end_line=8 end_col=7} Invalid Cursor => NotImplemented
// CHECK-scan: {start_line=8 start_col=8 end_line=8 end_col=10} ObjCClassRef=Foo:8:1
// CHECK-scan: {start_line=8 start_col=11 end_line=9 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK-scan: {start_line=10 start_col=1 end_line=11 end_col=1} ObjCInterfaceDecl=Foo:10:1
-// CHECK-scan: {start_line=11 start_col=2 end_line=12 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK-scan: {start_line=10 start_col=1 end_line=11 end_col=4} ObjCInterfaceDecl=Foo:10:1
+// CHECK-scan: {start_line=11 start_col=5 end_line=12 end_col=1} Invalid Cursor => NoDeclFound
// CHECK-scan: {start_line=13 start_col=1 end_line=13 end_col=4} FunctionDecl=function:13:6
// CHECK-scan: {start_line=13 start_col=5 end_line=13 end_col=5} Invalid Cursor => NoDeclFound
// CHECK-scan: {start_line=13 start_col=6 end_line=13 end_col=14} FunctionDecl=function:13:6
@@ -30,23 +30,9 @@ void function(Foo * arg)
// CHECK-scan: {start_line=13 start_col=20 end_line=13 end_col=20} FunctionDecl=function:13:6
// CHECK-scan: {start_line=13 start_col=21 end_line=13 end_col=23} ParmDecl=arg:13:21
// CHECK-scan: {start_line=13 start_col=24 end_line=16 end_col=1} FunctionDecl=function:13:6
-// CHECK-scan: {start_line=16 start_col=2 end_line=52 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK-scan: {start_line=16 start_col=2 end_line=38 end_col=1} Invalid Cursor => NoDeclFound
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:1 [Context=TestClassDecl.m]
-// CHECK-load: TestClassDecl.m:13:6: FunctionDefn=function [Context=TestClassDecl.m]
-// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 [Context=function]
+// CHECK-load: TestClassDecl.m:10:12: ObjCInterfaceDecl=Foo:10:1 [Context=TestClassDecl.m] [Extent=10:1:11:4]
+// CHECK-load: TestClassDecl.m:13:6: FunctionDefn=function [Context=TestClassDecl.m] [Extent=13:6:16:1]
+// CHECK-load: TestClassDecl.m:13:21: ParmDecl=arg:13:21 [Context=function] [Extent=13:21:13:23]
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 6ee50aef1e04..8a1e4d1556e4 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -1,22 +1,6 @@
// RUN: %clang_cc1 -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 all | FileCheck %s
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@interface Foo
{
}
@@ -58,28 +42,6 @@ enum {
someEnum
};
-// CHECK: c-index-api-loadTU-test.m:20:12: ObjCInterfaceDecl=Foo:20:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:24:1: ObjCInstanceMethodDecl=foo:24:1 [Context=Foo]
-// CHECK: c-index-api-loadTU-test.m:25:1: ObjCClassMethodDecl=fooC:25:1 [Context=Foo]
-// CHECK: c-index-api-loadTU-test.m:29:12: ObjCInterfaceDecl=Bar:29:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:29:18: ObjCSuperClassRef=Foo:29:1 [Context=Bar]
-// CHECK: c-index-api-loadTU-test.m:35:1: ObjCCategoryDecl=FooCat:35:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:20:1: ObjCClassRef=Foo:35:1 [Context=FooCat]
-// CHECK: c-index-api-loadTU-test.m:36:1: ObjCInstanceMethodDecl=catMethodWithFloat::36:1 [Context=FooCat]
-// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=floatMethod:37:1 [Context=FooCat]
-// CHECK: c-index-api-loadTU-test.m:40:1: ObjCProtocolDecl=Proto:40:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:41:1: ObjCInstanceMethodDecl=pMethod:41:1 [Context=Proto]
-// CHECK: c-index-api-loadTU-test.m:44:1: ObjCProtocolDecl=SubP:44:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:40:1: ObjCProtocolRef=Proto:40:1 [Context=SubP]
-// CHECK: c-index-api-loadTU-test.m:45:1: ObjCInstanceMethodDecl=spMethod:45:1 [Context=SubP]
-// CHECK: c-index-api-loadTU-test.m:48:12: ObjCInterfaceDecl=Baz:48:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:48:18: ObjCSuperClassRef=Bar:48:1 [Context=Baz]
-// CHECK: c-index-api-loadTU-test.m:44:1: ObjCProtocolRef=SubP:44:1 [Context=Baz]
-// CHECK: c-index-api-loadTU-test.m:50:9: ObjCIvarDecl=_anIVar:50:9 [Context=Baz]
-// CHECK: c-index-api-loadTU-test.m:53:1: ObjCInstanceMethodDecl=bazMethod:53:1 [Context=Baz]
-// CHECK: c-index-api-loadTU-test.m:57:1: EnumDecl=:57:1 [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:58:3: EnumConstantDecl=someEnum:58:3 [Context=]
-
int main (int argc, const char * argv[]) {
Baz * bee;
id a = [bee foo];
@@ -91,10 +53,33 @@ int main (int argc, const char * argv[]) {
main(someEnum, (const char **)bee);
}
-// CHECK: c-index-api-loadTU-test.m:83:5: FunctionDefn=main [Context=c-index-api-loadTU-test.m]
-// CHECK: c-index-api-loadTU-test.m:83:15: ParmDecl=argc:83:15 [Context=main]
-// CHECK: c-index-api-loadTU-test.m:83:34: ParmDecl=argv:83:34 [Context=main]
-// CHECK: c-index-api-loadTU-test.m:84:8: VarDecl=bee:84:8 [Context=main]
-// 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:4:12: ObjCInterfaceDecl=Foo:4:1 [Context=c-index-api-loadTU-test.m] [Extent=4:1:11:4]
+// CHECK: c-index-api-loadTU-test.m:8:1: ObjCInstanceMethodDecl=foo:8:1 [Context=Foo] [Extent=8:1:8:6]
+// CHECK: c-index-api-loadTU-test.m:9:1: ObjCClassMethodDecl=fooC:9:1 [Context=Foo] [Extent=9:1:9:7]
+// CHECK: c-index-api-loadTU-test.m:13:12: ObjCInterfaceDecl=Bar:13:1 [Context=c-index-api-loadTU-test.m] [Extent=13:1:17:4]
+// CHECK: c-index-api-loadTU-test.m:13:18: ObjCSuperClassRef=Foo:13:1 [Context=Bar] [Extent=13:1:17:4]
+// CHECK: c-index-api-loadTU-test.m:19:1: ObjCCategoryDecl=FooCat:19:1 [Context=c-index-api-loadTU-test.m] [Extent=19:1:22:4]
+// CHECK: c-index-api-loadTU-test.m:4:1: ObjCClassRef=Foo:19:1 [Context=FooCat] [Extent=19:1:22:4]
+// CHECK: c-index-api-loadTU-test.m:20:1: ObjCInstanceMethodDecl=catMethodWithFloat::20:1 [Context=FooCat] [Extent=20:1:20:40]
+// CHECK: c-index-api-loadTU-test.m:21:1: ObjCInstanceMethodDecl=floatMethod:21:1 [Context=FooCat] [Extent=21:1:21:22]
+// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolDecl=Proto:24:1 [Context=c-index-api-loadTU-test.m] [Extent=24:1:26:4]
+// CHECK: c-index-api-loadTU-test.m:25:1: ObjCInstanceMethodDecl=pMethod:25:1 [Context=Proto] [Extent=25:1:25:10]
+// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolDecl=SubP:28:1 [Context=c-index-api-loadTU-test.m] [Extent=28:1:30:4]
+// CHECK: c-index-api-loadTU-test.m:24:1: ObjCProtocolRef=Proto:24:1 [Context=SubP] [Extent=24:1:26:4]
+// CHECK: c-index-api-loadTU-test.m:29:1: ObjCInstanceMethodDecl=spMethod:29:1 [Context=SubP] [Extent=29:1:29:11]
+// CHECK: c-index-api-loadTU-test.m:32:12: ObjCInterfaceDecl=Baz:32:1 [Context=c-index-api-loadTU-test.m] [Extent=32:1:39:4]
+// CHECK: c-index-api-loadTU-test.m:32:18: ObjCSuperClassRef=Bar:32:1 [Context=Baz] [Extent=32:1:39:4]
+// CHECK: c-index-api-loadTU-test.m:28:1: ObjCProtocolRef=SubP:28:1 [Context=Baz] [Extent=28:1:30:4]
+// CHECK: c-index-api-loadTU-test.m:34:9: ObjCIvarDecl=_anIVar:34:9 [Context=Baz] [Extent=34:9:34:15]
+// CHECK: c-index-api-loadTU-test.m:37:1: ObjCInstanceMethodDecl=bazMethod:37:1 [Context=Baz] [Extent=37:1:37:20]
+// CHECK: c-index-api-loadTU-test.m:41:1: EnumDecl=:41:1 [Context=c-index-api-loadTU-test.m] [Extent=41:1:43:1]
+// CHECK: c-index-api-loadTU-test.m:42:3: EnumConstantDecl=someEnum:42:3 [Context=] [Extent=42:3:42:10]
+// CHECK: c-index-api-loadTU-test.m:45:5: FunctionDefn=main [Context=c-index-api-loadTU-test.m] [Extent=45:5:54:1]
+// CHECK: c-index-api-loadTU-test.m:45:15: ParmDecl=argc:45:15 [Context=main] [Extent=45:15:45:18]
+// CHECK: c-index-api-loadTU-test.m:45:34: ParmDecl=argv:45:34 [Context=main] [Extent=45:34:45:37]
+// CHECK: c-index-api-loadTU-test.m:46:8: VarDecl=bee:46:8 [Context=main] [Extent=46:8:46:10]
+// CHECK: c-index-api-loadTU-test.m:47:5: VarDecl=a:47:5 [Context=main] [Extent=47:5:47:17]
+// CHECK: c-index-api-loadTU-test.m:48:12: VarDecl=c:48:12 [Context=main] [Extent=48:12:48:25]
+// CHECK: c-index-api-loadTU-test.m:49:13: VarDecl=d:49:13 [Context=main] [Extent=49:13:49:13]
+
+
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index 23ae21887830..03ab5a820835 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -57,10 +57,10 @@ int main (int argc, const char * argv[]) {
// CHECK: {start_line=7 start_col=1 end_line=7 end_col=6} ObjCInstanceMethodDecl=foo:7:1
// CHECK: {start_line=7 start_col=7 end_line=7 end_col=7} ObjCInterfaceDecl=Foo:3:1
// CHECK: {start_line=8 start_col=1 end_line=8 end_col=7} ObjCClassMethodDecl=fooC:8:1
-// CHECK: {start_line=8 start_col=8 end_line=10 end_col=1} ObjCInterfaceDecl=Foo:3:1
-// CHECK: {start_line=10 start_col=2 end_line=11 end_col=1} Invalid Cursor => NoDeclFound
-// CHECK: {start_line=12 start_col=1 end_line=16 end_col=1} ObjCInterfaceDecl=Bar:12:1
-// CHECK: {start_line=16 start_col=2 end_line=17 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=8 start_col=8 end_line=10 end_col=4} ObjCInterfaceDecl=Foo:3:1
+// CHECK: {start_line=10 start_col=5 end_line=11 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=12 start_col=1 end_line=16 end_col=4} ObjCInterfaceDecl=Bar:12:1
+// CHECK: {start_line=16 start_col=5 end_line=17 end_col=1} Invalid Cursor => NoDeclFound
// CHECK: {start_line=18 start_col=1 end_line=18 end_col=24} ObjCCategoryDecl=FooCat:18:1
// CHECK: {start_line=19 start_col=1 end_line=19 end_col=28} ObjCInstanceMethodDecl=catMethodWithFloat::19:1
// CHECK: {start_line=19 start_col=29 end_line=19 end_col=33} ParmDecl=fArg:19:36
@@ -69,24 +69,24 @@ int main (int argc, const char * argv[]) {
// CHECK: {start_line=19 start_col=40 end_line=19 end_col=40} ObjCInstanceMethodDecl=catMethodWithFloat::19:1
// CHECK: {start_line=19 start_col=41 end_line=19 end_col=41} ObjCCategoryDecl=FooCat:18:1
// CHECK: {start_line=20 start_col=1 end_line=20 end_col=22} ObjCInstanceMethodDecl=floatMethod:20:1
-// CHECK: {start_line=20 start_col=23 end_line=21 end_col=1} ObjCCategoryDecl=FooCat:18:1
-// CHECK: {start_line=21 start_col=2 end_line=22 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=20 start_col=23 end_line=21 end_col=4} ObjCCategoryDecl=FooCat:18:1
+// CHECK: {start_line=21 start_col=5 end_line=22 end_col=1} Invalid Cursor => NoDeclFound
// CHECK: {start_line=23 start_col=1 end_line=23 end_col=16} ObjCProtocolDecl=Proto:23:1
// CHECK: {start_line=24 start_col=1 end_line=24 end_col=10} ObjCInstanceMethodDecl=pMethod:24:1
-// CHECK: {start_line=24 start_col=11 end_line=25 end_col=1} ObjCProtocolDecl=Proto:23:1
-// CHECK: {start_line=25 start_col=2 end_line=26 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=24 start_col=11 end_line=25 end_col=4} ObjCProtocolDecl=Proto:23:1
+// CHECK: {start_line=25 start_col=5 end_line=26 end_col=1} Invalid Cursor => NoDeclFound
// CHECK: {start_line=27 start_col=1 end_line=27 end_col=23} ObjCProtocolDecl=SubP:27:1
// CHECK: {start_line=28 start_col=1 end_line=28 end_col=11} ObjCInstanceMethodDecl=spMethod:28:1
-// CHECK: {start_line=28 start_col=12 end_line=29 end_col=1} ObjCProtocolDecl=SubP:27:1
-// CHECK: {start_line=29 start_col=2 end_line=30 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=28 start_col=12 end_line=29 end_col=4} ObjCProtocolDecl=SubP:27:1
+// CHECK: {start_line=29 start_col=5 end_line=30 end_col=1} Invalid Cursor => NoDeclFound
// CHECK: {start_line=31 start_col=1 end_line=33 end_col=4} ObjCInterfaceDecl=Baz:31:1
// CHECK: {start_line=33 start_col=5 end_line=33 end_col=7} Invalid Cursor => NotImplemented
// CHECK: {start_line=33 start_col=8 end_line=33 end_col=8} ObjCInterfaceDecl=Baz:31:1
// CHECK: {start_line=33 start_col=9 end_line=33 end_col=15} Invalid Cursor => NotImplemented
// CHECK: {start_line=33 start_col=16 end_line=35 end_col=1} ObjCInterfaceDecl=Baz:31:1
// CHECK: {start_line=36 start_col=1 end_line=36 end_col=20} ObjCInstanceMethodDecl=bazMethod:36:1
-// CHECK: {start_line=36 start_col=21 end_line=38 end_col=1} ObjCInterfaceDecl=Baz:31:1
-// CHECK: {start_line=38 start_col=2 end_line=39 end_col=1} Invalid Cursor => NoDeclFound
+// CHECK: {start_line=36 start_col=21 end_line=38 end_col=4} ObjCInterfaceDecl=Baz:31:1
+// CHECK: {start_line=38 start_col=5 end_line=39 end_col=1} Invalid Cursor => NoDeclFound
// CHECK: {start_line=40 start_col=1 end_line=41 end_col=2} EnumDecl=:40:1
// CHECK: {start_line=41 start_col=3 end_line=41 end_col=10} EnumConstantDecl=someEnum:41:3
// CHECK: {start_line=41 start_col=11 end_line=42 end_col=1} EnumDecl=:40:1
diff --git a/test/Index/code-completion.cpp b/test/Index/code-completion.cpp
index 55d068a16694..7fd4376735a0 100644
--- a/test/Index/code-completion.cpp
+++ b/test/Index/code-completion.cpp
@@ -34,20 +34,20 @@ void test_overloaded() {
}
// CHECK-MEMBER: FieldDecl:{ResultType double}{TypedText member}
+// CHECK-MEMBER: FieldDecl:{ResultType int}{Text X::}{TypedText member}
+// CHECK-MEMBER: FieldDecl:{ResultType float}{Text Y::}{TypedText member}
// CHECK-MEMBER: FunctionDecl:{ResultType void}{Informative Y::}{TypedText memfunc}{LeftParen (}{Optional {Placeholder int i}}{RightParen )}
-// CHECK-MEMBER: EnumConstantDecl:{ResultType enum X::E}{Informative E::}{TypedText Val1}
-// CHECK-MEMBER: FunctionDecl:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )}
-// CHECK-MEMBER: FunctionDecl:{ResultType void}{Informative Y::}{TypedText ~Y}{LeftParen (}{RightParen )}
-// CHECK-MEMBER: FunctionDecl:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )}
// CHECK-MEMBER: FunctionDecl:{ResultType int}{TypedText operator int}{LeftParen (}{RightParen )}{Informative const}
// CHECK-MEMBER: FunctionDecl:{ResultType struct Z &}{TypedText operator=}{LeftParen (}{Placeholder struct Z const &}{RightParen )}
-// CHECK-MEMBER: FieldDecl:{ResultType int}{Text X::}{TypedText member}
-// CHECK-MEMBER: FieldDecl:{ResultType float}{Text Y::}{TypedText member}
// CHECK-MEMBER: FunctionDecl:{ResultType struct X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder struct X const &}{RightParen )}
// CHECK-MEMBER: FunctionDecl:{ResultType struct Y &}{Text Y::}{TypedText operator=}{LeftParen (}{Placeholder struct Y const &}{RightParen )}
+// CHECK-MEMBER: EnumConstantDecl:{ResultType enum X::E}{Informative E::}{TypedText Val1}
// CHECK-MEMBER: StructDecl:{TypedText X}{Text ::}
// CHECK-MEMBER: StructDecl:{TypedText Y}{Text ::}
// CHECK-MEMBER: StructDecl:{TypedText Z}{Text ::}
+// CHECK-MEMBER: FunctionDecl:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )}
+// CHECK-MEMBER: FunctionDecl:{ResultType void}{Informative Y::}{TypedText ~Y}{LeftParen (}{RightParen )}
+// CHECK-MEMBER: FunctionDecl:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType int &}{Text overloaded}{LeftParen (}{Text struct Z z}{Comma , }{CurrentParameter int second}{RightParen )}
// CHECK-OVERLOAD: NotImplemented:{ResultType float &}{Text overloaded}{LeftParen (}{Text int i}{Comma , }{CurrentParameter long second}{RightParen )}
diff --git a/test/Index/complete-at-directives.m b/test/Index/complete-at-directives.m
index 68d1ef42f863..1d0a471dbbca 100644
--- a/test/Index/complete-at-directives.m
+++ b/test/Index/complete-at-directives.m
@@ -1,16 +1,16 @@
/* Run lines are at the end, since line/column matter in this test. */
-@interface MyClass { }
+@interface MyClass { @public }
@end
@implementation MyClass
@end
// RUN: c-index-test -code-completion-at=%s:2:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
-// CHECK-CC1: {TypedText class}{Text }{Placeholder identifier}{Text ;}
-// CHECK-CC1: {TypedText compatibility_alias}{Text }{Placeholder alias}{Text }{Placeholder class}
-// CHECK-CC1: {TypedText implementation}{Text }{Placeholder class}
-// CHECK-CC1: {TypedText interface}{Text }{Placeholder class}
-// CHECK-CC1: {TypedText protocol}{Text }{Placeholder protocol}
+// CHECK-CC1: {TypedText class}{HorizontalSpace }{Placeholder identifier}{SemiColon ;}
+// CHECK-CC1: {TypedText compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
+// CHECK-CC1: {TypedText implementation}{HorizontalSpace }{Placeholder class}
+// CHECK-CC1: {TypedText interface}{HorizontalSpace }{Placeholder class}
+// CHECK-CC1: {TypedText protocol}{HorizontalSpace }{Placeholder protocol}
// RUN: c-index-test -code-completion-at=%s:3:2 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText end}
@@ -19,6 +19,41 @@
// CHECK-CC2: {TypedText required}
// RUN: c-index-test -code-completion-at=%s:6:2 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// CHECK-CC3: {TypedText dynamic}{Text }{Placeholder property}
+// CHECK-CC3: {TypedText dynamic}{HorizontalSpace }{Placeholder property}
// CHECK-CC3: {TypedText end}
-// CHECK-CC3: {TypedText synthesize}{Text }{Placeholder property}
+// CHECK-CC3: {TypedText synthesize}{HorizontalSpace }{Placeholder property}
+
+// RUN: c-index-test -code-completion-at=%s:2:1 %s | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4: NotImplemented:{TypedText @class}{HorizontalSpace }{Placeholder identifier}{SemiColon ;}
+// CHECK-CC4: NotImplemented:{TypedText @compatibility_alias}{HorizontalSpace }{Placeholder alias}{HorizontalSpace }{Placeholder class}
+// CHECK-CC4: NotImplemented:{TypedText @implementation}{HorizontalSpace }{Placeholder class}
+// CHECK-CC4: NotImplemented:{TypedText @interface}{HorizontalSpace }{Placeholder class}
+// CHECK-CC4: NotImplemented:{TypedText @protocol}{HorizontalSpace }{Placeholder protocol}
+// CHECK-CC4: NotImplemented:{TypedText _Bool}
+// CHECK-CC4: TypedefDecl:{TypedText Class}
+// CHECK-CC4: TypedefDecl:{TypedText id}
+// CHECK-CC4: TypedefDecl:{TypedText SEL}
+
+// RUN: c-index-test -code-completion-at=%s:3:1 %s | FileCheck -check-prefix=CHECK-CC5 %s
+// CHECK-CC5: {TypedText @end}
+// CHECK-CC5: {TypedText @optional}
+// CHECK-CC5: {TypedText @property}
+// CHECK-CC5: {TypedText @required}
+// CHECK-CC5: NotImplemented:{TypedText _Bool}
+// CHECK-CC5: TypedefDecl:{TypedText Class}
+// CHECK-CC5: TypedefDecl:{TypedText id}
+// CHECK-CC5: ObjCInterfaceDecl:{TypedText MyClass}
+// CHECK-CC5: TypedefDecl:{TypedText SEL}
+
+// RUN: c-index-test -code-completion-at=%s:2:23 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: NotImplemented:{TypedText package}
+// CHECK-CC6: NotImplemented:{TypedText private}
+// CHECK-CC6: NotImplemented:{TypedText protected}
+// CHECK-CC6: NotImplemented:{TypedText public}
+
+// RUN: c-index-test -code-completion-at=%s:2:22 %s | FileCheck -check-prefix=CHECK-CC7 %s
+// CHECK-CC7: NotImplemented:{TypedText @package}
+// CHECK-CC7: NotImplemented:{TypedText @private}
+// CHECK-CC7: NotImplemented:{TypedText @protected}
+// CHECK-CC7: NotImplemented:{TypedText @public}
+// CHECK-CC7: NotImplemented:{TypedText _Bool}
diff --git a/test/Index/complete-at-exprstmt.m b/test/Index/complete-at-exprstmt.m
index 82c3983e82b2..e8efc3cf46f1 100644
--- a/test/Index/complete-at-exprstmt.m
+++ b/test/Index/complete-at-exprstmt.m
@@ -1,6 +1,6 @@
/* The run lines are below, because this test is line- and
column-number sensitive. */
-@interface MyClass { }
+@interface MyClass { int ivar; }
- (int)myMethod:(int)arg;
@end
@@ -13,11 +13,25 @@
// CHECK-CC1: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC1: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC1: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
-// CHECK-CC1: {TypedText synchronized}{Text }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
-// CHECK-CC1: {TypedText throw}{Text }{Placeholder expression}{Text ;}
+// CHECK-CC1: {TypedText synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
+// CHECK-CC1: {TypedText throw}{HorizontalSpace }{Placeholder expression}{SemiColon ;}
// CHECK-CC1: {TypedText try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
// RUN: c-index-test -code-completion-at=%s:9:19 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: {TypedText encode}{LeftParen (}{Placeholder type-name}{RightParen )}
// CHECK-CC2: {TypedText protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
// CHECK-CC2: {TypedText selector}{LeftParen (}{Placeholder selector}{RightParen )}
-
+// RUN: c-index-test -code-completion-at=%s:9:3 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: NotImplemented:{TypedText @encode}{LeftParen (}{Placeholder type-name}{RightParen )}
+// CHECK-CC3: NotImplemented:{TypedText @protocol}{LeftParen (}{Placeholder protocol-name}{RightParen )}
+// CHECK-CC3: NotImplemented:{TypedText @selector}{LeftParen (}{Placeholder selector}{RightParen )}
+// CHECK-CC3: NotImplemented:{TypedText @synchronized}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}
+// CHECK-CC3: NotImplemented:{TypedText @throw}{HorizontalSpace }{Placeholder expression}{SemiColon ;}
+// CHECK-CC3: NotImplemented:{TypedText @try}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @catch}{LeftParen (}{Placeholder parameter}{RightParen )}{LeftBrace {}{Placeholder statements}{RightBrace }}{Text @finally}{LeftBrace {}{Placeholder statements}{RightBrace }}
+// CHECK-CC3: NotImplemented:{ResultType SEL}{TypedText _cmd}
+// CHECK-CC3: ParmDecl:{ResultType int}{TypedText arg}
+// CHECK-CC3: TypedefDecl:{TypedText Class}
+// CHECK-CC3: TypedefDecl:{TypedText id}
+// CHECK-CC3: ObjCIvarDecl:{ResultType int}{TypedText ivar}
+// CHECK-CC3: ObjCInterfaceDecl:{TypedText MyClass}
+// CHECK-CC3: TypedefDecl:{TypedText SEL}
+// CHECK-CC3: NotImplemented:{ResultType MyClass *}{TypedText self}
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index a7b37fd2442c..096ed24c221c 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -105,7 +105,7 @@ void f(Ellipsis *e) {
// RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText categoryClassMethod}
-// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{Text withKeyword:}{Placeholder (int)b}
+// CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)a}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)b}
// CHECK-CC1: {TypedText classMethod2}
// CHECK-CC1: {TypedText new}
// CHECK-CC1: {TypedText protocolClassMethod}
@@ -117,10 +117,10 @@ void f(Ellipsis *e) {
// CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyClassMethod:}{Placeholder (id)obj}
// CHECK-CC3: ObjCClassMethodDecl:{ResultType int}{TypedText MyPrivateMethod}
// RUN: c-index-test -code-completion-at=%s:65:16 %s | FileCheck -check-prefix=CHECK-CC4 %s
-// CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y}
+// CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y}
// CHECK-CC4: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyPrivateInstMethod}
// RUN: c-index-test -code-completion-at=%s:74:9 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{Text second:}{Placeholder (id)y}
+// CHECK-CC5: ObjCInstanceMethodDecl:{ResultType int}{TypedText MyInstMethod:}{Placeholder (id)x}{HorizontalSpace }{Text second:}{Placeholder (id)y}
// CHECK-CC5: ObjCInstanceMethodDecl:{ResultType int}{TypedText MySubInstMethod}
// RUN: c-index-test -code-completion-at=%s:82:8 %s | FileCheck -check-prefix=CHECK-CC6 %s
// CHECK-CC6: ObjCInstanceMethodDecl:{ResultType id}{TypedText protocolInstanceMethod:}{Placeholder (int)value}
@@ -128,21 +128,20 @@ void f(Ellipsis *e) {
// RUN: c-index-test -code-completion-at=%s:95:8 %s | FileCheck -check-prefix=CHECK-CC7 %s
// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method}
// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}
-// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{Text Arg1:}{Placeholder (int)i1}{Text Arg2:}{Placeholder (int)i2}
-// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{Text Arg1:}{Placeholder (int)i1}{Text OtherArg:}{Placeholder (id)obj}
-// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{Text SomeArg:}{Placeholder (int)i1}{Text OtherArg:}{Placeholder (id)obj}
-// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{Text Arg1:}{Placeholder (int)i1}{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (float)f}{HorizontalSpace }{Text SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CC7: ObjCInstanceMethodDecl:{ResultType int}{TypedText OtherMethod:}{Placeholder (float)f}{HorizontalSpace }{Text Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
// RUN: c-index-test -code-completion-at=%s:95:17 %s | FileCheck -check-prefix=CHECK-CC8 %s
// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText }
-// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{Text Arg2:}{Placeholder (int)i2}
-// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{Text OtherArg:}{Placeholder (id)obj}
-// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText SomeArg:}{Placeholder (int)i1}{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text Arg2:}{Placeholder (int)i2}
+// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText Arg1:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
+// CHECK-CC8: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{TypedText SomeArg:}{Placeholder (int)i1}{HorizontalSpace }{Text OtherArg:}{Placeholder (id)obj}
// RUN: c-index-test -code-completion-at=%s:95:24 %s | FileCheck -check-prefix=CHECK-CC9 %s
// CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText Arg2:}{Placeholder (int)i2}
// CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)obj}
// RUN: c-index-test -code-completion-at=%s:61:11 %s | FileCheck -check-prefix=CHECK-CCA %s
// CHECK-CCA: {ResultType SEL}{TypedText _cmd}
-// CHECK-CCA: {ResultType Class}{TypedText self}
// CHECK-CCA: TypedefDecl:{TypedText Class}
// CHECK-CCA: ObjCInterfaceDecl:{TypedText Foo}
// CHECK-CCA: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{RightParen )}
@@ -150,6 +149,7 @@ void f(Ellipsis *e) {
// CHECK-CCA: ObjCInterfaceDecl:{TypedText MyClass}
// CHECK-CCA: ObjCInterfaceDecl:{TypedText MySubClass}
// CHECK-CCA: TypedefDecl:{TypedText SEL}
+// CHECK-CCA: {ResultType Class}{TypedText self}
// CHECK-CCA: {TypedText super}
// RUN: c-index-test -code-completion-at=%s:103:6 %s | FileCheck -check-prefix=CHECK-CCB %s
// CHECK-CCB: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int)i}{Placeholder , ...}
diff --git a/test/Index/complete-tabs.c b/test/Index/complete-tabs.c
new file mode 100644
index 000000000000..f3313bfbb81e
--- /dev/null
+++ b/test/Index/complete-tabs.c
@@ -0,0 +1,9 @@
+// Test code-completion in the presence of tabs
+struct Point { int x, y; };
+
+void f(struct Point *p) {
+ p->
+
+// RUN: c-index-test -code-completion-at=%s:5:5 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: {TypedText x}
+// CHECK-CC1: {TypedText y}
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
new file mode 100644
index 000000000000..7ea4c2c1cdcf
--- /dev/null
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang -E -std=c++0x %s -o - | FileCheck --check-prefix=CHECK-0X %s
+// RUN: %clang -E %s -o - | FileCheck --check-prefix=CHECK-NO-0X %s
+
+#if __has_feature(cxx_lambdas)
+int lambdas();
+#else
+int no_lambdas();
+#endif
+
+// CHECK-0X: no_lambdas
+// CHECK-NO-0X: no_lambdas
+
+
+#if __has_feature(cxx_nullptr)
+int has_nullptr();
+#else
+int no_nullptr();
+#endif
+
+// CHECK-0X: no_nullptr
+// CHECK-NO-0X: no_nullptr
+
+
+#if __has_feature(cxx_concepts)
+int concepts();
+#else
+int no_concepts();
+#endif
+
+// CHECK-0X: no_concepts
+// CHECK-NO-0X: no_concepts
+
+
+#if __has_feature(cxx_decltype)
+int has_decltype();
+#else
+int no_decltype();
+#endif
+
+// CHECK-0X: has_decltype
+// CHECK-NO-0X: no_decltype
+
+
+#if __has_feature(cxx_auto_type)
+int auto_type();
+#else
+int no_auto_type();
+#endif
+
+// CHECK-0X: auto_type
+// CHECK-NO-0X: no_auto_type
+
+
+#if __has_feature(cxx_attributes)
+int attributes();
+#else
+int no_attributes();
+#endif
+
+// CHECK-0X: attributes
+// CHECK-NO-0X: no_attributes
+
+
+#if __has_feature(cxx_static_assert)
+int has_static_assert();
+#else
+int no_static_assert();
+#endif
+
+// CHECK-0X: has_static_assert
+// CHECK-NO-0X: no_static_assert
+
+
+#if __has_feature(cxx_deleted_functions)
+int deleted_functions();
+#else
+int no_deleted_functions();
+#endif
+
+// CHECK-0X: deleted_functions
+// CHECK-NO-0X: no_deleted_functions
+
+
+#if __has_feature(cxx_rvalue_references)
+int rvalue_references();
+#else
+int no_rvalue_references();
+#endif
+
+// CHECK-0X: no_rvalue_references
+// CHECK-NO-0X: no_rvalue_references
+
+
+#if __has_feature(cxx_variadic_templates)
+int variadic_templates();
+#else
+int no_variadic_templates();
+#endif
+
+// CHECK-0X: no_variadic_templates
+// CHECK-NO-0X: no_variadic_templates
diff --git a/test/Lexer/hexfloat.cpp b/test/Lexer/hexfloat.cpp
new file mode 100644
index 000000000000..5a62556ff616
--- /dev/null
+++ b/test/Lexer/hexfloat.cpp
@@ -0,0 +1,8 @@
+//RUN: %clang_cc1 -fsyntax-only -verify
+//RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify
+
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
+float f = 0x1p+1; // expected-warning {{incompatible with C++0x}}
+#else
+float f = 0x1p+1; // expected-warning {{invalid suffix}}
+#endif
diff --git a/test/Lexer/numeric-literal-trash.c b/test/Lexer/numeric-literal-trash.c
index 1d7c87bfbf06..5407ba9824f7 100644
--- a/test/Lexer/numeric-literal-trash.c
+++ b/test/Lexer/numeric-literal-trash.c
@@ -4,7 +4,7 @@
-
+int ec(int, int);
void x() {
diff --git a/test/Misc/tabstop.c b/test/Misc/tabstop.c
new file mode 100644
index 000000000000..3fabda76eb8c
--- /dev/null
+++ b/test/Misc/tabstop.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -ftabstop 3 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=3 -strict-whitespace %s
+// RUN: %clang_cc1 -ftabstop 4 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=4 -strict-whitespace %s
+// RUN: %clang_cc1 -ftabstop 5 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=5 -strict-whitespace %s
+
+// tab
+ void* a = 1;
+
+// tab tab
+ void* b = 1;
+
+// 3x space tab
+ void* c = 1;
+
+// tab at column 10
+void* d = 1;
+
+//CHECK-3: {{^ void\* a = 1;}}
+//CHECK-3: {{^ void\* b = 1;}}
+//CHECK-3: {{^ void\* c = 1;}}
+//CHECK-3: {{^void\* d = 1;}}
+
+//CHECK-4: {{^ void\* a = 1;}}
+//CHECK-4: {{^ void\* b = 1;}}
+//CHECK-4: {{^ void\* c = 1;}}
+//CHECK-4: {{^void\* d = 1;}}
+
+//CHECK-5: {{^ void\* a = 1;}}
+//CHECK-5: {{^ void\* b = 1;}}
+//CHECK-5: {{^ void\* c = 1;}}
+//CHECK-5: {{^void\* d = 1;}}
diff --git a/test/Parser/cxx0x-literal-operators.cpp b/test/Parser/cxx0x-literal-operators.cpp
index 830754e56ae0..30b290382cb4 100644
--- a/test/Parser/cxx0x-literal-operators.cpp
+++ b/test/Parser/cxx0x-literal-operators.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -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);
+void operator "" (const char *); // expected-error {{expected identifier}}
+void operator "k" foo(const char *); // expected-error {{string literal after 'operator' must be '""'}}
+void operator "" tester (const char *);
diff --git a/test/Preprocessor/foo.framework/Headers/bar.h b/test/Preprocessor/foo.framework/Headers/bar.h
new file mode 100644
index 000000000000..574e851bb3e6
--- /dev/null
+++ b/test/Preprocessor/foo.framework/Headers/bar.h
@@ -0,0 +1,3 @@
+
+int y;
+
diff --git a/test/Preprocessor/foo.framework/Headers/foo.h b/test/Preprocessor/foo.framework/Headers/foo.h
new file mode 100644
index 000000000000..b08d948fabff
--- /dev/null
+++ b/test/Preprocessor/foo.framework/Headers/foo.h
@@ -0,0 +1,6 @@
+// This should warn: published framework headers should always
+// #import headers within the framework with framework paths.
+#include "bar.h"
+
+int x;
+
diff --git a/test/Preprocessor/framework-include.m b/test/Preprocessor/framework-include.m
new file mode 100644
index 000000000000..7e50f18f39b4
--- /dev/null
+++ b/test/Preprocessor/framework-include.m
@@ -0,0 +1,5 @@
+// RUN: %clang -E -F%S %s 2>&1 | grep "published framework headers should always #import headers within the framework with framework paths"
+
+// rdar://7520940
+#include <foo/foo.h>
+
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 5796b11e14bd..a1485b65013f 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -420,7 +420,7 @@
// MSP430:#define __LDBL_MIN_10_EXP__ (-307)
// MSP430:#define __LDBL_MIN_EXP__ (-1021)
// MSP430:#define __LDBL_MIN__ 2.2250738585072014e-308
-// MSP430:#define __LONG_LONG_MAX__ 2147483647LL
+// MSP430:#define __LONG_LONG_MAX__ 9223372036854775807LL
// MSP430:#define __LONG_MAX__ 2147483647L
// MSP430:#define __MSP430__ 1
// MSP430:#define __NO_INLINE__ 1
diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c
index 5f0842a616b0..e701494c20b6 100644
--- a/test/Preprocessor/stdint.c
+++ b/test/Preprocessor/stdint.c
@@ -380,15 +380,15 @@
// MSP430:INT_FAST32_MAX_ 2147483647L
// MSP430:UINT_FAST32_MAX_ 4294967295UL
//
-// MSP430:INT64_MAX_ INT64_MAX
-// MSP430:INT64_MIN_ INT64_MIN
-// MSP430:UINT64_MAX_ UINT64_MAX
-// MSP430:INT_LEAST64_MIN_ INT_LEAST64_MIN
-// MSP430:INT_LEAST64_MAX_ INT_LEAST64_MAX
-// MSP430:UINT_LEAST64_MAX_ UINT_LEAST64_MAX
-// MSP430:INT_FAST64_MIN_ INT_FAST64_MIN
-// MSP430:INT_FAST64_MAX_ INT_FAST64_MAX
-// MSP430:UINT_FAST64_MAX_ UINT_FAST64_MAX
+// MSP430:INT64_MAX_ 9223372036854775807LL
+// MSP430:INT64_MIN_ (-9223372036854775807LL -1)
+// MSP430:UINT64_MAX_ 18446744073709551615ULL
+// MSP430:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// MSP430:INT_LEAST64_MAX_ 9223372036854775807LL
+// MSP430:UINT_LEAST64_MAX_ 18446744073709551615ULL
+// MSP430:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// MSP430:INT_FAST64_MAX_ 9223372036854775807LL
+// MSP430:UINT_FAST64_MAX_ 18446744073709551615ULL
//
// MSP430:INTPTR_MIN_ (-32767 -1)
// MSP430:INTPTR_MAX_ 32767
@@ -415,8 +415,8 @@
// MSP430:UINT16_C_(0) 0U
// MSP430:INT32_C_(0) 0L
// MSP430:UINT32_C_(0) 0UL
-// MSP430:INT64_C_(0) INT64_C(0)
-// MSP430:UINT64_C_(0) UINT64_C(0)
+// MSP430:INT64_C_(0) 0LL
+// MSP430:UINT64_C_(0) 0ULL
//
// MSP430:INTMAX_C_(0) 0L
// MSP430:UINTMAX_C_(0) 0UL
diff --git a/test/Rewriter/rewrite-anonymous-union.m b/test/Rewriter/rewrite-anonymous-union.m
new file mode 100644
index 000000000000..579a06854fe6
--- /dev/null
+++ b/test/Rewriter/rewrite-anonymous-union.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -rewrite-objc -o - %s
+// rdar://6948022
+
+typedef unsigned int uint32_t;
+
+typedef struct {
+ union {
+ uint32_t daysOfWeek;
+ uint32_t dayOfMonth;
+ };
+ uint32_t nthOccurrence;
+} OSPatternSpecificData;
+
+@interface NSNumber
++ (NSNumber *)numberWithLong:(long)value;
+@end
+
+@interface OSRecurrence {
+ OSPatternSpecificData _pts;
+}
+- (void)_setTypeSpecificInfoOnRecord;
+@end
+
+@implementation OSRecurrence
+- (void)_setTypeSpecificInfoOnRecord
+{
+ [NSNumber numberWithLong:(_pts.dayOfMonth >= 31 ? -1 : _pts.dayOfMonth)];
+}
+@end
+
diff --git a/test/Rewriter/rewrite-byref-vars.mm b/test/Rewriter/rewrite-byref-vars.mm
new file mode 100644
index 000000000000..581437b5a5df
--- /dev/null
+++ b/test/Rewriter/rewrite-byref-vars.mm
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o - %s
+// radar 7540194
+
+extern "C" __declspec(dllexport) void BreakTheRewriter(int i) {
+ __block int aBlockVariable = 0;
+ void (^aBlock)(void) = ^ {
+ aBlockVariable = 42;
+ };
+ aBlockVariable++;
+ if (i) {
+ __block int bbBlockVariable = 0;
+ void (^aBlock)(void) = ^ {
+ bbBlockVariable = 42;
+ };
+ }
+}
+
+__declspec(dllexport) extern "C" __declspec(dllexport) void XXXXBreakTheRewriter(void) {
+
+ __block int aBlockVariable = 0;
+ void (^aBlock)(void) = ^ {
+ aBlockVariable = 42;
+ };
+ aBlockVariable++;
+ void (^bBlocks)(void) = ^ {
+ aBlockVariable = 43;
+ };
+ void (^c)(void) = ^ {
+ aBlockVariable = 44;
+ };
+
+}
+
+// $CLANG -cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks bug.mm
+// g++ -c -D"__declspec(X)=" bug.cpp
diff --git a/test/Rewriter/rewrite-eh.m b/test/Rewriter/rewrite-eh.m
new file mode 100644
index 000000000000..5bc80b55093f
--- /dev/null
+++ b/test/Rewriter/rewrite-eh.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -rewrite-objc -o - %s
+// rdar://7522880
+
+@interface NSException
+@end
+
+@interface Foo
+@end
+
+@implementation Foo
+- (void)bar {
+ @try {
+ } @catch (NSException *e) {
+ }
+ @catch (Foo *f) {
+ }
+ @catch (...) {
+ }
+}
+@end
diff --git a/test/Rewriter/rewrite-foreach-7.m b/test/Rewriter/rewrite-foreach-7.m
new file mode 100644
index 000000000000..9fa6a1a9f01a
--- /dev/null
+++ b/test/Rewriter/rewrite-foreach-7.m
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -rewrite-objc %s -o -
+
+@class NSArray;
+int main() {
+ NSArray *foo;
+ for (Class c in foo) { }
+}
diff --git a/test/Rewriter/rewrite-forward-class.m b/test/Rewriter/rewrite-forward-class.m
new file mode 100644
index 000000000000..5a50f53a480f
--- /dev/null
+++ b/test/Rewriter/rewrite-forward-class.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -rewrite-objc -o - %s
+// rdar://6969189
+
+@class XX;
+@class YY, ZZ, QQ;
+@class ISyncClient, SMSession, ISyncManager, ISyncSession, SMDataclassInfo, SMClientInfo,
+ DMCConfiguration, DMCStatusEntry;
+
diff --git a/test/Rewriter/rewrite-function-decl.mm b/test/Rewriter/rewrite-function-decl.mm
new file mode 100644
index 000000000000..023e55db4bbb
--- /dev/null
+++ b/test/Rewriter/rewrite-function-decl.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o - %s
+
+extern "C" __declspec(dllexport) void BreakTheRewriter(void) {
+ __block int aBlockVariable = 0;
+ void (^aBlock)(void) = ^ {
+ aBlockVariable = 42;
+ };
+ aBlockVariable++;
+ void (^bBlocks)(void) = ^ {
+ aBlockVariable = 43;
+ };
+ void (^c)(void) = ^ {
+ aBlockVariable = 44;
+ };
+
+}
+__declspec(dllexport) extern "C" void AnotherBreakTheRewriter(int *p1, double d) {
+
+ __block int bBlockVariable = 0;
+ void (^aBlock)(void) = ^ {
+ bBlockVariable = 42;
+ };
+ bBlockVariable++;
+ void (^bBlocks)(void) = ^ {
+ bBlockVariable = 43;
+ };
+ void (^c)(void) = ^ {
+ bBlockVariable = 44;
+ };
+
+}
diff --git a/test/Rewriter/rewrite-ivar-use.m b/test/Rewriter/rewrite-ivar-use.m
new file mode 100644
index 000000000000..82cff5b2d633
--- /dev/null
+++ b/test/Rewriter/rewrite-ivar-use.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -rewrite-objc -fms-extensions %s -o -
+// radar 7490331
+
+@interface Foo {
+ int a;
+ id b;
+}
+- (void)bar;
+- (void)baz:(id)q;
+@end
+
+@implementation Foo
+// radar 7522803
+static void foo(id bar) {
+ int i = ((Foo *)bar)->a;
+}
+
+- (void)bar {
+ a = 42;
+ [self baz:b];
+}
+- (void)baz:(id)q {
+}
+@end
+
diff --git a/test/Rewriter/rewrite-trivial-constructor.mm b/test/Rewriter/rewrite-trivial-constructor.mm
new file mode 100644
index 000000000000..81c7d9b8a72e
--- /dev/null
+++ b/test/Rewriter/rewrite-trivial-constructor.mm
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -x objective-c++ -fblocks -o - %s
+// radar 7537770
+
+typedef struct {
+ int a;
+ int b;
+} s;
+
+extern void CFBasicHashApply(int (^block)(s)) {
+ int used, cnt;
+ for (int idx = 0; 0 < used && idx < cnt; idx++) {
+ s bkt;
+ if (0 < bkt.a) {
+ if (!block(bkt)) {
+ return;
+ }
+ used--;
+ }
+ }
+}
+
diff --git a/test/Rewriter/rewrite-weak-attr.m b/test/Rewriter/rewrite-weak-attr.m
new file mode 100644
index 000000000000..2e559ee3e322
--- /dev/null
+++ b/test/Rewriter/rewrite-weak-attr.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fblocks -Dnil=0 -rewrite-objc -o - %s
+int main() {
+ __weak __block id foo = nil;
+ __block id foo2 = nil;
+ id foo3 = nil;
+
+ void (^myblock)() = ^{
+ foo = nil;
+ foo2 = nil;
+ [foo3 bar];
+ id foo4 = foo3;
+ };
+}
diff --git a/test/Rewriter/weak_byref_objects.m b/test/Rewriter/weak_byref_objects.m
new file mode 100644
index 000000000000..a0ebe88eaf16
--- /dev/null
+++ b/test/Rewriter/weak_byref_objects.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fblocks -triple i386-apple-darwin9 -fobjc-gc -rewrite-objc %s -o -
+
+#define nil 0
+int main() {
+ __weak __block id foo = nil;
+ __block id foo2 = nil;
+ id foo3 = nil;
+
+ void (^myblock)() = ^{
+ foo = nil;
+ foo2 = nil;
+ [foo3 bar];
+ id foo4 = foo3;
+ };
+}
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index 47fb2b6fba09..78995a993a4f 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -96,3 +96,9 @@ struct s2 {
int a;
}
}; // expected-error{{expected member name or ';' after declaration specifiers}}
+
+// Make sure we don't a.k.a. anonymous structs.
+typedef struct {
+ int x;
+} a_struct;
+int tmp = (a_struct) { .x = 0 }; // expected-error {{incompatible type initializing 'a_struct', expected 'int'}}
diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c
index 0966989bf9a3..3f064a01c867 100644
--- a/test/Sema/attr-noreturn.c
+++ b/test/Sema/attr-noreturn.c
@@ -2,6 +2,8 @@
static void (*fp0)(void) __attribute__((noreturn));
+void fatal();
+
static void __attribute__((noreturn)) f0(void) {
fatal();
} // expected-warning {{function declared 'noreturn' should not return}}
diff --git a/test/Sema/attr-section.c b/test/Sema/attr-section.c
index 20ae2e3547b9..614f294d237e 100644
--- a/test/Sema/attr-section.c
+++ b/test/Sema/attr-section.c
@@ -8,3 +8,8 @@ int x __attribute__((section(
int y __attribute__((section(
"sadf"))); // expected-error {{mach-o section specifier requires a segment and section separated by a comma}}
+// PR6007
+void test() {
+ __attribute__((section("NEAR,x"))) int n1; // expected-error {{'section' attribute is not valid on local variables}}
+ __attribute__((section("NEAR,x"))) static int n2; // ok.
+} \ No newline at end of file
diff --git a/test/Sema/block-labels.c b/test/Sema/block-labels.c
index af364b4f863a..353a5702eafa 100644
--- a/test/Sema/block-labels.c
+++ b/test/Sema/block-labels.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -verify -fblocks -fsyntax-only
+void xx();
+
int a() {
A:if (1) xx();
return ^{A:return 1;}();
diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c
index 9f1bc4025fac..52cebfe8922f 100644
--- a/test/Sema/block-misc.c
+++ b/test/Sema/block-misc.c
@@ -64,6 +64,7 @@ int test4(int argc) { // rdar://6251437
}
+void bar(void*);
// rdar://6257721 - reference to static/global is byref by default.
static int test5g;
void test5() {
@@ -157,6 +158,8 @@ void test16(__block int i) { // expected-error {{__block attribute not allowed,
__block int (*ap)[size]; // expected-error {{__block attribute not allowed on declaration with a variably modified type}}
}
+void f();
+
void test17() {
void (^bp)(int);
void (*rp)(int);
@@ -197,4 +200,23 @@ L0:
return x;
}
+// radr://7438948
+void test20() {
+ int n = 7;
+ int vla[n]; // expected-note {{declared at}}
+ int (*vm)[n] = 0; // expected-note {{declared at}}
+ vla[1] = 4341;
+ ^{
+ (void)vla[1]; // expected-error {{cannot refer to declaration with a variably modified type inside block}}
+ (void)(vm+1); // expected-error {{cannot refer to declaration with a variably modified type inside block}}
+ }();
+}
+// radr://7438948
+void test21() {
+ int a[7]; // expected-note {{declared at}}
+ a[1] = 1;
+ ^{
+ (void)a[1]; // expected-error {{cannot refer to declaration with an array type inside block}}
+ }();
+}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 4240b0985625..6416545cb7ea 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -76,6 +76,7 @@ static int funk(char *s) {
else
return 0;
}
+void next();
void foo4() {
int (^xx)(const char *s) = ^(char *s) { return 1; }; // expected-error {{incompatible block pointer types initializing 'int (^)(char *)', expected 'int (^)(char const *)'}}
int (*yy)(const char *s) = funk; // expected-warning {{incompatible pointer types initializing 'int (char *)', expected 'int (*)(char const *)'}}
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index 75a3cf1f62b8..579c3e5d6bdc 100644
--- a/test/Sema/compare.c
+++ b/test/Sema/compare.c
@@ -194,6 +194,9 @@ int ints(long a, unsigned long b) {
((short) a < (unsigned short) 0x80000) + // expected-warning {{comparison of integers of different signs}}
((signed char) a < (unsigned char) 0x80000) + // expected-warning {{comparison of integers of different signs}}
+ // We should be able to avoid warning about this.
+ (b != (a < 4 ? 1 : 2)) +
+
10
;
}
@@ -230,3 +233,44 @@ int test1(int i) {
enum en { zero };
return i > zero;
}
+
+// PR5937
+int test2(int i32) {
+ struct foo {
+ unsigned int u8 : 8;
+ unsigned long long u31 : 31;
+ unsigned long long u32 : 32;
+ unsigned long long u63 : 63;
+ unsigned long long u64 : 64;
+ } *x;
+
+ if (x->u8 == i32) { // comparison in int32, exact
+ return 0;
+ } else if (x->u31 == i32) { // comparison in int32, exact
+ return 1;
+ } else if (x->u32 == i32) { // expected-warning {{comparison of integers of different signs}}
+ return 2;
+ } else if (x->u63 == i32) { // comparison in uint64, exact because ==
+ return 3;
+ } else if (x->u64 == i32) { // expected-warning {{comparison of integers of different signs}}
+ return 4;
+ } else {
+ return 5;
+ }
+}
+
+// PR5887
+void test3() {
+ unsigned short x, y;
+ unsigned int z;
+ if ((x > y ? x : y) > z)
+ (void) 0;
+}
+
+// PR5961
+extern char *ptr4;
+void test4() {
+ long value;
+ if (value < (unsigned long) &ptr4) // expected-warning {{comparison of integers of different signs}}
+ return;
+}
diff --git a/test/Sema/complex-int.c b/test/Sema/complex-int.c
index 2bd03744d7a0..cb76a342c2d0 100644
--- a/test/Sema/complex-int.c
+++ b/test/Sema/complex-int.c
@@ -49,3 +49,7 @@ void test3(_Complex int *x) {
void test4(_Complex float *x) {
*x = ~*x;
}
+
+void test5(_Complex int *x) {
+ (*x)++;
+}
diff --git a/test/Sema/conditional.c b/test/Sema/conditional.c
index e67580ace600..c3dbe1321b6b 100644
--- a/test/Sema/conditional.c
+++ b/test/Sema/conditional.c
@@ -3,6 +3,7 @@
const char* test1 = 1 ? "i" : 1 == 1 ? "v" : "r";
void _efree(void *ptr);
+void free(void *ptr);
int _php_stream_free1() {
return (1 ? free(0) : _efree(0)); // expected-error {{incompatible type returning 'void', expected 'int'}}
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index 264e0430dacd..298bf7564219 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -235,3 +235,39 @@ extern void *test16_external;
void test16(void) {
int a = (unsigned long) &test16_external; // expected-warning {{implicit cast loses integer precision}}
}
+
+// PR 5938
+void test17() {
+ union {
+ unsigned long long a : 8;
+ unsigned long long b : 32;
+ unsigned long long c;
+ } U;
+
+ unsigned int x;
+ x = U.a;
+ x = U.b;
+ x = U.c; // expected-warning {{implicit cast loses integer precision}}
+}
+
+// PR 5939
+void test18() {
+ union {
+ unsigned long long a : 1;
+ unsigned long long b;
+ } U;
+
+ int x;
+ x = (U.a ? 0 : 1);
+ x = (U.b ? 0 : 1);
+}
+
+// None of these should warn.
+unsigned char test19(unsigned long u64) {
+ unsigned char x1 = u64 & 0xff;
+ unsigned char x2 = u64 >> 56;
+
+ unsigned char mask = 0xee;
+ unsigned char x3 = u64 & mask;
+ return x1 + x2 + x3;
+}
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 2cf49aa29da1..5b1196016032 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
typedef char T[4];
-T foo(int n, int m) { } // expected-error {{cannot return array or function}}
+T foo(int n, int m) { } // expected-error {{cannot return array type}}
void foof(const char *, ...) __attribute__((__format__(__printf__, 1, 2))), barf (void);
diff --git a/test/Sema/enum.c b/test/Sema/enum.c
index 262cab50a55f..916de41176bc 100644
--- a/test/Sema/enum.c
+++ b/test/Sema/enum.c
@@ -84,3 +84,11 @@ enum e1 { YES, NO };
static enum e1 badfunc(struct s1 *q) {
return q->bar();
}
+
+
+// Make sure we don't a.k.a. anonymous enums.
+typedef enum {
+ an_enumerator = 20
+} an_enum;
+// FIXME: why is this only a warning?
+char * s = (an_enum) an_enumerator; // expected-warning {{incompatible integer to pointer conversion initializing 'an_enum', expected 'char *'}}
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index e6cfa5fbe3e4..9acc63fa41a5 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -87,6 +87,10 @@ int test12(const char *X) {
return X == "foo"; // expected-warning {{comparison against a string literal is unspecified}}
}
+int test12b(const char *X) {
+ return sizeof(X == "foo"); // no-warning
+}
+
// rdar://6719156
void test13(
void (^P)()) { // expected-error {{blocks support disabled - compile with -fblocks}}
@@ -114,3 +118,13 @@ test15_t test15(void) {
// rdar://7446395
void test16(float x) { x == ((void*) 0); } // expected-error {{invalid operands to binary expression}}
+// PR6004
+void test17(int x) {
+ x = x / 0; // expected-warning {{division by zero is undefined}}
+ x = x % 0; // expected-warning {{remainder by zero is undefined}}
+ x /= 0; // expected-warning {{division by zero is undefined}}
+ x %= 0; // expected-warning {{remainder by zero is undefined}}
+
+ x = sizeof(x/0); // no warning.
+}
+
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 67081b5e2603..20e4dcd97fab 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -8,6 +8,7 @@ int printf(const char *restrict, ...);
int snprintf(char *restrict, size_t, const char *restrict, ...);
int sprintf(char *restrict, const char *restrict, ...);
int vasprintf(char **, const char *, va_list);
+int asprintf(char **, const char *, ...);
int vfprintf(FILE *, const char *restrict, va_list);
int vprintf(const char *restrict, va_list);
int vsnprintf(char *, size_t, const char *, va_list);
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index c561fe01c6ee..97d9f43cfba6 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -57,8 +57,9 @@ int comma3[(1,2)]; // expected-warning {{size of static array must be an integer
// Pointer + __builtin_constant_p
char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}}
-int illegaldiv1[1 || 1/0];
-int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}}
+int illegaldiv1[1 || 1/0]; // expected-warning {{division by zero is undefined}}
+int illegaldiv2[1/0]; // expected-error {{variable length array declaration not allowed at file scope}} \
+ // expected-warning {{division by zero is undefined}}
int illegaldiv3[INT_MIN / -1]; // expected-error {{variable length array declaration not allowed at file scope}}
int chooseexpr[__builtin_choose_expr(1, 1, expr)];
diff --git a/test/Sema/implicit-builtin-decl.c b/test/Sema/implicit-builtin-decl.c
index 09ecd23ca1ba..3d920389a228 100644
--- a/test/Sema/implicit-builtin-decl.c
+++ b/test/Sema/implicit-builtin-decl.c
@@ -22,7 +22,8 @@ void h() {
}
void f2() {
- fprintf(0, "foo"); // expected-error{{implicit declaration of 'fprintf' requires inclusion of the header <stdio.h>}}
+ fprintf(0, "foo"); // expected-error{{implicit declaration of 'fprintf' requires inclusion of the header <stdio.h>}} \
+ expected-warning {{implicit declaration of function 'fprintf' is invalid in C99}}
}
// PR2892
diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c
index fc48895f4eb1..830cde9b9f90 100644
--- a/test/Sema/implicit-decl.c
+++ b/test/Sema/implicit-decl.c
@@ -7,7 +7,8 @@ void func() {
int32_t *vector[16];
const char compDesc[16 + 1];
int32_t compCount = 0;
- if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}}
+ if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-note {{previous implicit declaration is here}} \
+ expected-warning {{implicit declaration of function '_CFCalendarDecomposeAbsoluteTimeV' is invalid in C99}}
}
return ((void *)0); // expected-warning {{void function 'func' should not return a value}}
}
diff --git a/test/Sema/invalid-decl.c b/test/Sema/invalid-decl.c
index 7f471a152681..a5e7ad3b1ec1 100644
--- a/test/Sema/invalid-decl.c
+++ b/test/Sema/invalid-decl.c
@@ -6,7 +6,7 @@ void test() {
// PR2400
-typedef xtype (*x)(void* handle); // expected-error {{function cannot return array or function type}} expected-warning {{type specifier missing, defaults to 'int'}} expected-warning {{type specifier missing, defaults to 'int'}}
+typedef xtype (*x)(void* handle); // expected-error {{function cannot return function type}} expected-warning {{type specifier missing, defaults to 'int'}} expected-warning {{type specifier missing, defaults to 'int'}}
typedef void ytype();
diff --git a/test/Sema/ms-fuzzy-asm.c b/test/Sema/ms-fuzzy-asm.c
index 9ace6569348e..250e3222564d 100644
--- a/test/Sema/ms-fuzzy-asm.c
+++ b/test/Sema/ms-fuzzy-asm.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 %s -verify -fms-extensions
-// XFAIL: *
#define M __asm int 0x2c
#define M2 int
diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c
index 72d3673c825e..ff631ed9c85e 100644
--- a/test/Sema/overloadable.c
+++ b/test/Sema/overloadable.c
@@ -37,9 +37,9 @@ void test_struct(struct X x, struct Y y) {
double *f(int) __attribute__((overloadable)); // expected-error{{conflicting types for 'f'}}
-double promote(float) __attribute__((__overloadable__));
-double promote(double) __attribute__((__overloadable__));
-long double promote(long double) __attribute__((__overloadable__));
+double promote(float) __attribute__((__overloadable__)); // expected-note {{candidate}}
+double promote(double) __attribute__((__overloadable__)); // expected-note {{candidate}}
+long double promote(long double) __attribute__((__overloadable__)); // expected-note {{candidate}}
void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}}
void promote(...) __attribute__((__overloadable__, __unavailable__)); // \
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index f7a7fbd37db3..69c91cb15f47 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -4,14 +4,18 @@
// Test the various warnings under -Wparentheses
void if_assign(void) {
int i;
- if (i = 4) {} // expected-warning {{assignment as a condition}}
+ if (i = 4) {} // expected-warning {{assignment as a condition}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
if ((i = 4)) {}
}
void bitwise_rel(unsigned i) {
- (void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}}
- (void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}}
- (void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}}
+ (void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}} \
+ // expected-note{{place parentheses around the & expression to evaluate it first}}
+ (void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}} \
+ // expected-note{{place parentheses around the & expression to evaluate it first}}
+ (void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}} \
+ // expected-note{{place parentheses around the & expression to evaluate it first}}
(void)((i & 0x2) == 0);
(void)(i & (0x2 == 0));
// Eager logical op
diff --git a/test/Sema/self-comparison.c b/test/Sema/self-comparison.c
index b2b06c209a61..1baba2755f43 100644
--- a/test/Sema/self-comparison.c
+++ b/test/Sema/self-comparison.c
@@ -31,3 +31,8 @@ int compare_enum() {
enum { A };
return A == A; // no-warning
}
+
+// Don't complain in unevaluated contexts.
+int compare_sizeof(int x) {
+ return sizeof(x == x); // no-warning
+}
diff --git a/test/Sema/switch.c b/test/Sema/switch.c
index f815ba4627f9..08ab0e0ebd73 100644
--- a/test/Sema/switch.c
+++ b/test/Sema/switch.c
@@ -76,7 +76,7 @@ void test6() {
}
// PR5606
-int f0(int var) {
+int f0(int var) { // expected-note{{'var' declared here}}
switch (va) { // expected-error{{use of undeclared identifier 'va'}}
case 1:
break;
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index f5c64e6715cd..68503bd6a161 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fno-math-errno %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
int foo(int X, int Y);
-double sqrt(double X); // implicitly const because of -fno-math-errno!
+double sqrt(double X); // implicitly const because of no -fmath-errno!
void bar(volatile int *VP, int *P, int A,
_Complex double C, volatile _Complex double VC) {
@@ -24,7 +24,7 @@ void bar(volatile int *VP, int *P, int A,
__real__ C; // expected-warning {{expression result unused}}
__real__ VC;
- // We know this can't change errno because of -fno-math-errno.
+ // We know this can't change errno because of no -fmath-errno.
sqrt(A); // expected-warning {{ignoring return value of function declared with const attribute}}
}
diff --git a/test/Sema/var-redecl.c b/test/Sema/var-redecl.c
index e67499bcc4c9..71d7ea1baee0 100644
--- a/test/Sema/var-redecl.c
+++ b/test/Sema/var-redecl.c
@@ -50,7 +50,7 @@ void outer_shadowing_test() {
}
}
-void g18(void) {
+void g18(void) { // expected-note{{'g18' declared here}}
extern int g19;
}
int *p=&g19; // expected-error{{use of undeclared identifier 'g19'}} \
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
new file mode 100644
index 000000000000..2c123d0b0fc4
--- /dev/null
+++ b/test/Sema/warn-unreachable.c
@@ -0,0 +1,20 @@
+// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code
+
+void test1() {
+ goto c;
+ d:
+ goto e; // expected-warning {{will never be executed}}
+ c: ;
+ int i;
+ return;
+ goto b; // expected-warning {{will never be executed}}
+ goto a; // expected-warning {{will never be executed}}
+ b:
+ i = 1;
+ a:
+ i = 2;
+ goto f;
+ e:
+ goto d;
+ f: ;
+}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 255b3529823e..ac482151fac1 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -26,3 +26,7 @@ NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'struct NonAggr1' c
NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'struct NonAggr2' cannot be initialized with an initializer list}}
NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'class NonAggr3' cannot be initialized with an initializer list}}
NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'struct NonAggr4' cannot be initialized with an initializer list}}
+
+// PR5817
+typedef int type[][2];
+const type foo = {0};
diff --git a/test/SemaCXX/ambig-user-defined-conversions.cpp b/test/SemaCXX/ambig-user-defined-conversions.cpp
index 0820bc93c39f..5e0a2e3766f8 100644
--- a/test/SemaCXX/ambig-user-defined-conversions.cpp
+++ b/test/SemaCXX/ambig-user-defined-conversions.cpp
@@ -1,52 +1,58 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// Test1
-struct BASE {
- operator int &(); // expected-note {{candidate function}}
-};
-struct BASE1 {
- operator int &(); // expected-note {{candidate function}}
-};
-
-struct B : public BASE, BASE1 {
-
-};
-
-extern B f();
-
-B b1;
-void func(const int ci, const char cc); // expected-note {{candidate function}}
-void func(const char ci, const B b); // expected-note {{candidate function}}
-void func(const B b, const int ci); // expected-note {{candidate function}}
-
-const int Test1() {
- func(b1, f()); // expected-error {{call to 'func' is ambiguous}}
- return f(); // expected-error {{conversion from 'struct B' to 'int const' is ambiguous}}
+namespace test0 {
+ struct BASE {
+ operator int &(); // expected-note {{candidate function}}
+ };
+ struct BASE1 {
+ operator int &(); // expected-note {{candidate function}}
+ };
+
+ struct B : public BASE, BASE1 {};
+
+ extern B f();
+ B b1;
+
+ void func(const int ci, const char cc); // expected-note {{candidate function}}
+ void func(const char ci, const B b); // expected-note {{candidate function}}
+ void func(const B b, const int ci); // expected-note {{candidate function}}
+
+ const int Test1() {
+ func(b1, f()); // expected-error {{call to 'func' is ambiguous}}
+ return f(); // expected-error {{conversion from 'struct test0::B' to 'int const' is ambiguous}}
+ }
+
+ // This used to crash when comparing the two operands.
+ void func2(const char cc); // expected-note {{candidate function}}
+ void func2(const int ci); // expected-note {{candidate function}}
+ void Test2() {
+ func2(b1); // expected-error {{call to 'func2' is ambiguous}}
+ }
}
-
-// Test2
-struct E;
-struct A {
- A (E&);
-};
-
-struct E {
- operator A ();
-};
-
-struct C {
- C (E&);
-};
-
-void f1(A); // expected-note {{candidate function}}
-void f1(C); // expected-note {{candidate function}}
-
-void Test2()
-{
- E b;
- f1(b); // expected-error {{call to 'f1' is ambiguous}}
- // ambiguous because b -> C via constructor and
- // b → A via constructor or conversion function.
+namespace test1 {
+ struct E;
+ struct A {
+ A (E&);
+ };
+
+ struct E {
+ operator A ();
+ };
+
+ struct C {
+ C (E&);
+ };
+
+ void f1(A); // expected-note {{candidate function}}
+ void f1(C); // expected-note {{candidate function}}
+
+ void Test2()
+ {
+ E b;
+ f1(b); // expected-error {{call to 'f1' is ambiguous}}
+ // ambiguous because b -> C via constructor and
+ // b → A via constructor or conversion function.
+ }
}
diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp
index bebd4cb18e5d..8b381dfe4b25 100644
--- a/test/SemaCXX/attr-unavailable.cpp
+++ b/test/SemaCXX/attr-unavailable.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int &foo(int);
-double &foo(double);
+int &foo(int); // expected-note {{candidate}}
+double &foo(double); // expected-note {{candidate}}
void foo(...) __attribute__((__unavailable__)); // expected-note {{candidate function}} \
// expected-note{{function has been explicitly marked unavailable here}}
diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
index 137503b2a4e0..b1b0b98b3c06 100644
--- a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
+++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp
@@ -40,7 +40,7 @@ void foo1(C1 c1, int A::* pmf) {
}
void foo1(C1 c1, int E::* pmf) {
- // FIXME. Error reporting needs much improvement here.
- int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}} \
- // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}}
+ int i = c1->*pmf; // expected-error {{use of overloaded operator '->*' is ambiguous}} \
+ // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}} \
+ // expected-note 4 {{built-in candidate operator}}
}
diff --git a/test/SemaCXX/composite-pointer-type.cpp b/test/SemaCXX/composite-pointer-type.cpp
index 829e64f6c72e..fdf838ffa09a 100644
--- a/test/SemaCXX/composite-pointer-type.cpp
+++ b/test/SemaCXX/composite-pointer-type.cpp
@@ -43,3 +43,10 @@ int f2() {
IntPtrPtr j = 0;
return i != j;
}
+
+// PR5763
+typedef double Matrix4[4][4];
+
+bool f(Matrix4 m1, const Matrix4 m2) {
+ return m1 != m2;
+}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index a0b57e1baa53..fe802d0555ed 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -16,8 +16,8 @@ void test() {
for (;s;) ; // expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}}
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
- while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate function}}
- while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}} expected-note{{candidate function}}
+ while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct S' is not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
+ while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{no viable conversion}} expected-error {{value of type 'struct <anonymous>' is not contextually convertible to 'bool'}} expected-note{{candidate constructor (the implicit copy constructor)}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}}
if (int x=0) { // expected-note 2 {{previous definition is here}}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 0617cd5702c6..b71133bfeec8 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -7,8 +7,8 @@
struct ToBool { explicit operator bool(); };
struct B;
-struct A { A(); A(const B&); };
-struct B { operator A() const; };
+struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
+struct B { operator A() const; }; // expected-note 2 {{candidate function}}
struct I { operator int(); };
struct J { operator I(); };
struct K { operator double(); };
@@ -50,8 +50,8 @@ struct MixedFieldsDerived : MixedFields {
enum Enum { EVal };
struct Ambig {
- operator short();
- operator signed char();
+ operator short(); // expected-note 2 {{candidate function}}
+ operator signed char(); // expected-note 2 {{candidate function}}
};
void test()
@@ -128,11 +128,10 @@ void test()
// "the type [it] woud have if E2 were converted to an rvalue"
vfn pfn = i1 ? F() : test;
pfn = i1 ? test : F();
- // these are ambiguous - better messages would be nice
- (void)(i1 ? A() : B()); // expected-error {{incompatible operand types}}
- (void)(i1 ? B() : A()); // expected-error {{incompatible operand types}}
- (void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}}
- (void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}}
+ (void)(i1 ? A() : B()); // expected-error {{conversion from 'struct B' to 'struct A' is ambiguous}}
+ (void)(i1 ? B() : A()); // expected-error {{conversion from 'struct B' to 'struct A' is ambiguous}}
+ (void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'struct Ambig' to 'int' is ambiguous}}
+ (void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'struct Ambig' to 'int' is ambiguous}}
// By the way, this isn't an lvalue:
&(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index 67d4074cbcdc..53f057ed0f35 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -97,13 +97,10 @@ struct Current : Derived {
// expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
};
- // FIXME. This is bad message!
-struct M { // expected-note {{candidate function}} \
- // expected-note {{candidate function}} \
+struct M { // expected-note 2 {{candidate constructor (the implicit copy constructor)}} \
// expected-note {{declared here}} \
// expected-note {{declared here}}
- M(int i, int j); // expected-note {{candidate function}} \
- // // expected-note {{candidate function}}
+ M(int i, int j); // expected-note 2 {{candidate constructor}}
};
struct N : M {
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index db322f4a3d34..4fef172bd5a1 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -56,9 +56,9 @@ public:
// This used to crash Clang.
struct Flip;
-struct Flop { // expected-note{{candidate function}}
+struct Flop { // expected-note{{candidate is the implicit copy constructor}}
Flop();
- Flop(const Flip&); // expected-note{{candidate function}}
+ Flop(const Flip&); // expected-note{{candidate constructor}}
};
struct Flip {
operator Flop() const; // expected-note{{candidate function}}
diff --git a/test/SemaCXX/converting-constructor.cpp b/test/SemaCXX/converting-constructor.cpp
index e78798b82cb7..1688e51e73fd 100644
--- a/test/SemaCXX/converting-constructor.cpp
+++ b/test/SemaCXX/converting-constructor.cpp
@@ -27,7 +27,7 @@ public:
FromShort(short s);
};
-class FromShortExplicitly { // expected-note{{candidate function}}
+class FromShortExplicitly { // expected-note{{candidate constructor (the implicit copy constructor)}}
public:
explicit FromShortExplicitly(short s);
};
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
index ad149232a4e3..2cf878a84411 100644
--- a/test/SemaCXX/copy-initialization.cpp
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -2,7 +2,7 @@
class X {
public:
explicit X(const X&);
- X(int*); // expected-note 2{{candidate function}}
+ X(int*); // expected-note 2{{candidate constructor}}
explicit X(float*);
};
diff --git a/test/SemaCXX/dcl_init_aggr.cpp b/test/SemaCXX/dcl_init_aggr.cpp
index 87b51e32e5cf..07ddb0add2ca 100644
--- a/test/SemaCXX/dcl_init_aggr.cpp
+++ b/test/SemaCXX/dcl_init_aggr.cpp
@@ -40,9 +40,9 @@ char cv[4] = { 'a', 's', 'd', 'f', 0 }; // expected-error{{excess elements in ar
struct TooFew { int a; char* b; int c; };
TooFew too_few = { 1, "asdf" }; // okay
-struct NoDefaultConstructor { // expected-note 3 {{candidate function}} \
+struct NoDefaultConstructor { // expected-note 3 {{candidate constructor (the implicit copy constructor)}} \
// expected-note{{declared here}}
- NoDefaultConstructor(int); // expected-note 3 {{candidate function}}
+ NoDefaultConstructor(int); // expected-note 3 {{candidate constructor}}
};
struct TooFewError { // expected-error{{implicit default constructor for}}
int a;
@@ -115,7 +115,7 @@ B2 b2_2 = { 4, d2, 0 };
B2 b2_3 = { c2, a2, a2 };
// C++ [dcl.init.aggr]p15:
-union u { int a; char* b; }; // expected-note{{candidate function}}
+union u { int a; char* b; }; // expected-note{{candidate constructor (the implicit copy constructor)}}
u u1 = { 1 };
u u2 = u1;
u u3 = 1; // expected-error{{no viable conversion}}
diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp
index 294543f495db..656f3436a0c3 100644
--- a/test/SemaCXX/decl-init-ref.cpp
+++ b/test/SemaCXX/decl-init-ref.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
-struct A {}; // expected-note {{candidate function}}
+struct A {}; // expected-note {{candidate is the implicit copy constructor}}
struct BASE {
operator A(); // expected-note {{candidate function}}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index 880255e4531b..d2c44bd998a0 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -82,7 +82,7 @@ int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member '
// constructors.
class Z {
public:
- Z(Z&, int i = 17); // expected-note 3 {{candidate function}}
+ Z(Z&, int i = 17); // expected-note 3 {{candidate constructor}}
void f(Z& z) {
Z z2; // expected-error{{no matching constructor for initialization}}
@@ -103,7 +103,7 @@ struct ZZ {
void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}}
- ZZ(ZZ&, int = 17); // expected-note{{candidate function}}
+ ZZ(ZZ&, int = 17); // expected-note{{candidate constructor}}
};
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325
diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp
index 03a5da3a303b..6601a3dd0d92 100644
--- a/test/SemaCXX/direct-initializer.cpp
+++ b/test/SemaCXX/direct-initializer.cpp
@@ -13,16 +13,16 @@ class Y {
explicit Y(float);
};
-class X { // expected-note{{candidate function}}
+class X { // expected-note{{candidate constructor (the implicit copy constructor)}}
public:
- explicit X(int); // expected-note{{candidate function}}
- X(float, float, float); // expected-note{{candidate function}}
- X(float, Y); // expected-note{{candidate function}}
+ explicit X(int); // expected-note{{candidate constructor}}
+ X(float, float, float); // expected-note{{candidate constructor}}
+ X(float, Y); // expected-note{{candidate constructor}}
};
-class Z { // expected-note{{candidate function}}
+class Z { // expected-note{{candidate constructor (the implicit copy constructor)}}
public:
- Z(int); // expected-note{{candidate function}}
+ Z(int); // expected-note{{candidate constructor}}
};
void g() {
diff --git a/test/SemaCXX/functional-cast.cpp b/test/SemaCXX/functional-cast.cpp
index 63be77008cb4..0bef0cd6be4c 100644
--- a/test/SemaCXX/functional-cast.cpp
+++ b/test/SemaCXX/functional-cast.cpp
@@ -10,10 +10,8 @@ struct InitViaConstructor {
InitViaConstructor(int i = 7);
};
-// FIXME: error messages for implicitly-declared special member
-// function candidates are very poor
-struct NoValueInit { // expected-note 2 {{candidate function}}
- NoValueInit(int i, int j); // expected-note 2 {{candidate function}}
+struct NoValueInit { // expected-note 2 {{candidate constructor (the implicit copy constructor)}}
+ NoValueInit(int i, int j); // expected-note 2 {{candidate constructor}}
};
void test_cxx_functional_value_init() {
diff --git a/test/SemaCXX/implicit-virtual-member-functions.cpp b/test/SemaCXX/implicit-virtual-member-functions.cpp
index a6b1f8c537d2..4ae9eae3b316 100644
--- a/test/SemaCXX/implicit-virtual-member-functions.cpp
+++ b/test/SemaCXX/implicit-virtual-member-functions.cpp
@@ -15,15 +15,15 @@ void B::f() { // expected-note {{implicit default destructor for 'struct B' firs
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
C();
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-};
+}; // expected-note {{implicit default destructor for 'struct C' first required here}}
-C::C() { } // expected-note {{implicit default destructor for 'struct C' first required here}}
+C::C() { }
struct D : A { // expected-error {{no suitable member 'operator delete' in 'D'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-};
+}; // expected-note {{implicit default destructor for 'struct D' first required here}}
void f() {
- new D; // expected-note {{implicit default destructor for 'struct D' first required here}}
+ new D;
}
diff --git a/test/SemaCXX/literal-operators.cpp b/test/SemaCXX/literal-operators.cpp
new file mode 100644
index 000000000000..ec585a61da9f
--- /dev/null
+++ b/test/SemaCXX/literal-operators.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+#include <stddef.h>
+
+struct tag {
+ void operator "" tag_bad (const char *); // expected-error {{literal operator 'operator "" tag_bad' must be in a namespace or global scope}}
+ friend void operator "" tag_good (const char *);
+};
+
+namespace ns { void operator "" ns_good (const char *); }
+
+// Check extern "C++" declarations
+extern "C++" void operator "" extern_good (const char *);
+extern "C++" { void operator "" extern_good (const char *); }
+
+void fn () { void operator "" fn_bad (const char *); } // expected-error {{literal operator 'operator "" fn_bad' must be in a namespace or global scope}}
+
+// One-param declarations (const char * was already checked)
+void operator "" good (char);
+void operator "" good (wchar_t);
+void operator "" good (char16_t);
+void operator "" good (char32_t);
+void operator "" good (unsigned long long);
+void operator "" good (long double);
+
+// Two-param declarations
+void operator "" good (const char *, size_t);
+void operator "" good (const wchar_t *, size_t);
+void operator "" good (const char16_t *, size_t);
+void operator "" good (const char32_t *, size_t);
+
+// Check typedef and array equivalences
+void operator "" good (const char[]);
+typedef const char c;
+void operator "" good (c*);
+
+// Check extra cv-qualifiers
+void operator "" cv_good (volatile const char *, const size_t);
+
+// Template delcaration (not implemented yet)
+// template <char...> void operator "" good ();
+
+// FIXME: Test some invalid decls that might crop up.
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 65d05eb5af74..3d9d5b5ebbbc 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -80,7 +80,7 @@ void g() {
void (HasMembers::*pmf)() = &HasMembers::f;
void (*pnf)() = &Fake::f;
- &hm.f; // FIXME: needs diagnostic expected-warning{{result unused}}
+ &hm.f; // expected-error {{must explicitly qualify}} expected-warning{{result unused}}
void (HasMembers::*pmgv)() = &HasMembers::g;
void (HasMembers::*pmgi)(int) = &HasMembers::g;
@@ -136,3 +136,15 @@ void i() {
OverloadsPtrMem m;
int foo = m->*"Awesome!";
}
+
+namespace pr5985 {
+ struct c {
+ void h();
+ void f() {
+ void (c::*p)();
+ p = &h; // expected-error {{must explicitly qualify}}
+ p = &this->h; // expected-error {{must explicitly qualify}}
+ p = &(*this).h; // expected-error {{must explicitly qualify}}
+ }
+ };
+}
diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp
index ab690b7286ec..2a9d31fa945a 100644
--- a/test/SemaCXX/namespace.cpp
+++ b/test/SemaCXX/namespace.cpp
@@ -9,7 +9,7 @@ int A; // expected-error {{redefinition of 'A' as different kind of symbol}}
class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
class B {}; // expected-note {{previous definition is here}} \
- // FIXME: ugly expected-note{{candidate function}}
+ // expected-note{{candidate function (the implicit copy assignment operator)}}
void C(); // expected-note {{previous definition is here}}
namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 4e65b41e666c..8618f0339bca 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -178,7 +178,7 @@ bool (foo_S::value);
namespace somens {
- struct a { }; // expected-note{{candidate function}}
+ struct a { }; // expected-note{{candidate constructor (the implicit copy constructor)}}
}
template <typename T>
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 299c0a78f926..d20bf23b8fd9 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -301,3 +301,35 @@ namespace PR5756 {
(void)ir;
}
}
+
+// Tests the exact text used to note the candidates
+namespace test1 {
+ template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for 2nd argument}}
+ void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for 2nd argument}}
+ void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}}
+ void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}}
+ void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
+ void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+ void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+
+ void test() {
+ foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}}
+ }
+}
+
+// PR 6014
+namespace test2 {
+ struct QFixed {
+ QFixed(int i);
+ QFixed(long i);
+ };
+
+ bool operator==(const QFixed &f, int i);
+
+ class qrgb666 {
+ inline operator unsigned int () const;
+
+ inline bool operator==(const qrgb666 &v) const;
+ inline bool operator!=(const qrgb666 &v) const { return !(*this == v); }
+ };
+}
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
index 4bb3ff3a54cd..22416f3ea48e 100644
--- a/test/SemaCXX/overload-member-call.cpp
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -66,3 +66,33 @@ void test_X2(X2 *x2p, const X2 *cx2p) {
int &ir = x2p->member();
float &fr = cx2p->member();
}
+
+// Tests the exact text used to note the candidates
+namespace test1 {
+ class A {
+ template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for 2nd argument}}
+ void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for 2nd argument}}
+ void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}}
+ void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}}
+ void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
+ void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+ void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
+
+ void bar(double d); //expected-note {{candidate function not viable: 'this' argument has type 'class test1::A const', but method is not marked const}}
+ void bar(int i); //expected-note {{candidate function not viable: 'this' argument has type 'class test1::A const', but method is not marked const}}
+
+ void baz(A &d); // expected-note {{candidate function not viable: 1st argument ('class test1::A const') would lose const qualifier}}
+ void baz(int i); // expected-note {{candidate function not viable: no known conversion from 'class test1::A const' to 'int' for 1st argument}}
+ };
+
+ void test() {
+ A a;
+ a.foo(4, "hello"); //expected-error {{no matching member function for call to 'foo'}}
+
+ const A b;
+ b.bar(0); //expected-error {{no matching member function for call to 'bar'}}
+
+ a.baz(b); //expected-error {{no matching member function for call to 'baz'}}
+ }
+}
+
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 12903cc7facf..61c2e2110a99 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -59,7 +59,7 @@ void f(Short s, Long l, Enum1 e1, Enum2 e2, Xpmf pmf) {
// FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
}
-struct ShortRef { // expected-note{{candidate function}}
+struct ShortRef { // expected-note{{candidate function (the implicit copy assignment operator)}}
operator short&();
};
@@ -67,7 +67,7 @@ struct LongRef {
operator volatile long&();
};
-struct XpmfRef { // expected-note{{candidate function}}
+struct XpmfRef { // expected-note{{candidate function (the implicit copy assignment operator)}}
operator pmf&();
};
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index a20c69b8d5d1..861d679c7261 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -190,16 +190,23 @@ typedef INTREF Func1(FLOAT, double);
typedef float& Func2(int, double);
struct ConvertToFunc {
- operator Func1*(); // expected-note{{conversion candidate of type 'INTREF (*)(FLOAT, double)'}}
- operator Func2&(); // expected-note{{conversion candidate of type 'float &(&)(int, double)'}}
+ operator Func1*(); // expected-note 2{{conversion candidate of type 'INTREF (*)(FLOAT, double)'}}
+ operator Func2&(); // expected-note 2{{conversion candidate of type 'float &(&)(int, double)'}}
void operator()();
};
-void test_funcptr_call(ConvertToFunc ctf) {
+struct ConvertToFuncDerived : ConvertToFunc { };
+
+void test_funcptr_call(ConvertToFunc ctf, ConvertToFuncDerived ctfd) {
int &i1 = ctf(1.0f, 2.0);
- float &f2 = ctf((short int)1, 1.0f);
+ float &f1 = ctf((short int)1, 1.0f);
ctf((long int)17, 2.0); // expected-error{{error: call to object of type 'struct ConvertToFunc' is ambiguous; candidates are:}}
ctf();
+
+ int &i2 = ctfd(1.0f, 2.0);
+ float &f2 = ctfd((short int)1, 1.0f);
+ ctfd((long int)17, 2.0); // expected-error{{error: call to object of type 'struct ConvertToFuncDerived' is ambiguous; candidates are:}}
+ ctfd();
}
struct HasMember {
@@ -324,3 +331,27 @@ namespace pr5512 {
a += x;
}
}
+
+// PR5900
+namespace pr5900 {
+ struct NotAnArray {};
+ void test0() {
+ NotAnArray x;
+ x[0] = 0; // expected-error {{does not provide a subscript operator}}
+ }
+
+ struct NonConstArray {
+ int operator[](unsigned); // expected-note {{candidate}}
+ };
+ int test1() {
+ const NonConstArray x;
+ return x[0]; // expected-error {{no viable overloaded operator[] for type}}
+ }
+
+ // Not really part of this PR, but implemented at the same time.
+ struct NotAFunction {};
+ void test2() {
+ NotAFunction x;
+ x(); // expected-error {{does not provide a call operator}}
+ }
+}
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 7ff3d584c02e..2a7fb25c62a9 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -65,10 +65,10 @@ int&& should_not_warn(int&& i) { // But GCC 4.4 does
// Test the return dance. This also tests IsReturnCopyElidable.
struct MoveOnly {
MoveOnly();
- MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate function}} \
+ MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate constructor}} \
// expected-note 3{{explicitly marked deleted here}}
- MoveOnly(MoveOnly&&); // expected-note {{candidate function}}
- MoveOnly(int&&); // expected-note {{candidate function}}
+ MoveOnly(MoveOnly&&); // expected-note {{candidate constructor}}
+ MoveOnly(int&&); // expected-note {{candidate constructor}}
};
MoveOnly gmo;
diff --git a/test/SemaCXX/unreachable-code.cpp b/test/SemaCXX/unreachable-code.cpp
new file mode 100644
index 000000000000..528bba7d5e15
--- /dev/null
+++ b/test/SemaCXX/unreachable-code.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunreachable-code -fblocks -verify %s
+
+int j;
+void bar() { }
+int test1() {
+ for (int i = 0;
+ i != 10;
+ ++i) { // expected-warning {{will never be executed}}
+ if (j == 23) // missing {}'s
+ bar();
+ return 1;
+ }
+ return 0;
+ return 1; // expected-warning {{will never be executed}}
+}
+
+void test2(int i) {
+ switch (i) {
+ case 0:
+ break;
+ bar(); // expected-warning {{will never be executed}}
+ case 2:
+ switch (i) {
+ default:
+ a: goto a;
+ }
+ bar(); // expected-warning {{will never be executed}}
+ }
+ b: goto b;
+ bar(); // expected-warning {{will never be executed}}
+}
+
+void test3() {
+ ^{ return;
+ bar(); // expected-warning {{will never be executed}}
+ }();
+ while (++j) {
+ continue;
+ bar(); // expected-warning {{will never be executed}}
+ }
+}
diff --git a/test/SemaCXX/virtual-member-functions-key-function.cpp b/test/SemaCXX/virtual-member-functions-key-function.cpp
index 3d048595e94e..2e21fb7365e9 100644
--- a/test/SemaCXX/virtual-member-functions-key-function.cpp
+++ b/test/SemaCXX/virtual-member-functions-key-function.cpp
@@ -4,19 +4,26 @@ struct A {
};
struct B : A { // expected-error {{no suitable member 'operator delete' in 'B'}}
- B() { } // expected-note {{implicit default destructor for 'struct B' first required here}}
+ B() { }
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-};
+}; // expected-note {{implicit default destructor for 'struct B' first required here}}
struct C : A { // expected-error {{no suitable member 'operator delete' in 'C'}}
void operator delete(void *, int); // expected-note {{'operator delete' declared here}}
-};
+}; // expected-note {{implicit default destructor for 'struct C' first required here}}
void f() {
- // new B should mark the constructor as used, which then marks
- // all the virtual members as used, because B has no key function.
(void)new B;
-
- // Same here, except that C has an implicit constructor.
- (void)new C; // expected-note {{implicit default destructor for 'struct C' first required here}}
+ (void)new C;
}
+
+// Make sure that the key-function computation is consistent when the
+// first virtual member function of a nested class has an inline body.
+struct Outer {
+ struct Inner {
+ virtual void f() { }
+ void g();
+ };
+};
+
+void Outer::Inner::g() { }
diff --git a/test/SemaCXX/warn-assignment-condition.cpp b/test/SemaCXX/warn-assignment-condition.cpp
index 1df906dd7ec6..ce16a68a77ef 100644
--- a/test/SemaCXX/warn-assignment-condition.cpp
+++ b/test/SemaCXX/warn-assignment-condition.cpp
@@ -11,26 +11,34 @@ void test() {
A a, b;
// With scalars.
- if (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
if ((x = 7)) {}
do {
- } while (x = 7); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ } while (x = 7); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
do {
} while ((x = 7));
- while (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while (x = 7) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
while ((x = 7)) {}
- for (; x = 7; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; x = 7; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
for (; (x = 7); ) {}
- if (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
if ((p = p)) {}
do {
- } while (p = p); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ } while (p = p); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
do {
} while ((p = p));
- while (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while (p = p) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
while ((p = p)) {}
- for (; p = p; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; p = p; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
for (; (p = p); ) {}
// Initializing variables (shouldn't warn).
@@ -40,26 +48,34 @@ void test() {
while (A y = a) {}
// With temporaries.
- if (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
if ((x = (b+b).foo())) {}
do {
- } while (x = (b+b).foo()); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ } while (x = (b+b).foo()); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
do {
} while ((x = (b+b).foo()));
- while (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while (x = (b+b).foo()) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
while ((x = (b+b).foo())) {}
- for (; x = (b+b).foo(); ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; x = (b+b).foo(); ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
for (; (x = (b+b).foo()); ) {}
// With a user-defined operator.
- if (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ if (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
if ((a = b + b)) {}
do {
- } while (a = b + b); // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ } while (a = b + b); // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
do {
} while ((a = b + b));
- while (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ while (a = b + b) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
while ((a = b + b)) {}
- for (; a = b + b; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}}
+ for (; a = b + b; ) {} // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note{{use '==' to turn this assignment into an equality comparison}}
for (; (a = b + b); ) {}
}
diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m
index 094c12f7d81b..33e163086475 100644
--- a/test/SemaObjC/bad-receiver-1.m
+++ b/test/SemaObjC/bad-receiver-1.m
@@ -4,6 +4,8 @@
- (id) retain;
@end
+int objc_lookUpClass(const char*);
+
void __raiseExc1() {
[objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} \
expected-warning {{method '-retain' not found}}
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
index 17c6b4620274..33e4646837a0 100644
--- a/test/SemaObjC/category-1.m
+++ b/test/SemaObjC/category-1.m
@@ -29,7 +29,7 @@
@interface MyClass1 (Category) <p2, p3> @end // expected-warning {{cannot find protocol definition for 'p2'}}
-@interface MyClass (Category) @end // expected-error {{cannot find interface declaration for 'MyClass'}}
+@interface UnknownClass (Category) @end // expected-error {{cannot find interface declaration for 'UnknownClass'}}
@class MyClass2;
diff --git a/test/SemaObjC/continuation-class-property.m b/test/SemaObjC/continuation-class-property.m
new file mode 100644
index 000000000000..c48a23d62a9b
--- /dev/null
+++ b/test/SemaObjC/continuation-class-property.m
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// radar 7509234
+
+@protocol Foo
+@property (readonly, copy) id foos;
+@end
+
+@interface Bar <Foo> {
+}
+
+@end
+
+@interface Baz <Foo> {
+}
+@end
+
+@interface Bar ()
+@property (readwrite, copy) id foos;
+@end
+
+@interface Baz ()
+@property (readwrite, copy) id foos;
+@end
+
diff --git a/test/SemaObjC/ivar-access-package.m b/test/SemaObjC/ivar-access-package.m
index 956ae5bdb6cc..abc3420f1bd2 100644
--- a/test/SemaObjC/ivar-access-package.m
+++ b/test/SemaObjC/ivar-access-package.m
@@ -34,6 +34,8 @@ typedef unsigned char BOOL;
}
@end
+void NSLog(id, ...);
+
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
A *a = [[A new] autorelease];
diff --git a/test/SemaObjC/ivar-lookup-resolution-builtin.m b/test/SemaObjC/ivar-lookup-resolution-builtin.m
new file mode 100644
index 000000000000..2e90e8e04425
--- /dev/null
+++ b/test/SemaObjC/ivar-lookup-resolution-builtin.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// pr5986
+
+@interface Test {
+ int index;
+}
+- (int) index;
++ (int) ClassMethod;
+@end
+
+@implementation Test
+- (int) index
+{
+ return index;
+}
++ (int) ClassMethod
+{
+ return index; // expected-error {{instance variable 'index' accessed in class method}}
+}
+@end
+
+@interface Test1 {
+}
+- (int) InstMethod;
++ (int) ClassMethod;
+@end
+
+@implementation Test1
+- (int) InstMethod
+{
+ return index; // expected-warning {{implicitly declaring C library function 'index'}} \
+ // expected-note {{please include the header <strings.h> or explicitly provide a declaration for 'index'}} \
+ // expected-warning {{incompatible pointer to integer conversion returning}}
+}
++ (int) ClassMethod
+{
+ return index; // expected-warning {{incompatible pointer to integer conversion returning}}
+}
+@end
+
diff --git a/test/SemaObjC/nonnull.m b/test/SemaObjC/nonnull.m
index c96a91a7f815..642f50f9e4d6 100644
--- a/test/SemaObjC/nonnull.m
+++ b/test/SemaObjC/nonnull.m
@@ -19,6 +19,9 @@ __attribute__((nonnull(1,3)));
extern void func4 (void (^block1)(), void (^block2)()) __attribute__((nonnull(1)))
__attribute__((nonnull(2)));
+void func6();
+void func7();
+
void
foo (int i1, int i2, int i3, void (^cp1)(), void (^cp2)(), void (^cp3)())
{
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
index 138f09953d5a..d527a9c9f30b 100644
--- a/test/SemaObjC/property-9.m
+++ b/test/SemaObjC/property-9.m
@@ -84,3 +84,15 @@ typedef signed char BOOL;
view.inEyeDropperMode = 1;
}
@end
+
+// radar 7427072
+@interface MyStyleIntf
+{
+ int _myStyle;
+}
+
+@property(readonly) int myStyle;
+
+- (float)setMyStyle:(int)style;
+@end
+
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 108a72988e21..138c43d1a83a 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -5,6 +5,7 @@
- (void) bar;
@end
+void bar();
void foo(id x) {
bar((short<SomeProtocol>)x); // expected-error {{expected ')'}} expected-note {{to match this '('}}
bar((<SomeProtocol>)x); // expected-warning {{protocol qualifiers without 'id' is archaic}}
diff --git a/test/SemaObjC/undef-class-messagin-error.m b/test/SemaObjC/undef-class-messagin-error.m
index 0a400dd39f5f..63e0b9dec329 100644
--- a/test/SemaObjC/undef-class-messagin-error.m
+++ b/test/SemaObjC/undef-class-messagin-error.m
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface _Child
+@interface _Child // expected-note{{'_Child' declared here}}
+ (int) flashCache;
@end
-@interface Child (Categ) // expected-error {{cannot find interface declaration for 'Child'}}
+@interface Child (Categ) // expected-error {{cannot find interface declaration for 'Child'; did you mean '_Child'?}}
+ (int) flushCache2;
@end
-@implementation Child (Categ) // expected-error {{cannot find interface declaration for 'Child'}}
+@implementation OtherChild (Categ) // expected-error {{cannot find interface declaration for 'OtherChild'}}
+ (int) flushCache2 { [super flashCache]; } // expected-error {{no @interface declaration found in class messaging of 'flushCache2'}}
@end
diff --git a/test/SemaObjC/undef-superclass-1.m b/test/SemaObjC/undef-superclass-1.m
index 7611cf3b1554..0c2594cc226a 100644
--- a/test/SemaObjC/undef-superclass-1.m
+++ b/test/SemaObjC/undef-superclass-1.m
@@ -13,7 +13,8 @@
@interface INTF2 : INTF1
@end
-@interface INTF3 : Y // expected-error {{cannot find interface declaration for 'Y', superclass of 'INTF3'}}
+@interface INTF3 : Y // expected-error {{cannot find interface declaration for 'Y', superclass of 'INTF3'}} \
+ // expected-note{{'INTF3' declared here}}
@end
@interface INTF1 // expected-error {{duplicate interface definition for class 'INTF1'}}
@@ -31,3 +32,5 @@
@implementation RecursiveClass
@end
+@implementation iNTF3 // expected-warning{{cannot find interface declaration for 'iNTF3'; did you mean 'INTF3'?}}
+@end
diff --git a/test/SemaTemplate/ambiguous-ovl-print.cpp b/test/SemaTemplate/ambiguous-ovl-print.cpp
index 17f412f6716d..7e3fa24197eb 100644
--- a/test/SemaTemplate/ambiguous-ovl-print.cpp
+++ b/test/SemaTemplate/ambiguous-ovl-print.cpp
@@ -2,7 +2,7 @@
void f(void*, int); // expected-note{{candidate function}}
template<typename T>
- void f(T*, long); // expected-note{{candidate function template}}
+ void f(T*, long); // expected-note{{candidate function}}
void test_f(int *ip, int i) {
f(ip, i); // expected-error{{ambiguous}}
diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp
index 139de9d68605..82c2aa4cc3e7 100644
--- a/test/SemaTemplate/constructor-template.cpp
+++ b/test/SemaTemplate/constructor-template.cpp
@@ -52,8 +52,8 @@ template <> struct A<int>{A(const A<int>&);};
struct B { A<int> x; B(B& a) : x(a.x) {} };
struct X2 {
- X2(); // expected-note{{candidate function}}
- X2(X2&); // expected-note {{candidate function}}
+ X2(); // expected-note{{candidate constructor}}
+ X2(X2&); // expected-note {{candidate constructor}}
template<typename T> X2(T);
};
@@ -71,9 +71,9 @@ struct X3 {
template<> X3::X3(X3); // expected-error{{must pass its first argument by reference}}
struct X4 {
- X4(); // expected-note{{candidate function}}
+ X4(); // expected-note{{candidate constructor}}
~X4();
- X4(X4&); // expected-note {{candidate function}}
+ X4(X4&); // expected-note {{candidate constructor}}
template<typename T> X4(const T&, int = 17);
};
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index 0edc504ea0a3..131b80cb1f36 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -5,7 +5,7 @@ class C { C(int a0 = 0); };
template<>
C<char>::C(int a0);
-struct S { }; // expected-note 3 {{candidate function}}
+struct S { }; // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
template<typename T> void f1(T a, T b = 10) { } // expected-error{{no viable conversion}}
diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp
new file mode 100644
index 000000000000..79b28c2239fe
--- /dev/null
+++ b/test/SemaTemplate/dependent-base-classes.cpp
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X0 : T::template apply<U> {
+ X0(U u) : T::template apply<U>(u) { }
+};
+
+template<typename T, typename U>
+struct X1 : T::apply<U> { }; // expected-error{{missing 'template' keyword prior to dependent template name 'T::apply'}}
+
+template<typename T>
+struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}}
+
+namespace PR6031 {
+ template<typename T>
+ struct A;
+
+ template <class X>
+ struct C { };
+
+ template <class TT>
+ struct II {
+ typedef typename A<TT>::type type;
+ };
+
+ template <class TT>
+ struct FI : II<TT>
+ {
+ C<typename FI::type> a;
+ };
+
+ template <class TT>
+ struct FI2
+ {
+ C<typename FI2::type> a; // expected-error{{no type named 'type' in 'struct PR6031::FI2'}} \
+ // expected-error{{C++ requires a type specifier for all declarations}}
+ };
+
+ template<typename T>
+ struct Base {
+ class Nested { };
+ template<typename U> struct MemberTemplate { };
+ int a;
+ };
+
+ template<typename T>
+ struct HasDepBase : Base<T> {
+ int foo() {
+ class HasDepBase::Nested nested;
+ typedef typename HasDepBase::template MemberTemplate<T>::type type;
+ return HasDepBase::a;
+ }
+ };
+
+ template<typename T>
+ struct NoDepBase {
+ int foo() {
+ class NoDepBase::Nested nested; // expected-error{{'Nested' does not name a tag member in the specified scope}}
+ typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \
+ // FIXME: expected-error{{expected an identifier or template-id after '::'}} \
+ // FIXME: expected-error{{unqualified-id}}
+ return NoDepBase::a; // expected-error{{no member named 'a' in 'struct PR6031::NoDepBase'}}
+ }
+ };
+}
+
+namespace Ambig {
+ template<typename T>
+ struct Base1 {
+ typedef int type; // expected-note{{member found by ambiguous name lookup}}
+ };
+
+ struct Base2 {
+ typedef float type; // expected-note{{member found by ambiguous name lookup}}
+ };
+
+ template<typename T>
+ struct Derived : Base1<T>, Base2 {
+ typedef typename Derived::type type; // expected-error{{member 'type' found in multiple base classes of different types}}
+ type *foo(float *fp) { return fp; }
+ };
+
+ Derived<int> di; // expected-note{{instantiation of}}
+}
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index fbb5edbefd6c..227856f1a8e2 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -25,8 +25,8 @@ T X0<T>::value; // expected-error{{no matching constructor}}
template int X0<int>::value;
-struct NotDefaultConstructible { // expected-note{{candidate function}}
- NotDefaultConstructible(int); // expected-note{{candidate function}}
+struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}}
+ NotDefaultConstructible(int); // expected-note{{candidate constructor}}
};
template NotDefaultConstructible X0<NotDefaultConstructible>::value; // expected-note{{instantiation}}
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
index 0c2cf9c4f2e6..1c9b232f6d36 100644
--- a/test/SemaTemplate/fun-template-def.cpp
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -8,7 +8,7 @@
// Fake typeid, lacking a typeinfo header.
namespace std { class type_info {}; }
-struct dummy {}; // expected-note 3 {{candidate function}}
+struct dummy {}; // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
template<typename T>
int f0(T x) {
diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp
index 91989b1ccae0..9afc99fe7d5e 100644
--- a/test/SemaTemplate/function-template-specialization.cpp
+++ b/test/SemaTemplate/function-template-specialization.cpp
@@ -33,3 +33,11 @@ template<> void f2<double>(double (&array)[42]);
template<> void f2<42>(double (&array)[42]);
void f2<25>(double (&array)[25]); // expected-error{{specialization}}
+
+// PR5833
+namespace PR5833 {
+ template <typename T> bool f0(T &t1);
+ template <> bool f0<float>(float &t1);
+}
+template <> bool PR5833::f0<float>(float &t1) {}
+
diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp
index 1a65aeb3d6cb..482eae14ba59 100644
--- a/test/SemaTemplate/injected-class-name.cpp
+++ b/test/SemaTemplate/injected-class-name.cpp
@@ -11,11 +11,7 @@ struct X<int***> {
typedef X<int***> *ptr;
};
-// FIXME: EDG rejects this in their strict-conformance mode, but I
-// don't see any wording making this ill-formed. Actually,
-// [temp.local]p2 might make it ill-formed. Are we "in the scope of
-// the class template specialization?"
-X<float>::X<int> xi = x;
+X<float>::X<int> xi = x; // expected-error{{qualified reference to 'X' is a constructor name rather than a template name wherever a constructor can be declared}}
// [temp.local]p1:
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index c524e958f8a7..428ef1ba8736 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -21,8 +21,8 @@ struct FunctionalCast0 {
template struct FunctionalCast0<5>;
-struct X { // expected-note 3 {{candidate function}}
- X(int, int); // expected-note 3 {{candidate function}}
+struct X { // expected-note 3 {{candidate constructor (the implicit copy constructor)}}
+ X(int, int); // expected-note 3 {{candidate constructor}}
};
template<int N, int M>
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 8a19d74cdde4..742abcc569c2 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -14,8 +14,8 @@ public:
X<int>::C *c1;
X<float>::C *c2;
-X<int>::X *xi;
-X<float>::X *xf;
+X<int>::X *xi; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
+X<float>::X *xf; // expected-error{{qualified reference to 'X' is a constructor name rather than a type wherever a constructor can be declared}}
void test_naming() {
c1 = c2; // expected-error{{incompatible type assigning 'X<float>::C *', expected 'X<int>::C *'}}
diff --git a/test/SemaTemplate/instantiate-member-expr.cpp b/test/SemaTemplate/instantiate-member-expr.cpp
index db13624d4426..324363ce96dc 100644
--- a/test/SemaTemplate/instantiate-member-expr.cpp
+++ b/test/SemaTemplate/instantiate-member-expr.cpp
@@ -25,3 +25,27 @@ class RetainReleaseChecker { };
void f(GRExprEngine& Eng) {
Eng.registerCheck(new RetainReleaseChecker); // expected-note {{in instantiation of function template specialization 'GRExprEngine::registerCheck<class RetainReleaseChecker>' requested here}}
}
+
+// PR 5838
+namespace test1 {
+ template<typename T> struct A {
+ int a;
+ };
+
+ template<typename T> struct B : A<float>, A<T> {
+ void f() {
+ a = 0; // should not be ambiguous
+ }
+ };
+ template struct B<int>;
+
+ struct O {
+ int a;
+ template<typename T> struct B : A<T> {
+ void f() {
+ a = 0; // expected-error {{type 'struct test1::O' is not a direct or virtual base of ''B<int>''}}
+ }
+ };
+ };
+ template struct O::B<int>; // expected-note {{in instantiation}}
+}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index 8a2f34d475a7..789fe3db872e 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -30,7 +30,7 @@ T Z<T>::value; // expected-error{{no matching constructor}}
struct DefCon {};
struct NoDefCon {
- NoDefCon(const NoDefCon&); // expected-note{{candidate function}}
+ NoDefCon(const NoDefCon&); // expected-note{{candidate constructor}}
};
void test() {
diff --git a/test/SemaTemplate/instantiate-subscript.cpp b/test/SemaTemplate/instantiate-subscript.cpp
index a7187516da39..8c119ec8c6de 100644
--- a/test/SemaTemplate/instantiate-subscript.cpp
+++ b/test/SemaTemplate/instantiate-subscript.cpp
@@ -16,7 +16,7 @@ struct ConvertibleToInt {
template<typename T, typename U, typename Result>
struct Subscript0 {
void test(T t, U u) {
- Result &result = t[u]; // expected-error{{subscripted value is not}}
+ Result &result = t[u]; // expected-error{{no viable overloaded operator[] for type}}
}
};
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
index 48026f913178..e86f07a02ffe 100644
--- a/test/SemaTemplate/temp_class_spec.cpp
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -330,3 +330,21 @@ template<typename T, T N, typename U> class A0;
template<typename T, T N> class A0<T, N, int> { }; // expected-note{{here}}
template<typename T, T N> class A0<T, N, int>;
template<typename T, T N> class A0<T, N, int> { }; // expected-error{{redef}}
+
+namespace PR6025 {
+ template< int N > struct A;
+
+ namespace N
+ {
+ template< typename F >
+ struct B;
+ }
+
+ template< typename Protect, typename Second >
+ struct C;
+
+ template <class T>
+ struct C< T, A< N::B<T>::value > >
+ {
+ };
+}
diff --git a/test/SemaTemplate/typo-dependent-name.cpp b/test/SemaTemplate/typo-dependent-name.cpp
new file mode 100644
index 000000000000..96554e9dcf4a
--- /dev/null
+++ b/test/SemaTemplate/typo-dependent-name.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T>
+struct Base {
+ T inner;
+};
+
+template<typename T>
+struct X {
+ template<typename U>
+ struct Inner {
+ };
+
+ bool f(T other) {
+ return this->inner < other;
+ }
+};
diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp
index 69ae0807b4c5..db243130bb3d 100644
--- a/test/SemaTemplate/virtual-member-functions.cpp
+++ b/test/SemaTemplate/virtual-member-functions.cpp
@@ -3,14 +3,19 @@
namespace PR5557 {
template <class T> struct A {
A();
+ virtual void anchor(); // expected-note{{instantiation}}
virtual int a(T x);
};
template<class T> A<T>::A() {}
+template<class T> void A<T>::anchor() { }
+
template<class T> int A<T>::a(T x) {
return *x; // expected-error{{requires pointer operand}}
}
-A<int> x; // expected-note{{instantiation}}
+void f(A<int> x) {
+ x.anchor();
+}
template<typename T>
struct X {
@@ -20,3 +25,31 @@ struct X {
template<>
void X<int>::f() { }
}
+
+template<typename T>
+struct Base {
+ virtual ~Base() {
+ int *ptr = 0;
+ T t = ptr; // expected-error{{cannot initialize}}
+ }
+};
+
+template<typename T>
+struct Derived : Base<T> {
+ virtual void foo() { }
+};
+
+template struct Derived<int>; // expected-note{{instantiation}}
+
+template<typename T>
+struct HasOutOfLineKey {
+ HasOutOfLineKey() { } // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}}
+ virtual T *f(float *fp);
+};
+
+template<typename T>
+T *HasOutOfLineKey<T>::f(float *fp) {
+ return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}}
+}
+
+HasOutOfLineKey<int> out_of_line;
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 9b2355dc0a12..86e0ddc20205 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -7,49 +7,116 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Clang-C Source Indexing library.
+// This file implements the main API hooks in the Clang-C Source Indexing
+// library.
//
//===----------------------------------------------------------------------===//
-#include "clang-c/Index.h"
-#include "clang/AST/Decl.h"
+#include "CIndexer.h"
+
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Index/ASTLocation.h"
-#include "clang/Index/Indexer.h"
-#include "clang/Index/Program.h"
-#include "clang/Index/Utils.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
-#include "llvm/Support/Compiler.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
+// Needed to define L_TMPNAM on some systems.
#include <cstdio>
-#include <vector>
-#include <sstream>
-
-#ifdef LLVM_ON_WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
using namespace clang;
using namespace idx;
+//===----------------------------------------------------------------------===//
+// Crash Reporting.
+//===----------------------------------------------------------------------===//
+
+#ifdef __APPLE__
+#ifndef NDEBUG
+#define USE_CRASHTRACER
+#include "clang/Analysis/Support/SaveAndRestore.h"
+// Integrate with crash reporter.
+extern "C" const char *__crashreporter_info__;
+#define NUM_CRASH_STRINGS 16
+static unsigned crashtracer_counter = 0;
+static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 };
+static const char *crashtracer_strings[NUM_CRASH_STRINGS] = { 0 };
+static const char *agg_crashtracer_strings[NUM_CRASH_STRINGS] = { 0 };
+
+static unsigned SetCrashTracerInfo(const char *str,
+ llvm::SmallString<1024> &AggStr) {
+
+ unsigned slot = 0;
+ while (crashtracer_strings[slot]) {
+ if (++slot == NUM_CRASH_STRINGS)
+ slot = 0;
+ }
+ crashtracer_strings[slot] = str;
+ crashtracer_counter_id[slot] = ++crashtracer_counter;
+
+ // We need to create an aggregate string because multiple threads
+ // may be in this method at one time. The crash reporter string
+ // will attempt to overapproximate the set of in-flight invocations
+ // of this function. Race conditions can still cause this goal
+ // to not be achieved.
+ {
+ llvm::raw_svector_ostream Out(AggStr);
+ for (unsigned i = 0; i < NUM_CRASH_STRINGS; ++i)
+ if (crashtracer_strings[i]) Out << crashtracer_strings[i] << '\n';
+ }
+ __crashreporter_info__ = agg_crashtracer_strings[slot] = AggStr.c_str();
+ return slot;
+}
+
+static void ResetCrashTracerInfo(unsigned slot) {
+ unsigned max_slot = 0;
+ unsigned max_value = 0;
+
+ crashtracer_strings[slot] = agg_crashtracer_strings[slot] = 0;
+
+ for (unsigned i = 0 ; i < NUM_CRASH_STRINGS; ++i)
+ if (agg_crashtracer_strings[i] &&
+ crashtracer_counter_id[i] > max_value) {
+ max_slot = i;
+ max_value = crashtracer_counter_id[i];
+ }
+
+ __crashreporter_info__ = agg_crashtracer_strings[max_slot];
+}
+
+namespace {
+class ArgsCrashTracerInfo {
+ llvm::SmallString<1024> CrashString;
+ llvm::SmallString<1024> AggregateString;
+ unsigned crashtracerSlot;
+public:
+ ArgsCrashTracerInfo(llvm::SmallVectorImpl<const char*> &Args)
+ : crashtracerSlot(0)
+ {
+ {
+ llvm::raw_svector_ostream Out(CrashString);
+ Out << "ClangCIndex [createTranslationUnitFromSourceFile]: clang";
+ for (llvm::SmallVectorImpl<const char*>::iterator I=Args.begin(),
+ E=Args.end(); I!=E; ++I)
+ Out << ' ' << *I;
+ }
+ crashtracerSlot = SetCrashTracerInfo(CrashString.c_str(),
+ AggregateString);
+ }
+
+ ~ArgsCrashTracerInfo() {
+ ResetCrashTracerInfo(crashtracerSlot);
+ }
+};
+}
+#endif
+#endif
+
+//===----------------------------------------------------------------------===//
+// Visitors.
+//===----------------------------------------------------------------------===//
+
namespace {
-static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
-{
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) {
NamedDecl *D = DRE->getDecl();
if (isa<VarDecl>(D))
return CXCursor_VarRef;
@@ -97,18 +164,14 @@ 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 &) {}
-};
-
// Translation Unit Visitor.
+
class TUVisitor : public DeclVisitor<TUVisitor> {
- CXTranslationUnit TUnit;
- CXTranslationUnitIterator Callback;
+public:
+ typedef void (*Iterator)(void *, CXCursor, CXClientData);
+private:
+ void *Root; // CXDecl or CXTranslationUnit
+ Iterator Callback; // CXTranslationUnitIterator or CXDeclIterator.
CXClientData CData;
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
@@ -125,45 +188,60 @@ class TUVisitor : public DeclVisitor<TUVisitor> {
if (ND->isImplicit())
return;
- CXCursor C = { CK, ND, 0 };
- Callback(TUnit, C, CData);
+ CXCursor C = { CK, ND, 0, 0 };
+ Callback(Root, C, CData);
}
+
public:
- TUVisitor(CXTranslationUnit CTU,
- CXTranslationUnitIterator cback, CXClientData D,
- unsigned MaxPCHLevel) :
- TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
+ TUVisitor(void *root, Iterator cback, CXClientData D, unsigned MaxPCHLevel) :
+ Root(root), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
+
+ void VisitDeclContext(DeclContext *DC);
+ void VisitFunctionDecl(FunctionDecl *ND);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *ND);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *ND);
+ void VisitTagDecl(TagDecl *ND);
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+ void VisitTypedefDecl(TypedefDecl *ND);
+ void VisitVarDecl(VarDecl *ND);
+};
- void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
- VisitDeclContext(dyn_cast<DeclContext>(D));
- }
- void VisitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
- Visit(*I);
- }
+void TUVisitor::VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I)
+ Visit(*I);
+}
+
+void TUVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+ Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn
+ : CXCursor_FunctionDecl, ND);
+}
+
+void TUVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ Call(CXCursor_ObjCCategoryDecl, ND);
+}
- void VisitFunctionDecl(FunctionDecl *ND) {
- Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn
- : CXCursor_FunctionDecl, ND);
- }
- void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
- Call(CXCursor_ObjCCategoryDecl, ND);
- }
- void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) {
- Call(CXCursor_ObjCCategoryDefn, ND);
- }
- void VisitObjCImplementationDecl(ObjCImplementationDecl *ND) {
- Call(CXCursor_ObjCClassDefn, ND);
- }
- void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
- Call(CXCursor_ObjCInterfaceDecl, ND);
- }
- void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
- Call(CXCursor_ObjCProtocolDecl, ND);
- }
- void VisitTagDecl(TagDecl *ND) {
- switch (ND->getTagKind()) {
+void TUVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) {
+ Call(CXCursor_ObjCCategoryDefn, ND);
+}
+
+void TUVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *ND) {
+ Call(CXCursor_ObjCClassDefn, ND);
+}
+
+void TUVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
+ Call(CXCursor_ObjCInterfaceDecl, ND);
+}
+
+void TUVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
+ Call(CXCursor_ObjCProtocolDecl, ND);
+}
+
+void TUVisitor::VisitTagDecl(TagDecl *ND) {
+ switch (ND->getTagKind()) {
case TagDecl::TK_struct:
Call(CXCursor_StructDecl, ND);
break;
@@ -176,16 +254,20 @@ public:
case TagDecl::TK_enum:
Call(CXCursor_EnumDecl, ND);
break;
- }
}
- void VisitTypedefDecl(TypedefDecl *ND) {
- Call(CXCursor_TypedefDecl, ND);
- }
- void VisitVarDecl(VarDecl *ND) {
- Call(CXCursor_VarDecl, ND);
- }
-};
+}
+
+void TUVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+}
+
+void TUVisitor::VisitTypedefDecl(TypedefDecl *ND) {
+ Call(CXCursor_TypedefDecl, ND);
+}
+void TUVisitor::VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
+}
// Declaration visitor.
class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
@@ -207,7 +289,7 @@ class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
if (ND->getPCHLevel() > MaxPCHLevel)
return;
- CXCursor C = { CK, ND, 0 };
+ CXCursor C = { CK, ND, 0, 0 };
Callback(CDecl, C, CData);
}
public:
@@ -215,188 +297,112 @@ public:
unsigned MaxPCHLevel) :
CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
- void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
- // Issue callbacks for the containing class.
- Call(CXCursor_ObjCClassRef, ND);
- // FIXME: Issue callbacks for protocol refs.
- VisitDeclContext(dyn_cast<DeclContext>(ND));
- }
- void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
- // Issue callbacks for super class.
- if (D->getSuperClass())
- Call(CXCursor_ObjCSuperClassRef, D);
-
- 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)
- Call(CXCursor_ObjCProtocolRef, *I);
-
- VisitDeclContext(dyn_cast<DeclContext>(PID));
- }
- void VisitTagDecl(TagDecl *D) {
- VisitDeclContext(dyn_cast<DeclContext>(D));
- }
- void VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
- VisitDeclContext(dyn_cast<DeclContext>(D));
- }
- void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
- VisitDeclContext(dyn_cast<DeclContext>(D));
- }
- void VisitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
- Visit(*I);
- }
- void VisitEnumConstantDecl(EnumConstantDecl *ND) {
- Call(CXCursor_EnumConstantDecl, ND);
- }
- void VisitFieldDecl(FieldDecl *ND) {
- Call(CXCursor_FieldDecl, ND);
- }
- void VisitVarDecl(VarDecl *ND) {
- Call(CXCursor_VarDecl, ND);
- }
- void VisitParmVarDecl(ParmVarDecl *ND) {
- Call(CXCursor_ParmDecl, ND);
- }
- void VisitObjCPropertyDecl(ObjCPropertyDecl *ND) {
- Call(CXCursor_ObjCPropertyDecl, ND);
- }
- void VisitObjCIvarDecl(ObjCIvarDecl *ND) {
- Call(CXCursor_ObjCIvarDecl, ND);
- }
- void VisitFunctionDecl(FunctionDecl *ND) {
- if (ND->isThisDeclarationADefinition()) {
- VisitDeclContext(dyn_cast<DeclContext>(ND));
-#if 0
- // Not currently needed.
- CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody());
- CRefVisitor RVisit(CDecl, Callback, CData);
- RVisit.Visit(Body);
-#endif
- }
- }
- void VisitObjCMethodDecl(ObjCMethodDecl *ND) {
- if (ND->getBody()) {
- Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn
- : CXCursor_ObjCClassMethodDefn, ND);
- VisitDeclContext(dyn_cast<DeclContext>(ND));
- } else
- Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl
- : CXCursor_ObjCClassMethodDecl, ND);
- }
+ void VisitDeclContext(DeclContext *DC);
+ void VisitEnumConstantDecl(EnumConstantDecl *ND);
+ void VisitFieldDecl(FieldDecl *ND);
+ void VisitFunctionDecl(FunctionDecl *ND);
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ void VisitObjCIvarDecl(ObjCIvarDecl *ND);
+ void VisitObjCMethodDecl(ObjCMethodDecl *ND);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *ND);
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ void VisitParmVarDecl(ParmVarDecl *ND);
+ void VisitTagDecl(TagDecl *D);
+ void VisitVarDecl(VarDecl *ND);
};
+} // end anonymous namespace
-class CIndexer : public Indexer {
- DiagnosticOptions DiagOpts;
- IgnoreDiagnosticsClient IgnoreDiagClient;
- llvm::OwningPtr<Diagnostic> TextDiags;
- Diagnostic IgnoreDiags;
- bool UseExternalASTGeneration;
- bool OnlyLocalDecls;
- bool DisplayDiagnostics;
-
- llvm::sys::Path ClangPath;
-
-public:
- explicit CIndexer(Program *prog) : Indexer(*prog),
- IgnoreDiags(&IgnoreDiagClient),
- UseExternalASTGeneration(false),
- OnlyLocalDecls(false),
- DisplayDiagnostics(false) {
- TextDiags.reset(
- CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
- }
+void CDeclVisitor::VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+}
- virtual ~CIndexer() { delete &getProgram(); }
+void CDeclVisitor::VisitEnumConstantDecl(EnumConstantDecl *ND) {
+ Call(CXCursor_EnumConstantDecl, ND);
+}
- /// \brief Whether we only want to see "local" declarations (that did not
- /// come from a previous precompiled header). If false, we want to see all
- /// declarations.
- bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
- void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
+void CDeclVisitor::VisitFieldDecl(FieldDecl *ND) {
+ Call(CXCursor_FieldDecl, ND);
+}
- bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
- void setDisplayDiagnostics(bool Display = true) {
- DisplayDiagnostics = Display;
+void CDeclVisitor::VisitFunctionDecl(FunctionDecl *ND) {
+ if (ND->isThisDeclarationADefinition()) {
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+#if 0
+ // Not currently needed.
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody());
+ CRefVisitor RVisit(CDecl, Callback, CData);
+ RVisit.Visit(Body);
+#endif
}
+}
- bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
- void setUseExternalASTGeneration(bool Value) {
- UseExternalASTGeneration = Value;
- }
+void CDeclVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ // Issue callbacks for the containing class.
+ Call(CXCursor_ObjCClassRef, ND);
+ // FIXME: Issue callbacks for protocol refs.
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+}
- Diagnostic &getDiags() {
- return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
- }
+void CDeclVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+}
- /// \brief Get the path of the clang binary.
- const llvm::sys::Path& getClangPath();
+void CDeclVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+}
- /// \brief Get the path of the clang resource files.
- std::string getClangResourcesPath();
-};
+void CDeclVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Issue callbacks for super class.
+ if (D->getSuperClass())
+ Call(CXCursor_ObjCSuperClassRef, D);
+
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+}
-const llvm::sys::Path& CIndexer::getClangPath() {
- // Did we already compute the path?
- if (!ClangPath.empty())
- return ClangPath;
-
- // Find the location where this library lives (libCIndex.dylib).
-#ifdef LLVM_ON_WIN32
- MEMORY_BASIC_INFORMATION mbi;
- char path[MAX_PATH];
- VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
- sizeof(mbi));
- GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
-
- llvm::sys::Path CIndexPath(path);
-
- CIndexPath.eraseComponent();
- CIndexPath.appendComponent("clang");
- CIndexPath.appendSuffix("exe");
- CIndexPath.makeAbsolute();
-#else
- // This silly cast below avoids a C++ warning.
- Dl_info info;
- if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
- assert(0 && "Call to dladdr() failed");
-
- llvm::sys::Path CIndexPath(info.dli_fname);
-
- // We now have the CIndex directory, locate clang relative to it.
- CIndexPath.eraseComponent();
- CIndexPath.eraseComponent();
- CIndexPath.appendComponent("bin");
- CIndexPath.appendComponent("clang");
-#endif
+void CDeclVisitor::VisitObjCIvarDecl(ObjCIvarDecl *ND) {
+ Call(CXCursor_ObjCIvarDecl, ND);
+}
- // Cache our result.
- ClangPath = CIndexPath;
- return ClangPath;
+void CDeclVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+ if (ND->getBody()) {
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn
+ : CXCursor_ObjCClassMethodDefn, ND);
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+ } else
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl
+ : CXCursor_ObjCClassMethodDecl, ND);
}
-std::string CIndexer::getClangResourcesPath() {
- llvm::sys::Path P = getClangPath();
+void CDeclVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *ND) {
+ Call(CXCursor_ObjCPropertyDecl, ND);
+}
- if (!P.empty()) {
- P.eraseComponent(); // Remove /clang from foo/bin/clang
- P.eraseComponent(); // Remove /bin from foo/bin
+void CDeclVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+
+ VisitDeclContext(dyn_cast<DeclContext>(PID));
+}
- // Get foo/lib/clang/<version>/include
- P.appendComponent("lib");
- P.appendComponent("clang");
- P.appendComponent(CLANG_VERSION_STRING);
- }
+void CDeclVisitor::VisitParmVarDecl(ParmVarDecl *ND) {
+ Call(CXCursor_ParmDecl, ND);
+}
- return P.str();
+void CDeclVisitor::VisitTagDecl(TagDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
}
+void CDeclVisitor::VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
}
static SourceLocation getLocationFromCursor(CXCursor C,
@@ -463,7 +469,7 @@ static SourceLocation getLocationFromCursor(CXCursor C,
}
}
-static CXString createCXString(const char *String, bool DupString = false) {
+CXString CIndexer::createCXString(const char *String, bool DupString){
CXString Str;
if (DupString) {
Str.Spelling = strdup(String);
@@ -476,7 +482,6 @@ static CXString createCXString(const char *String, bool DupString = false) {
}
extern "C" {
-
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
CIndexer *CIdxr = new CIndexer(new Program());
@@ -529,13 +534,18 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
command_line_args + num_command_line_args);
unsigned NumErrors = CXXIdx->getDiags().getNumErrors();
+
+#ifdef USE_CRASHTRACER
+ ArgsCrashTracerInfo ACTI(Args);
+#endif
+
llvm::OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(),
CXXIdx->getDiags(),
CXXIdx->getClangResourcesPath(),
CXXIdx->getOnlyLocalDecls(),
/* UseBumpAllocator = */ true));
-
+
// FIXME: Until we have broader testing, just drop the entire AST if we
// encountered an error.
if (NumErrors != CXXIdx->getDiags().getNumErrors())
@@ -621,7 +631,8 @@ void clang_disposeTranslationUnit(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);
+ return CIndexer::createCXString(CXXUnit->getOriginalSourceFileName().c_str(),
+ true);
}
void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
@@ -665,61 +676,41 @@ void clang_loadDeclaration(CXDecl Dcl,
static_cast<Decl *>(Dcl)->getPCHLevel());
DVisit.Visit(static_cast<Decl *>(Dcl));
}
+} // end: extern "C"
-// Some notes on CXEntity:
-//
-// - 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
-// within a CXTranslationUnit are *not* currently represented by entities.
-// As a result, there will be no entity for the following:
-//
-// module.m: static void Foo() { }
-//
-
-
-const char *clang_getDeclarationName(CXEntity) {
- return "";
-}
-
-const char *clang_getURI(CXEntity) {
- return "";
-}
-
-CXEntity clang_getEntity(const char *URI) {
- return 0;
-}
-
-//
+//===----------------------------------------------------------------------===//
// CXDecl Operations.
-//
+//===----------------------------------------------------------------------===//
-CXEntity clang_getEntityFromDecl(CXDecl) {
- return 0;
+static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
+ SourceLocation SLoc) {
+ FileID FID;
+ if (SLoc.isFileID())
+ FID = SMgr.getFileID(SLoc);
+ else
+ FID = SMgr.getDecomposedSpellingLoc(SLoc).first;
+ return SMgr.getFileEntryForID(FID);
}
+extern "C" {
CXString clang_getDeclSpelling(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
- return createCXString(OMD->getSelector().getAsString().c_str(), true);
+ return CIndexer::createCXString(OMD->getSelector().getAsString().c_str(),
+ true);
if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
// No, this isn't the same as the code below. getIdentifier() is non-virtual
// and returns different names. NamedDecl returns the class name and
// ObjCCategoryImplDecl returns the category name.
- return createCXString(CIMP->getIdentifier()->getNameStart());
+ return CIndexer::createCXString(CIMP->getIdentifier()->getNameStart());
if (ND->getIdentifier())
- return createCXString(ND->getIdentifier()->getNameStart());
+ return CIndexer::createCXString(ND->getIdentifier()->getNameStart());
- return createCXString("");
+ return CIndexer::createCXString("");
}
unsigned clang_getDeclLine(CXDecl AnonDecl) {
@@ -735,23 +726,67 @@ unsigned clang_getDeclColumn(CXDecl AnonDecl) {
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
return SourceMgr.getSpellingColumnNumber(ND->getLocation());
}
+
+CXDeclExtent clang_getDeclExtent(CXDecl AnonDecl) {
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SM = ND->getASTContext().getSourceManager();
+ SourceRange R = ND->getSourceRange();
+
+ SourceLocation Begin = SM.getInstantiationLoc(R.getBegin());
+ SourceLocation End = SM.getInstantiationLoc(R.getEnd());
+
+ if (!Begin.isValid()) {
+ CXDeclExtent extent = { { 0, 0 }, { 0, 0 } };
+ return extent;
+ }
+
+ // FIXME: This is largely copy-paste from
+ ///TextDiagnosticPrinter::HighlightRange. When it is clear that this is
+ // what we want the two routines should be refactored.
+
+ // If the End location and the start location are the same and are a macro
+ // location, then the range was something that came from a macro expansion
+ // or _Pragma. If this is an object-like macro, the best we can do is to
+ // get the range. If this is a function-like macro, we'd also like to
+ // get the arguments.
+ if (Begin == End && R.getEnd().isMacroID())
+ End = SM.getInstantiationRange(R.getEnd()).second;
+
+ assert(SM.getFileID(Begin) == SM.getFileID(End));
+ unsigned StartLineNo = SM.getInstantiationLineNumber(Begin);
+ unsigned EndLineNo = SM.getInstantiationLineNumber(End);
+
+ // Compute the column number of the start. Keep the column based at 1.
+ unsigned StartColNo = SM.getInstantiationColumnNumber(Begin);
+
+ // Compute the column number of the end.
+ unsigned EndColNo = SM.getInstantiationColumnNumber(End);
+ if (EndColNo) {
+ // Offset the end column by 1 so that we point to the last character
+ // in the last token.
+ --EndColNo;
+
+ // Add in the length of the token, so that we cover multi-char tokens.
+ ASTContext &Ctx = ND->getTranslationUnitDecl()->getASTContext();
+ const LangOptions &LOpts = Ctx.getLangOptions();
+
+ EndColNo += Lexer::MeasureTokenLength(End, SM, LOpts);
+ }
+
+ // Package up the line/column data and return to the caller.
+ CXDeclExtent extent = { { StartLineNo, StartColNo },
+ { EndLineNo, EndColNo } };
+ return extent;
+}
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");
+ assert(FEnt && "Cannot find FileEntry for Decl");
return clang_getFileName(FEnt);
}
-static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
- SourceLocation SLoc) {
- FileID FID;
- if (SLoc.isFileID())
- FID = SMgr.getFileID(SLoc);
- else
- FID = SMgr.getDecomposedSpellingLoc(SLoc).first;
- return SMgr.getFileEntryForID(FID);
-}
CXFile clang_getDeclSourceFile(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
@@ -759,7 +794,13 @@ CXFile clang_getDeclSourceFile(CXDecl AnonDecl) {
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
return (void *)getFileEntryFromSourceLocation(SourceMgr, ND->getLocation());
}
+} // end: extern "C"
+//===----------------------------------------------------------------------===//
+// CXFile Operations.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
const char *clang_getFileName(CXFile SFile) {
assert(SFile && "Passed null CXFile");
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
@@ -771,7 +812,67 @@ time_t clang_getFileTime(CXFile SFile) {
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
return FEnt->getModificationTime();
}
+} // end: extern "C"
+
+//===----------------------------------------------------------------------===//
+// CXCursor Operations.
+//===----------------------------------------------------------------------===//
+
+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;
+ }
+ return CXCursor_NotImplemented;
+}
+
+
+static CXCursor MakeCXCursor(CXCursorKind K, Decl *D) {
+ CXCursor C = { K, D, 0, 0 };
+ return C;
+}
+
+static CXCursor MakeCXCursor(CXCursorKind K, Decl *D, Stmt *S) {
+ assert(clang_isReference(K));
+ CXCursor C = { K, D, S, 0 };
+ return C;
+}
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+ if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ return OME->getMethodDecl();
+
+ return 0;
+}
+extern "C" {
CXString clang_getCursorSpelling(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
@@ -781,28 +882,29 @@ CXString clang_getCursorSpelling(CXCursor C) {
case CXCursor_ObjCSuperClassRef: {
ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
assert(OID && "clang_getCursorLine(): Missing interface decl");
- return createCXString(OID->getSuperClass()->getIdentifier()
- ->getNameStart());
+ return CIndexer::createCXString(OID->getSuperClass()->getIdentifier()
+ ->getNameStart());
}
case CXCursor_ObjCClassRef: {
if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND))
- return createCXString(OID->getIdentifier()->getNameStart());
+ return CIndexer::createCXString(OID->getIdentifier()->getNameStart());
ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
assert(OCD && "clang_getCursorLine(): Missing category decl");
- return createCXString(OCD->getClassInterface()->getIdentifier()
+ return CIndexer::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());
+ return CIndexer::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);
+ return CIndexer::createCXString(OME->getSelector().getAsString().c_str(),
+ true);
}
case CXCursor_VarRef:
case CXCursor_FunctionRef:
@@ -810,10 +912,11 @@ CXString clang_getCursorSpelling(CXCursor C) {
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
static_cast<Stmt *>(C.stmt));
assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
- return createCXString(DRE->getDecl()->getIdentifier()->getNameStart());
+ return CIndexer::createCXString(DRE->getDecl()->getIdentifier()
+ ->getNameStart());
}
default:
- return createCXString("<not implemented>");
+ return CIndexer::createCXString("<not implemented>");
}
}
return clang_getDeclSpelling(C.decl);
@@ -860,33 +963,6 @@ const char *clang_getCursorKindSpelling(enum CXCursorKind Kind) {
}
}
-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;
- }
- return CXCursor_NotImplemented;
-}
-//
-// CXCursor Operations.
-//
-
CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
unsigned line, unsigned column) {
assert(CTUnit && "Passed null CXTranslationUnit");
@@ -895,17 +971,17 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
FileManager &FMgr = CXXUnit->getFileManager();
const FileEntry *File = FMgr.getFile(source_name,
source_name+strlen(source_name));
- if (!File) {
- CXCursor C = { CXCursor_InvalidFile, 0, 0 };
- return C;
- }
+ if (!File)
+ return clang_getNullCursor();
+
SourceLocation SLoc =
CXXUnit->getSourceManager().getLocation(File, line, column);
ASTLocation LastLoc = CXXUnit->getLastASTLocation();
-
ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
&LastLoc);
+
+ // FIXME: This doesn't look thread-safe.
if (ALoc.isValid())
CXXUnit->setLastASTLocation(ALoc);
@@ -915,50 +991,40 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
Stmt *Stm = ALoc.dyn_AsStmt();
if (Dcl) {
if (Stm) {
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) {
- CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm };
- return C;
- } else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) {
- CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp };
- return C;
- }
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm))
+ return MakeCXCursor(TranslateDeclRefExpr(DRE), Dcl, Stm);
+ else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm))
+ return MakeCXCursor(CXCursor_ObjCSelectorRef, Dcl, MExp);
// Fall through...treat as a decl, not a ref.
}
if (ALoc.isNamedRef()) {
if (isa<ObjCInterfaceDecl>(Dcl)) {
- CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() };
+ CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl(), 0 };
return C;
}
if (isa<ObjCProtocolDecl>(Dcl)) {
- CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl() };
+ CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl(), 0 };
return C;
}
}
- CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
- return C;
+ return MakeCXCursor(TranslateKind(Dcl), Dcl);
}
- CXCursor C = { CXCursor_NoDeclFound, 0, 0 };
- return C;
+ return MakeCXCursor(CXCursor_NoDeclFound, 0);
}
CXCursor clang_getNullCursor(void) {
- CXCursor C;
- C.kind = CXCursor_InvalidFile;
- C.decl = NULL;
- C.stmt = NULL;
- return C;
+ return MakeCXCursor(CXCursor_InvalidFile, 0);
}
unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
- return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt;
+ return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt &&
+ X.referringDecl == Y.referringDecl;
}
CXCursor clang_getCursorFromDecl(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
-
- CXCursor C = { TranslateKind(ND), ND, 0 };
- return C;
+ return MakeCXCursor(TranslateKind(ND), ND);
}
unsigned clang_isInvalid(enum CXCursorKind K) {
@@ -981,24 +1047,6 @@ CXCursorKind clang_getCursorKind(CXCursor C) {
return C.kind;
}
-static Decl *getDeclFromExpr(Stmt *E) {
- if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
- return RefExpr->getDecl();
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return ME->getMemberDecl();
- if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
- return RE->getDecl();
-
- if (CallExpr *CE = dyn_cast<CallExpr>(E))
- return getDeclFromExpr(CE->getCallee());
- if (CastExpr *CE = dyn_cast<CastExpr>(E))
- return getDeclFromExpr(CE->getSubExpr());
- if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
- return OME->getMethodDecl();
-
- return 0;
-}
-
CXDecl clang_getCursorDecl(CXCursor C) {
if (clang_isDeclaration(C.kind))
return C.decl;
@@ -1024,21 +1072,12 @@ unsigned clang_getCursorLine(CXCursor C) {
SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
return SourceMgr.getSpellingLineNumber(SLoc);
}
-
-const char *clang_getCString(CXString string) {
- return string.Spelling;
-}
-
-void clang_disposeString(CXString string) {
- if (string.MustFreeString)
- free((void*)string.Spelling);
-}
-
+
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);
}
@@ -1047,22 +1086,22 @@ 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;
}
-
+
// 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
- = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first);
+ = SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first);
if (!Buffer)
return 0;
-
+
return Buffer->getBufferIdentifier();
}
@@ -1070,9 +1109,10 @@ 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));
+
+ return (void *)
+ getFileEntryFromSourceLocation(SourceMgr, getLocationFromCursor(C,SourceMgr,
+ ND));
}
void clang_getDefinitionSpellingAndExtent(CXCursor C,
@@ -1086,7 +1126,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
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());
@@ -1095,329 +1135,20 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
*endLine = SM.getSpellingLineNumber(Body->getRBracLoc());
*endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
}
+
+} // end: extern "C"
-enum CXCompletionChunkKind
-clang_getCompletionChunkKind(CXCompletionString completion_string,
- unsigned chunk_number) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
- if (!CCStr || chunk_number >= CCStr->size())
- return CXCompletionChunk_Text;
-
- switch ((*CCStr)[chunk_number].Kind) {
- case CodeCompletionString::CK_TypedText:
- return CXCompletionChunk_TypedText;
- case CodeCompletionString::CK_Text:
- return CXCompletionChunk_Text;
- case CodeCompletionString::CK_Optional:
- return CXCompletionChunk_Optional;
- case CodeCompletionString::CK_Placeholder:
- return CXCompletionChunk_Placeholder;
- case CodeCompletionString::CK_Informative:
- return CXCompletionChunk_Informative;
- case CodeCompletionString::CK_ResultType:
- return CXCompletionChunk_ResultType;
- case CodeCompletionString::CK_CurrentParameter:
- return CXCompletionChunk_CurrentParameter;
- case CodeCompletionString::CK_LeftParen:
- return CXCompletionChunk_LeftParen;
- case CodeCompletionString::CK_RightParen:
- return CXCompletionChunk_RightParen;
- case CodeCompletionString::CK_LeftBracket:
- return CXCompletionChunk_LeftBracket;
- case CodeCompletionString::CK_RightBracket:
- return CXCompletionChunk_RightBracket;
- case CodeCompletionString::CK_LeftBrace:
- return CXCompletionChunk_LeftBrace;
- case CodeCompletionString::CK_RightBrace:
- return CXCompletionChunk_RightBrace;
- case CodeCompletionString::CK_LeftAngle:
- return CXCompletionChunk_LeftAngle;
- case CodeCompletionString::CK_RightAngle:
- return CXCompletionChunk_RightAngle;
- case CodeCompletionString::CK_Comma:
- return CXCompletionChunk_Comma;
- }
-
- // 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:
- case CodeCompletionString::CK_Placeholder:
- case CodeCompletionString::CK_CurrentParameter:
- case CodeCompletionString::CK_Informative:
- case CodeCompletionString::CK_LeftParen:
- case CodeCompletionString::CK_RightParen:
- case CodeCompletionString::CK_LeftBracket:
- case CodeCompletionString::CK_RightBracket:
- case CodeCompletionString::CK_LeftBrace:
- case CodeCompletionString::CK_RightBrace:
- case CodeCompletionString::CK_LeftAngle:
- case CodeCompletionString::CK_RightAngle:
- case CodeCompletionString::CK_Comma:
- case CodeCompletionString::CK_ResultType:
- return (*CCStr)[chunk_number].Text;
-
- case CodeCompletionString::CK_Optional:
- // Note: treated as an empty text block.
- return "";
- }
-
- // 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:
- case CodeCompletionString::CK_Placeholder:
- case CodeCompletionString::CK_CurrentParameter:
- case CodeCompletionString::CK_Informative:
- case CodeCompletionString::CK_LeftParen:
- case CodeCompletionString::CK_RightParen:
- case CodeCompletionString::CK_LeftBracket:
- case CodeCompletionString::CK_RightBracket:
- case CodeCompletionString::CK_LeftBrace:
- case CodeCompletionString::CK_RightBrace:
- case CodeCompletionString::CK_LeftAngle:
- case CodeCompletionString::CK_RightAngle:
- case CodeCompletionString::CK_Comma:
- case CodeCompletionString::CK_ResultType:
- return 0;
-
- case CodeCompletionString::CK_Optional:
- // Note: treated as an empty text block.
- return (*CCStr)[chunk_number].Optional;
- }
-
- // Should be unreachable, but let's be careful.
- return 0;
-}
-
-unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
- CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
- return CCStr? CCStr->size() : 0;
-}
-
-static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
- unsigned &Value) {
- if (Memory + sizeof(unsigned) > MemoryEnd)
- return true;
-
- memmove(&Value, Memory, sizeof(unsigned));
- Memory += sizeof(unsigned);
- return false;
-}
-
-/// \brief The CXCodeCompleteResults structure we allocate internally;
-/// the client only sees the initial CXCodeCompleteResults structure.
-struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
- /// \brief The memory buffer from which we parsed the results. We
- /// retain this buffer because the completion strings point into it.
- llvm::MemoryBuffer *Buffer;
-};
-
-CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
- const char *source_filename,
- int num_command_line_args,
- const char **command_line_args,
- unsigned num_unsaved_files,
- struct CXUnsavedFile *unsaved_files,
- const char *complete_filename,
- unsigned complete_line,
- unsigned complete_column) {
- // The indexer, which is mainly used to determine where diagnostics go.
- CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
-
- // The set of temporary files that we've built.
- std::vector<llvm::sys::Path> TemporaryFiles;
-
- // Build up the arguments for invoking 'clang'.
- std::vector<const char *> argv;
-
- // First add the complete path to the 'clang' executable.
- llvm::sys::Path ClangPath = CXXIdx->getClangPath();
- argv.push_back(ClangPath.c_str());
-
- // Add the '-fsyntax-only' argument so that we only perform a basic
- // syntax check of the code.
- argv.push_back("-fsyntax-only");
-
- // Add the appropriate '-code-completion-at=file:line:column' argument
- // to perform code completion, with an "-Xclang" preceding it.
- std::string code_complete_at;
- code_complete_at += complete_filename;
- code_complete_at += ":";
- code_complete_at += llvm::utostr(complete_line);
- code_complete_at += ":";
- code_complete_at += llvm::utostr(complete_column);
- argv.push_back("-Xclang");
- argv.push_back("-code-completion-at");
- argv.push_back("-Xclang");
- argv.push_back(code_complete_at.c_str());
- argv.push_back("-Xclang");
- argv.push_back("-no-code-completion-debug-printer");
-
- std::vector<std::string> RemapArgs;
- for (unsigned i = 0; i != num_unsaved_files; ++i) {
- char tmpFile[L_tmpnam];
- char *tmpFileName = tmpnam(tmpFile);
-
- // Write the contents of this unsaved file into the temporary file.
- llvm::sys::Path SavedFile(tmpFileName);
- std::string ErrorInfo;
- llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
- if (!ErrorInfo.empty())
- continue;
-
- OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
- OS.close();
- if (OS.has_error()) {
- SavedFile.eraseFromDisk();
- continue;
- }
-
- // Remap the file.
- std::string RemapArg = unsaved_files[i].Filename;
- RemapArg += ';';
- RemapArg += tmpFileName;
- RemapArgs.push_back("-Xclang");
- RemapArgs.push_back("-remap-file");
- RemapArgs.push_back("-Xclang");
- RemapArgs.push_back(RemapArg);
- TemporaryFiles.push_back(SavedFile);
- }
-
- // The pointers into the elements of RemapArgs are stable because we
- // won't be adding anything to RemapArgs after this point.
- for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
- argv.push_back(RemapArgs[i].c_str());
-
- // Add the source file name (FIXME: later, we'll want to build temporary
- // file from the buffer, or just feed the source text via standard input).
- if (source_filename)
- argv.push_back(source_filename);
-
- // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
- for (int i = 0; i < num_command_line_args; ++i)
- if (const char *arg = command_line_args[i]) {
- if (strcmp(arg, "-o") == 0) {
- ++i; // Also skip the matching argument.
- continue;
- }
- if (strcmp(arg, "-emit-ast") == 0 ||
- strcmp(arg, "-c") == 0 ||
- strcmp(arg, "-fsyntax-only") == 0) {
- continue;
- }
-
- // Keep the argument.
- argv.push_back(arg);
- }
-
- // Add the null terminator.
- argv.push_back(NULL);
-
- // Generate a temporary name for the AST file.
- char tmpFile[L_tmpnam];
- char *tmpFileName = tmpnam(tmpFile);
- llvm::sys::Path ResultsFile(tmpFileName);
- TemporaryFiles.push_back(ResultsFile);
-
- // Invoke 'clang'.
- llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
- // on Unix or NUL (Windows).
- std::string ErrMsg;
- const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
- llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
- /* redirects */ &Redirects[0],
- /* secondsToWait */ 0,
- /* memoryLimits */ 0, &ErrMsg);
-
- if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- 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)
- llvm::errs() << ' ' << *I << '\n';
- }
- llvm::errs() << '\n';
- }
-
- // Parse the resulting source file to find code-completion results.
- using llvm::MemoryBuffer;
- using llvm::StringRef;
- AllocatedCXCodeCompleteResults *Results = 0;
- if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
- llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
- StringRef Buffer = F->getBuffer();
- for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
- Str < StrEnd;) {
- unsigned KindValue;
- if (ReadUnsigned(Str, StrEnd, KindValue))
- break;
-
- CodeCompletionString *CCStr
- = CodeCompletionString::Deserialize(Str, StrEnd);
- if (!CCStr)
- continue;
-
- if (!CCStr->empty()) {
- // Vend the code-completion result to the caller.
- CXCompletionResult Result;
- Result.CursorKind = (CXCursorKind)KindValue;
- Result.CompletionString = CCStr;
- CompletionResults.push_back(Result);
- }
- };
-
- // Allocate the results.
- Results = new AllocatedCXCodeCompleteResults;
- Results->Results = new CXCompletionResult [CompletionResults.size()];
- Results->NumResults = CompletionResults.size();
- memcpy(Results->Results, CompletionResults.data(),
- CompletionResults.size() * sizeof(CXCompletionResult));
- Results->Buffer = F;
- }
-
- for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
- TemporaryFiles[i].eraseFromDisk();
+//===----------------------------------------------------------------------===//
+// CXString Operations.
+//===----------------------------------------------------------------------===//
- return Results;
+extern "C" {
+const char *clang_getCString(CXString string) {
+ return string.Spelling;
}
-void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
- if (!ResultsIn)
- return;
-
- AllocatedCXCodeCompleteResults *Results
- = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
-
- for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
- delete (CXCompletionString *)Results->Results[I].CompletionString;
- delete [] Results->Results;
-
- Results->Results = 0;
- Results->NumResults = 0;
- delete Results->Buffer;
- Results->Buffer = 0;
- delete Results;
+void clang_disposeString(CXString string) {
+ if (string.MustFreeString && string.Spelling)
+ free((void*)string.Spelling);
}
-
-} // end extern "C"
+} // end: extern "C"
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
index e925df945d06..a695ba2b08d1 100644
--- a/tools/CIndex/CIndex.exports
+++ b/tools/CIndex/CIndex.exports
@@ -22,20 +22,21 @@ _clang_getCursorSource
_clang_getCursorSourceFile
_clang_getCursorSpelling
_clang_getDeclColumn
+_clang_getDeclExtent
_clang_getDeclLine
+_clang_getDeclExtent
_clang_getDeclSource
_clang_getDeclSourceFile
_clang_getDeclSpelling
-_clang_getDeclarationName
+_clang_getDeclUSR
+_clang_getDeclaration
_clang_getDefinitionSpellingAndExtent
-_clang_getEntity
_clang_getEntityFromDecl
_clang_getFileName
_clang_getFileTime
_clang_getNullCursor
_clang_getNumCompletionChunks
_clang_getTranslationUnitSpelling
-_clang_getURI
_clang_isDeclaration
_clang_isDefinition
_clang_isInvalid
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
new file mode 100644
index 000000000000..f70479b5e8d3
--- /dev/null
+++ b/tools/CIndex/CIndexCodeCompletion.cpp
@@ -0,0 +1,371 @@
+//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library hooks for
+// code completion.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Program.h"
+
+using namespace clang;
+
+extern "C" {
+
+enum CXCompletionChunkKind
+clang_getCompletionChunkKind(CXCompletionString completion_string,
+ unsigned chunk_number) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr || chunk_number >= CCStr->size())
+ return CXCompletionChunk_Text;
+
+ switch ((*CCStr)[chunk_number].Kind) {
+ case CodeCompletionString::CK_TypedText:
+ return CXCompletionChunk_TypedText;
+ case CodeCompletionString::CK_Text:
+ return CXCompletionChunk_Text;
+ case CodeCompletionString::CK_Optional:
+ return CXCompletionChunk_Optional;
+ case CodeCompletionString::CK_Placeholder:
+ return CXCompletionChunk_Placeholder;
+ case CodeCompletionString::CK_Informative:
+ return CXCompletionChunk_Informative;
+ case CodeCompletionString::CK_ResultType:
+ return CXCompletionChunk_ResultType;
+ case CodeCompletionString::CK_CurrentParameter:
+ return CXCompletionChunk_CurrentParameter;
+ case CodeCompletionString::CK_LeftParen:
+ return CXCompletionChunk_LeftParen;
+ case CodeCompletionString::CK_RightParen:
+ return CXCompletionChunk_RightParen;
+ case CodeCompletionString::CK_LeftBracket:
+ return CXCompletionChunk_LeftBracket;
+ case CodeCompletionString::CK_RightBracket:
+ return CXCompletionChunk_RightBracket;
+ case CodeCompletionString::CK_LeftBrace:
+ return CXCompletionChunk_LeftBrace;
+ case CodeCompletionString::CK_RightBrace:
+ return CXCompletionChunk_RightBrace;
+ case CodeCompletionString::CK_LeftAngle:
+ return CXCompletionChunk_LeftAngle;
+ case CodeCompletionString::CK_RightAngle:
+ return CXCompletionChunk_RightAngle;
+ case CodeCompletionString::CK_Comma:
+ return CXCompletionChunk_Comma;
+ case CodeCompletionString::CK_Colon:
+ return CXCompletionChunk_Colon;
+ case CodeCompletionString::CK_SemiColon:
+ return CXCompletionChunk_SemiColon;
+ case CodeCompletionString::CK_Equal:
+ return CXCompletionChunk_Equal;
+ case CodeCompletionString::CK_HorizontalSpace:
+ return CXCompletionChunk_HorizontalSpace;
+ case CodeCompletionString::CK_VerticalSpace:
+ return CXCompletionChunk_VerticalSpace;
+ }
+
+ // Should be unreachable, but let's be careful.
+ return CXCompletionChunk_Text;
+}
+
+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:
+ case CodeCompletionString::CK_Placeholder:
+ case CodeCompletionString::CK_CurrentParameter:
+ case CodeCompletionString::CK_Informative:
+ case CodeCompletionString::CK_LeftParen:
+ case CodeCompletionString::CK_RightParen:
+ case CodeCompletionString::CK_LeftBracket:
+ case CodeCompletionString::CK_RightBracket:
+ case CodeCompletionString::CK_LeftBrace:
+ case CodeCompletionString::CK_RightBrace:
+ case CodeCompletionString::CK_LeftAngle:
+ case CodeCompletionString::CK_RightAngle:
+ case CodeCompletionString::CK_Comma:
+ case CodeCompletionString::CK_ResultType:
+ case CodeCompletionString::CK_Colon:
+ case CodeCompletionString::CK_SemiColon:
+ case CodeCompletionString::CK_Equal:
+ case CodeCompletionString::CK_HorizontalSpace:
+ case CodeCompletionString::CK_VerticalSpace:
+ return (*CCStr)[chunk_number].Text;
+
+ case CodeCompletionString::CK_Optional:
+ // Note: treated as an empty text block.
+ return "";
+ }
+
+ // 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:
+ case CodeCompletionString::CK_Placeholder:
+ case CodeCompletionString::CK_CurrentParameter:
+ case CodeCompletionString::CK_Informative:
+ case CodeCompletionString::CK_LeftParen:
+ case CodeCompletionString::CK_RightParen:
+ case CodeCompletionString::CK_LeftBracket:
+ case CodeCompletionString::CK_RightBracket:
+ case CodeCompletionString::CK_LeftBrace:
+ case CodeCompletionString::CK_RightBrace:
+ case CodeCompletionString::CK_LeftAngle:
+ case CodeCompletionString::CK_RightAngle:
+ case CodeCompletionString::CK_Comma:
+ case CodeCompletionString::CK_ResultType:
+ case CodeCompletionString::CK_Colon:
+ case CodeCompletionString::CK_SemiColon:
+ case CodeCompletionString::CK_Equal:
+ case CodeCompletionString::CK_HorizontalSpace:
+ case CodeCompletionString::CK_VerticalSpace:
+ return 0;
+
+ case CodeCompletionString::CK_Optional:
+ // Note: treated as an empty text block.
+ return (*CCStr)[chunk_number].Optional;
+ }
+
+ // Should be unreachable, but let's be careful.
+ return 0;
+}
+
+unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ return CCStr? CCStr->size() : 0;
+}
+
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+ unsigned &Value) {
+ if (Memory + sizeof(unsigned) > MemoryEnd)
+ return true;
+
+ memmove(&Value, Memory, sizeof(unsigned));
+ Memory += sizeof(unsigned);
+ return false;
+}
+
+/// \brief The CXCodeCompleteResults structure we allocate internally;
+/// the client only sees the initial CXCodeCompleteResults structure.
+struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
+ /// \brief The memory buffer from which we parsed the results. We
+ /// retain this buffer because the completion strings point into it.
+ llvm::MemoryBuffer *Buffer;
+};
+
+CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
+ const char *source_filename,
+ int num_command_line_args,
+ const char **command_line_args,
+ unsigned num_unsaved_files,
+ struct CXUnsavedFile *unsaved_files,
+ const char *complete_filename,
+ unsigned complete_line,
+ unsigned complete_column) {
+ // The indexer, which is mainly used to determine where diagnostics go.
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ // The set of temporary files that we've built.
+ std::vector<llvm::sys::Path> TemporaryFiles;
+
+ // Build up the arguments for invoking 'clang'.
+ std::vector<const char *> argv;
+
+ // First add the complete path to the 'clang' executable.
+ llvm::sys::Path ClangPath = CXXIdx->getClangPath();
+ argv.push_back(ClangPath.c_str());
+
+ // Add the '-fsyntax-only' argument so that we only perform a basic
+ // syntax check of the code.
+ argv.push_back("-fsyntax-only");
+
+ // Add the appropriate '-code-completion-at=file:line:column' argument
+ // to perform code completion, with an "-Xclang" preceding it.
+ std::string code_complete_at;
+ code_complete_at += complete_filename;
+ code_complete_at += ":";
+ code_complete_at += llvm::utostr(complete_line);
+ code_complete_at += ":";
+ code_complete_at += llvm::utostr(complete_column);
+ argv.push_back("-Xclang");
+ argv.push_back("-code-completion-at");
+ argv.push_back("-Xclang");
+ argv.push_back(code_complete_at.c_str());
+ argv.push_back("-Xclang");
+ argv.push_back("-no-code-completion-debug-printer");
+ argv.push_back("-Xclang");
+ argv.push_back("-code-completion-macros");
+
+ std::vector<std::string> RemapArgs;
+ for (unsigned i = 0; i != num_unsaved_files; ++i) {
+ char tmpFile[L_tmpnam];
+ char *tmpFileName = tmpnam(tmpFile);
+
+ // Write the contents of this unsaved file into the temporary file.
+ llvm::sys::Path SavedFile(tmpFileName);
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
+ if (!ErrorInfo.empty())
+ continue;
+
+ OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
+ OS.close();
+ if (OS.has_error()) {
+ SavedFile.eraseFromDisk();
+ continue;
+ }
+
+ // Remap the file.
+ std::string RemapArg = unsaved_files[i].Filename;
+ RemapArg += ';';
+ RemapArg += tmpFileName;
+ RemapArgs.push_back("-Xclang");
+ RemapArgs.push_back("-remap-file");
+ RemapArgs.push_back("-Xclang");
+ RemapArgs.push_back(RemapArg);
+ TemporaryFiles.push_back(SavedFile);
+ }
+
+ // The pointers into the elements of RemapArgs are stable because we
+ // won't be adding anything to RemapArgs after this point.
+ for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
+ argv.push_back(RemapArgs[i].c_str());
+
+ // Add the source file name (FIXME: later, we'll want to build temporary
+ // file from the buffer, or just feed the source text via standard input).
+ if (source_filename)
+ argv.push_back(source_filename);
+
+ // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
+ for (int i = 0; i < num_command_line_args; ++i)
+ if (const char *arg = command_line_args[i]) {
+ if (strcmp(arg, "-o") == 0) {
+ ++i; // Also skip the matching argument.
+ continue;
+ }
+ if (strcmp(arg, "-emit-ast") == 0 ||
+ strcmp(arg, "-c") == 0 ||
+ strcmp(arg, "-fsyntax-only") == 0) {
+ continue;
+ }
+
+ // Keep the argument.
+ argv.push_back(arg);
+ }
+
+ // Add the null terminator.
+ argv.push_back(NULL);
+
+ // Generate a temporary name for the AST file.
+ char tmpFile[L_tmpnam];
+ char *tmpFileName = tmpnam(tmpFile);
+ llvm::sys::Path ResultsFile(tmpFileName);
+ TemporaryFiles.push_back(ResultsFile);
+
+ // Invoke 'clang'.
+ llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
+ // on Unix or NUL (Windows).
+ std::string ErrMsg;
+ const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
+ llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
+ /* redirects */ &Redirects[0],
+ /* secondsToWait */ 0,
+ /* memoryLimits */ 0, &ErrMsg);
+
+ if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
+ 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)
+ llvm::errs() << ' ' << *I << '\n';
+ }
+ llvm::errs() << '\n';
+ }
+
+ // Parse the resulting source file to find code-completion results.
+ using llvm::MemoryBuffer;
+ using llvm::StringRef;
+ AllocatedCXCodeCompleteResults *Results = 0;
+ if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
+ llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
+ StringRef Buffer = F->getBuffer();
+ for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+ Str < StrEnd;) {
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
+ break;
+
+ CodeCompletionString *CCStr
+ = CodeCompletionString::Deserialize(Str, StrEnd);
+ if (!CCStr)
+ continue;
+
+ if (!CCStr->empty()) {
+ // Vend the code-completion result to the caller.
+ CXCompletionResult Result;
+ Result.CursorKind = (CXCursorKind)KindValue;
+ Result.CompletionString = CCStr;
+ CompletionResults.push_back(Result);
+ }
+ };
+
+ // Allocate the results.
+ Results = new AllocatedCXCodeCompleteResults;
+ Results->Results = new CXCompletionResult [CompletionResults.size()];
+ Results->NumResults = CompletionResults.size();
+ memcpy(Results->Results, CompletionResults.data(),
+ CompletionResults.size() * sizeof(CXCompletionResult));
+ Results->Buffer = F;
+ }
+
+ for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
+ TemporaryFiles[i].eraseFromDisk();
+
+ return Results;
+}
+
+void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
+ if (!ResultsIn)
+ return;
+
+ AllocatedCXCodeCompleteResults *Results
+ = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+
+ for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
+ delete (CXCompletionString *)Results->Results[I].CompletionString;
+ delete [] Results->Results;
+
+ Results->Results = 0;
+ Results->NumResults = 0;
+ delete Results->Buffer;
+ Results->Buffer = 0;
+ delete Results;
+}
+
+} // end extern "C"
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
new file mode 100644
index 000000000000..549c65058d86
--- /dev/null
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -0,0 +1,203 @@
+//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the generation and use of USRs from CXEntities.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "clang/AST/DeclVisitor.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+// Some notes on CXEntity:
+//
+// - 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
+// within a CXTranslationUnit are *not* currently represented by entities.
+// As a result, there will be no entity for the following:
+//
+// module.m: static void Foo() { }
+//
+
+static inline Entity GetEntity(const CXEntity &E) {
+ return Entity::getFromOpaquePtr(E.data);
+}
+
+static inline ASTUnit *GetTranslationUnit(CXTranslationUnit TU) {
+ return (ASTUnit*) TU;
+}
+
+static inline ASTContext &GetASTContext(CXTranslationUnit TU) {
+ return GetTranslationUnit(TU)->getASTContext();
+}
+
+static inline CXEntity NullCXEntity() {
+ CXEntity CE;
+ CE.index = NULL;
+ CE.data = NULL;
+ return CE;
+}
+
+static inline CXEntity MakeEntity(CXIndex CIdx, const Entity &E) {
+ CXEntity CE;
+ CE.index = CIdx;
+ CE.data = E.getAsOpaquePtr();
+ return CE;
+}
+
+static inline Program &GetProgram(CXIndex CIdx) {
+ return ((CIndexer*) CIdx)->getProgram();
+}
+
+//===----------------------------------------------------------------------===//
+// USR generation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class USRGenerator : public DeclVisitor<USRGenerator> {
+ llvm::raw_ostream &Out;
+public:
+ USRGenerator(llvm::raw_ostream &out) : Out(out) {}
+
+ void VisitBlockDecl(BlockDecl *D);
+ void VisitDeclContext(DeclContext *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitNamedDecl(NamedDecl *D);
+ void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitObjCContainerDecl(ObjCContainerDecl *CD);
+ void VisitObjCMethodDecl(ObjCMethodDecl *MD);
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+};
+} // end anonymous namespace
+
+void USRGenerator::VisitBlockDecl(BlockDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ // FIXME: Better support for anonymous blocks.
+ Out << "@B^anon";
+}
+
+void USRGenerator::VisitDeclContext(DeclContext *DC) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
+ Visit(D);
+}
+
+void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@F^" << D->getNameAsString();
+}
+
+void USRGenerator::VisitNamedDecl(NamedDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ const std::string &s = D->getNameAsString();
+ assert(!s.empty());
+ Out << "@^" << s;
+}
+
+void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@N^" << D->getNameAsString();
+}
+
+void USRGenerator::VisitRecordDecl(RecordDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@S^";
+ // FIXME: Better support for anonymous structures.
+ const std::string &s = D->getNameAsString();
+ if (s.empty())
+ Out << "^anon";
+ else
+ Out << s;
+}
+
+void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ Visit(cast<Decl>(D->getDeclContext()));
+ Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
+ Out << DeclarationName(D->getSelector()).getAsString();
+}
+
+void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+ switch (D->getKind()) {
+ default:
+ assert(false && "Invalid ObjC container.");
+ case Decl::ObjCInterface:
+ case Decl::ObjCImplementation:
+ Out << "objc(cs)" << D->getName();
+ break;
+ case Decl::ObjCCategory: {
+ ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ Out << "objc(cy)" << CD->getClassInterface()->getName()
+ << '_' << CD->getName();
+ break;
+ }
+ case Decl::ObjCCategoryImpl: {
+ ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
+ Out << "objc(cy)" << CD->getClassInterface()->getName()
+ << '_' << CD->getName();
+ break;
+ }
+ case Decl::ObjCProtocol:
+ Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName();
+ break;
+ }
+}
+
+void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ Visit(cast<Decl>(D->getDeclContext()));
+ Out << "(py)" << D->getName();
+}
+
+void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+ DeclContext *DC = D->getDeclContext();
+ if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
+ Visit(DCN);
+ Out << "typedef@" << D->getName();
+}
+
+extern "C" {
+
+/// clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any)
+/// in a specified translation unit.
+CXDecl clang_getDeclaration(CXEntity CE, CXTranslationUnit TU) {
+ return (CXDecl) GetEntity(CE).getDecl(GetASTContext(TU));
+}
+
+
+CXEntity clang_getEntityFromDecl(CXIndex CIdx, CXDecl CE) {
+ if (Decl *D = (Decl *) CE)
+ return MakeEntity(CIdx, Entity::get(D, GetProgram(CIdx)));
+ return NullCXEntity();
+}
+
+// FIXME: This is a skeleton implementation. It will be overhauled.
+CXString clang_getDeclUSR(CXDecl D) {
+ assert(D && "Null CXDecl passed to clang_getDeclUSR()");
+ llvm::SmallString<1024> StrBuf;
+ {
+ llvm::raw_svector_ostream Out(StrBuf);
+ USRGenerator UG(Out);
+ UG.Visit(static_cast<Decl*>(D));
+ }
+
+ if (StrBuf.empty())
+ return CIndexer::createCXString(NULL);
+
+ // Return a copy of the string that must be disposed by the caller.
+ return CIndexer::createCXString(StrBuf.c_str(), true);
+}
+
+} // end extern "C"
diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp
new file mode 100644
index 000000000000..f26c8ce8136b
--- /dev/null
+++ b/tools/CIndex/CIndexer.cpp
@@ -0,0 +1,96 @@
+//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Program.h"
+
+#include <cstdio>
+#include <vector>
+#include <sstream>
+
+#ifdef LLVM_ON_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+using namespace clang;
+using namespace idx;
+
+const llvm::sys::Path& CIndexer::getClangPath() {
+ // Did we already compute the path?
+ if (!ClangPath.empty())
+ return ClangPath;
+
+ // Find the location where this library lives (libCIndex.dylib).
+#ifdef LLVM_ON_WIN32
+ MEMORY_BASIC_INFORMATION mbi;
+ char path[MAX_PATH];
+ VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
+ sizeof(mbi));
+ GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
+
+ llvm::sys::Path CIndexPath(path);
+
+ CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("clang");
+ CIndexPath.appendSuffix("exe");
+ CIndexPath.makeAbsolute();
+#else
+ // This silly cast below avoids a C++ warning.
+ Dl_info info;
+ if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
+ assert(0 && "Call to dladdr() failed");
+
+ llvm::sys::Path CIndexPath(info.dli_fname);
+
+ // We now have the CIndex directory, locate clang relative to it.
+ CIndexPath.eraseComponent();
+ CIndexPath.eraseComponent();
+ CIndexPath.appendComponent("bin");
+ CIndexPath.appendComponent("clang");
+#endif
+
+ // Cache our result.
+ ClangPath = CIndexPath;
+ return ClangPath;
+}
+
+std::string CIndexer::getClangResourcesPath() {
+ llvm::sys::Path P = getClangPath();
+
+ if (!P.empty()) {
+ P.eraseComponent(); // Remove /clang from foo/bin/clang
+ P.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ }
+
+ return P.str();
+}
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
new file mode 100644
index 000000000000..4f3cd8b85f71
--- /dev/null
+++ b/tools/CIndex/CIndexer.h
@@ -0,0 +1,88 @@
+//===- CIndexer.h - Clang-C Source Indexing Library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CIndexer, a subclass of Indexer that provides extra
+// functionality needed by the CIndex library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CINDEXER_H
+#define LLVM_CLANG_CINDEXER_H
+
+#include "clang-c/Index.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/Utils.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "llvm/System/Path.h"
+
+using namespace clang;
+
+/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
+/// warnings and errors.
+class IgnoreDiagnosticsClient : public DiagnosticClient {
+public:
+ virtual ~IgnoreDiagnosticsClient() {}
+ virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
+};
+
+class CIndexer : public Indexer {
+ DiagnosticOptions DiagOpts;
+ IgnoreDiagnosticsClient IgnoreDiagClient;
+ llvm::OwningPtr<Diagnostic> TextDiags;
+ Diagnostic IgnoreDiags;
+ bool UseExternalASTGeneration;
+ bool OnlyLocalDecls;
+ bool DisplayDiagnostics;
+
+ llvm::sys::Path ClangPath;
+
+public:
+ explicit CIndexer(Program *prog) : Indexer(*prog),
+ IgnoreDiags(&IgnoreDiagClient),
+ UseExternalASTGeneration(false),
+ OnlyLocalDecls(false),
+ DisplayDiagnostics(false) {
+ TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+ }
+
+ virtual ~CIndexer() { delete &getProgram(); }
+
+ /// \brief Whether we only want to see "local" declarations (that did not
+ /// come from a previous precompiled header). If false, we want to see all
+ /// declarations.
+ bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
+ void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
+
+ bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
+ void setDisplayDiagnostics(bool Display = true) {
+ DisplayDiagnostics = Display;
+ }
+
+ bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
+ void setUseExternalASTGeneration(bool Value) {
+ UseExternalASTGeneration = Value;
+ }
+
+ Diagnostic &getDiags() {
+ return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
+ }
+
+ /// \brief Get the path of the clang binary.
+ const llvm::sys::Path& getClangPath();
+
+ /// \brief Get the path of the clang resource files.
+ std::string getClangResourcesPath();
+
+ static CXString createCXString(const char *String, bool DupString = false);
+};
+
+#endif
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
index a3ff3db2d9b5..52f847ef17da 100644
--- a/tools/CIndex/CMakeLists.txt
+++ b/tools/CIndex/CMakeLists.txt
@@ -19,7 +19,12 @@ set( LLVM_LINK_COMPONENTS
core
)
-add_clang_library(CIndex CIndex.cpp)
+add_clang_library(CIndex
+ CIndex.cpp
+ CIndexCodeCompletion.cpp
+ CIndexUSRs.cpp
+ CIndexer.cpp
+)
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# FIXME: Deal with LLVM_SUBMIT_VERSION?
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 33013f3b66b2..01a0d439297b 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -70,16 +70,30 @@ static const char* GetCursorSource(CXCursor Cursor) {
/* Logic for testing clang_loadTranslationUnit(). */
/******************************************************************************/
+static const char *FileCheckPrefix = "CHECK";
+
+static void PrintDeclExtent(CXDecl Dcl) {
+ CXSourceExtent extent = clang_getDeclExtent(Dcl);
+ printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column,
+ extent.end.line, extent.end.column);
+}
+
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),
- clang_getCursorLine(Cursor),
- clang_getCursorColumn(Cursor));
+ printf("// %s: %s:%d:%d: ", FileCheckPrefix,
+ GetCursorSource(Cursor),
+ clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
PrintCursor(Cursor);
+
string = clang_getDeclSpelling(Dcl);
- printf(" [Context=%s]\n", clang_getCString(string));
+ printf(" [Context=%s]", clang_getCString(string));
clang_disposeString(string);
+
+ PrintDeclExtent(clang_getCursorDecl(Cursor));
+
+ printf("\n");
}
}
@@ -87,15 +101,19 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
CXClientData Filter) {
if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
CXString string;
- printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
- clang_getCursorLine(Cursor),
- clang_getCursorColumn(Cursor));
+ printf("// %s: %s:%d:%d: ", FileCheckPrefix,
+ GetCursorSource(Cursor), clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
PrintCursor(Cursor);
string = clang_getTranslationUnitSpelling(Unit);
- printf(" [Context=%s]\n",
+ printf(" [Context=%s]",
basename(clang_getCString(string)));
clang_disposeString(string);
+
+ PrintDeclExtent(Cursor.decl);
+ printf("\n");
+
clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
}
}
@@ -130,7 +148,7 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
/* Nothing found here; that's fine. */
} else if (Ref.kind != CXCursor_FunctionDecl) {
CXString string;
- printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
+ printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
curLine, curColumn);
PrintCursor(Ref);
string = clang_getDeclSpelling(Ref.decl);
@@ -141,12 +159,45 @@ static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
}
}
+/******************************************************************************/
+/* USR testing. */
+/******************************************************************************/
+
+static void USRDeclVisitor(CXDecl D, CXCursor C, CXClientData Filter) {
+ if (!Filter || (C.kind == *(enum CXCursorKind *)Filter)) {
+ CXString USR = clang_getDeclUSR(C.decl);
+ if (!USR.Spelling) {
+ clang_disposeString(USR);
+ return;
+ }
+ printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling);
+ PrintDeclExtent(C.decl);
+ printf("\n");
+ clang_disposeString(USR);
+ }
+}
+
+static void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor,
+ CXClientData Filter) {
+ if (Cursor.decl) {
+ /* USRDeclVisitor(Unit, Cursor.decl, Cursor, Filter);*/
+ clang_loadDeclaration(Cursor.decl, USRDeclVisitor, 0);
+ }
+}
+
+/******************************************************************************/
+/* Loading ASTs/source. */
+/******************************************************************************/
+
static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
- const char *filter) {
+ const char *filter, const char *prefix,
+ CXTranslationUnitIterator Visitor) {
enum CXCursorKind K = CXCursor_NotImplemented;
- CXTranslationUnitIterator Visitor = TranslationUnitVisitor;
enum CXCursorKind *ck = &K;
+ if (prefix)
+ FileCheckPrefix = prefix;
+
/* Perform some simple filtering. */
if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
@@ -165,7 +216,9 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
return 0;
}
-int perform_test_load_tu(const char *file, const char *filter) {
+int perform_test_load_tu(const char *file, const char *filter,
+ const char *prefix,
+ CXTranslationUnitIterator Visitor) {
CXIndex Idx;
CXTranslationUnit TU;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
@@ -175,10 +228,11 @@ int perform_test_load_tu(const char *file, const char *filter) {
if (!CreateTranslationUnit(Idx, file, &TU))
return 1;
- return perform_test_load(Idx, TU, filter);
+ return perform_test_load(Idx, TU, filter, prefix, Visitor);
}
-int perform_test_load_source(int argc, const char **argv, const char *filter) {
+int perform_test_load_source(int argc, const char **argv, const char *filter,
+ CXTranslationUnitIterator Visitor) {
const char *UseExternalASTs =
getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
CXIndex Idx;
@@ -196,7 +250,7 @@ int perform_test_load_source(int argc, const char **argv, const char *filter) {
return 1;
}
- return perform_test_load(Idx, TU, filter);
+ return perform_test_load(Idx, TU, filter, NULL, Visitor);
}
/******************************************************************************/
@@ -207,7 +261,7 @@ static void print_cursor_file_scan(CXCursor cursor,
unsigned start_line, unsigned start_col,
unsigned end_line, unsigned end_col,
const char *prefix) {
- printf("// CHECK");
+ printf("// %s: ", FileCheckPrefix);
if (prefix)
printf("-%s", prefix);
printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
@@ -356,6 +410,11 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
case CXCompletionChunk_RightAngle: return "RightAngle";
case CXCompletionChunk_Comma: return "Comma";
case CXCompletionChunk_ResultType: return "ResultType";
+ case CXCompletionChunk_Colon: return "Colon";
+ case CXCompletionChunk_SemiColon: return "SemiColon";
+ case CXCompletionChunk_Equal: return "Equal";
+ case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
+ case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
}
return "Unknown";
@@ -531,14 +590,26 @@ int perform_code_completion(int argc, const char **argv) {
/* Command line processing. */
/******************************************************************************/
+static CXTranslationUnitIterator GetVisitor(const char *s) {
+ if (s[0] == '\0')
+ return TranslationUnitVisitor;
+ if (strcmp(s, "-usrs") == 0)
+ return USRVisitor;
+ return NULL;
+}
+
static void print_usage(void) {
fprintf(stderr,
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" 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"
- " c-index-test -test-load-source <symbol filter> {<args>}*\n\n"
- " <symbol filter> options for -test-load-tu and -test-load-source:\n%s",
+ " c-index-test -test-load-tu <AST file> <symbol filter> "
+ "[FileCheck prefix]\n"
+ " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
+ "[FileCheck prefix]\n"
+ " c-index-test -test-load-source <symbol filter> {<args>}*\n"
+ " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n"
+ " <symbol filter> values:\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"
@@ -552,11 +623,17 @@ static void print_usage(void) {
int main(int argc, const char **argv) {
if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
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)
+ else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
+ CXTranslationUnitIterator I = GetVisitor(argv[1] + 13);
+ if (I)
+ return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I);
+ }
+ else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
+ CXTranslationUnitIterator I = GetVisitor(argv[1] + 17);
+ if (I)
+ return perform_test_load_source(argc - 3, argv + 3, argv[2], I);
+ }
+ else 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/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index eb1f60ccb645..d2f1017c2151 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -14,10 +14,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/FileManager.h"
-#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"
@@ -30,7 +26,6 @@
#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"
#include "llvm/Support/ErrorHandling.h"
@@ -38,8 +33,6 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/DynamicLibrary.h"
-#include "llvm/System/Host.h"
-#include "llvm/System/Path.h"
#include "llvm/System/Signals.h"
#include "llvm/Target/TargetSelect.h"
#include <cstdio>
@@ -207,13 +200,13 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
Diags);
// Infer the builtin include path if unspecified.
- if (Clang.getInvocation().getHeaderSearchOpts().UseBuiltinIncludes &&
- Clang.getInvocation().getHeaderSearchOpts().ResourceDir.empty())
- Clang.getInvocation().getHeaderSearchOpts().ResourceDir =
+ if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
+ Clang.getHeaderSearchOpts().ResourceDir.empty())
+ Clang.getHeaderSearchOpts().ResourceDir =
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Honor -help.
- if (Clang.getInvocation().getFrontendOpts().ShowHelp) {
+ if (Clang.getFrontendOpts().ShowHelp) {
llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1OptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org");
@@ -223,7 +216,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Honor -version.
//
// FIXME: Use a better -version message?
- if (Clang.getInvocation().getFrontendOpts().ShowVersion) {
+ if (Clang.getFrontendOpts().ShowVersion) {
llvm::cl::PrintVersionMessage();
return 0;
}
@@ -249,86 +242,18 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error;
}
- // If there were any errors in processing arguments, exit now.
- if (Clang.getDiagnostics().getNumErrors())
- return 1;
-
- // 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 -cc1 version " CLANG_VERSION_STRING
- << " based upon " << PACKAGE_STRING
- << " hosted on " << llvm::sys::getHostTriple() << "\n";
-
- if (Clang.getFrontendOpts().ShowTimers)
- 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
- // filesystem.
- Clang.createFileManager();
-
- // Create the source manager.
- Clang.createSourceManager();
- } else {
- // Reset the ID tables if we are reusing the SourceManager.
- Clang.getSourceManager().clearIDTables();
- }
-
- // Create the preprocessor.
- Clang.createPreprocessor();
- }
-
+ // If there were errors in processing arguments, don't do anything else.
+ bool Success = false;
+ if (!Clang.getDiagnostics().getNumErrors()) {
+ // Create and execute the frontend action.
llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(Clang));
- if (!Act)
- break;
-
- if (Act->BeginSourceFile(Clang, InFile, IsAST)) {
- Act->Execute();
- Act->EndSourceFile();
- }
+ if (Act)
+ Success = Clang.ExecuteAction(*Act);
}
- if (Clang.getDiagnosticOpts().ShowCarets)
- if (unsigned NumDiagnostics = Clang.getDiagnostics().getNumDiagnostics())
- fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
- (NumDiagnostics == 1 ? "" : "s"));
-
- if (Clang.getFrontendOpts().ShowStats) {
- Clang.getFileManager().PrintStats();
- fprintf(stderr, "\n");
- }
-
- // Return the appropriate status when verifying diagnostics.
- //
- // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
- // this.
- if (Clang.getDiagnosticOpts().VerifyDiagnostics)
- return static_cast<VerifyDiagnosticsClient&>(
- Clang.getDiagnosticClient()).HadErrors();
-
// Managed static deconstruction. Useful for making things like
// -time-passes usable.
llvm::llvm_shutdown();
- return (Clang.getDiagnostics().getNumErrors() != 0);
+ return !Success;
}
diff --git a/utils/VtableTest/Makefile b/utils/VtableTest/Makefile
new file mode 100644
index 000000000000..0e060267903a
--- /dev/null
+++ b/utils/VtableTest/Makefile
@@ -0,0 +1,21 @@
+GXX := llvm-g++-4.2
+CLANGXX := clang++
+
+all: one
+
+test.cc: gen.cc
+ g++ gen.cc -o gen
+ gen >test.cc
+
+test-gcc.sum: test.cc
+ time $(GXX) test.cc -o test-gcc.s -S
+ $(GXX) test-gcc.s -o test-gcc
+ test-gcc >test-gcc.sum
+
+test-clang.sum: test.cc
+ time $(CLANGXX) test.cc -o test-clang.s -S
+ $(CLANGXX) test-clang.s -o test-clang
+ test-clang >test-clang.sum
+
+one: test-gcc.sum test-clang.sum
+ cmp test-gcc.sum test-clang.sum
diff --git a/utils/VtableTest/check-zti b/utils/VtableTest/check-zti
new file mode 100755
index 000000000000..bf5b045d81d2
--- /dev/null
+++ b/utils/VtableTest/check-zti
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+N_STRUCTS=300
+
+# Utility routine to "hand" check type infos.
+
+let i=1;
+while [ $i != $N_STRUCTS ]; do
+ sed -n "/^__ZTI.*s$i:/,/\.[sg][el]/p" test-clang.s |
+ grep -v '\.[sg][el]' | sed 's/(\([0-9][0-9]*\))/\1/' >test-clang-zti
+ sed -n "/^__ZTI.*s$i:/,/\.[sg][el]/p" test-gcc.s |
+ grep -v '\.[sg][el]' | sed 's/(\([0-9][0-9]*\))/\1/' >test-gcc-zti
+ diff -U3 test-gcc-zti test-clang-zti
+ if [ $? != 0 ]; then
+ echo "FAIL: s$i type info"
+ else
+ echo "PASS: s$i type info"
+ fi
+ let i=i+1
+done
diff --git a/utils/VtableTest/check-ztt b/utils/VtableTest/check-ztt
new file mode 100755
index 000000000000..77cf99d53598
--- /dev/null
+++ b/utils/VtableTest/check-ztt
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+N_STRUCTS=300
+
+# Utility routine to "hand" check VTTs.
+
+let i=1;
+while [ $i != $N_STRUCTS ]; do
+ sed -n "/^__ZTT.*s$i:/,/\.[sg][el]/p" test-clang.s |
+ grep -v '\.[sg][el]' | sed 's/(\([0-9][0-9]*\))/\1/' >test-clang-ztt
+ sed -n "/^__ZTT.*s$i:/,/\.[sg][el]/p" test-gcc.s |
+ grep -v '\.[sg][el]' | sed 's/(\([0-9][0-9]*\))/\1/' >test-gcc-ztt
+ diff -U3 test-gcc-ztt test-clang-ztt
+ if [ $? != 0 ]; then
+ echo "FAIL: s$i VTT"
+ else
+ echo "PASS: s$i VTT"
+ fi
+ let i=i+1
+done
diff --git a/utils/VtableTest/check-zvt b/utils/VtableTest/check-zvt
new file mode 100755
index 000000000000..d8b93bd01fa1
--- /dev/null
+++ b/utils/VtableTest/check-zvt
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+N_STRUCTS=300
+
+# Utility routine to "hand" check vtables.
+
+let i=1;
+while [ $i != $N_STRUCTS ]; do
+ sed -n "/^__ZTV.*s$i:/,/\.[sg][el]/p" test-clang.s | grep -v '\.[sg][el]' >test-clang-ztv
+ sed -n "/^__ZTV.*s$i:/,/\.[sg][el]/p" test-gcc.s | grep -v '\.[sg][el]' >test-gcc-ztv
+ diff -U3 test-gcc-ztv test-clang-ztv
+ if [ $? != 0 ]; then
+ echo "FAIL: s$i vtable"
+ else
+ echo "PASS: s$i vtable"
+ fi
+ let i=i+1
+done
diff --git a/utils/VtableTest/gen.cc b/utils/VtableTest/gen.cc
new file mode 100644
index 000000000000..8396f8d138b3
--- /dev/null
+++ b/utils/VtableTest/gen.cc
@@ -0,0 +1,350 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#define N_FIELDS 7
+#define N_FUNCS 128
+#define FUNCSPACING 20
+#define N_STRUCTS 180 /* 1280 */
+#define N_BASES 6
+#define COVARIANT 0
+
+const char *simple_types[] = { "bool", "char", "short", "int", "float",
+ "double", "long double", "wchar_t", "void *",
+ "char *"
+};
+
+void gl(const char *c) {
+ printf("%s\n", c);
+}
+
+void g(const char *c) {
+ printf("%s", c);
+}
+
+void g(int i) {
+ printf("%d", i);
+}
+
+int uuid = 0;
+char base_present[N_STRUCTS][N_STRUCTS];
+
+// The return type for each function when doing covariant testcase generation.
+short ret_types[N_STRUCTS][N_FUNCS*FUNCSPACING];
+
+bool is_ambiguous(int s, int base) {
+ for (int i = 0; i < N_STRUCTS; ++i) {
+ if ((base_present[base][i] & base_present[s][i]) == 1)
+ return true;
+ }
+ return false;
+}
+
+void add_bases(int s, int base) {
+ for (int i = 0; i < N_STRUCTS; ++i)
+ base_present[s][i] |= base_present[base][i];
+ if (!COVARIANT)
+ return;
+ for (int i = 0; i < N_FUNCS*FUNCSPACING; ++i) {
+ if (!ret_types[base][i])
+ continue;
+ if (!ret_types[s][i]) {
+ ret_types[s][i] = ret_types[base][i];
+ continue;
+ }
+ if (base_present[ret_types[base][i]][ret_types[s][i]])
+ // If the return type of the function from this base dominates
+ ret_types[s][i] = ret_types[base][i];
+ if (base_present[ret_types[s][i]][ret_types[base][i]])
+ // If a previous base dominates
+ continue;
+ // If neither dominates, we'll use this class.
+ ret_types[s][i] = s;
+ }
+}
+
+// This contains the class that has the final override for
+// each class, for each function.
+short final_override[N_STRUCTS][N_FUNCS*FUNCSPACING];
+
+void gs(int s) {
+ bool polymorphic = false;
+
+ static int bases[N_BASES];
+ int i_bases = random() % (N_BASES*2);
+ if (i_bases >= N_BASES)
+ // PARAM: 1/2 of all clases should have no bases
+ i_bases = 0;
+ int n_bases = 0;
+ bool first_base = true;
+
+ // PARAM: 3/4 of all should be class, the rest are structs
+ if (random() % 4 == 0)
+ g("struct s");
+ else
+ g("class s");
+ g(s);
+ int old_base = -1;
+ if (s == 0 || s == 1)
+ i_bases = 0;
+ while (i_bases) {
+ --i_bases;
+ int base = random() % (s-1) + 1;
+ if (!base_present[s][base]) {
+ if (is_ambiguous(s, base))
+ continue;
+ if (first_base) {
+ first_base = false;
+ g(": ");
+ } else
+ g(", ");
+ int base_type = 1;
+ if (random()%8 == 0) {
+ // PARAM: 1/8th the bases are virtual
+ g("virtual ");
+ // We have a vtable and rtti, but technically we're not polymorphic
+ // polymorphic = true;
+ base_type = 3;
+ }
+ // PARAM: 1/4 are public, 1/8 are privare, 1/8 are protected, the reset, default
+ int base_protection = 0;
+ if (!COVARIANT)
+ base_protection = random()%8;
+ switch (base_protection) {
+ case 0:
+ case 1:
+ g("public "); break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ case 6:
+ g("private "); break;
+ case 7:
+ g("protected "); break;
+ }
+ g("s");
+ add_bases(s, base);
+ bases[n_bases] = base;
+ base_present[s][base] = base_type;
+ ++n_bases;
+ g(base);
+ old_base = base;
+ }
+ }
+ gl(" {");
+
+ /* Fields */
+ int n_fields = N_FIELDS == 0 ? 0 : random() % (N_FIELDS*4);
+ // PARAM: 3/4 of all structs should have no members
+ if (n_fields >= N_FIELDS)
+ n_fields = 0;
+ for (int i = 0; i < n_fields; ++i) {
+ int t = random() % (sizeof(simple_types) / sizeof(simple_types[0]));
+ g(" "); g(simple_types[t]); g(" field"); g(i); gl(";");
+ }
+
+ /* Virtual functions */
+ static int funcs[N_FUNCS*FUNCSPACING];
+ // PARAM: 1/2 of all structs should have no virtual functions
+ int n_funcs = random() % (N_FUNCS*2);
+ if (n_funcs > N_FUNCS)
+ n_funcs = 0;
+ int old_func = -1;
+ for (int i = 0; i < n_funcs; ++i) {
+ int fn = old_func + random() % FUNCSPACING + 1;
+ funcs[i] = fn;
+ int ret_type = 0;
+ if (COVARIANT) {
+ ret_type = random() % s + 1;
+ if (!base_present[s][ret_type]
+ || !base_present[ret_type][ret_types[s][fn]])
+ if (ret_types[s][fn]) {
+ printf(" // Found one for s%d for s%d* fun%d.\n", s,
+ ret_types[s][fn], fn);
+ ret_type = ret_types[s][fn];
+ } else
+ ret_type = s;
+ else
+ printf(" // Wow found one for s%d for fun%d.\n", s, fn);
+ ret_types[s][fn] = ret_type;
+ }
+ if (ret_type) {
+ g(" virtual s"); g(ret_type); g("* fun");
+ } else
+ g(" virtual void fun");
+ g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
+ if (ret_type)
+ gl("); return 0; }");
+ else
+ gl("); }");
+ final_override[s][fn] = s;
+ old_func = fn;
+ }
+
+ // Add required overriders for correctness
+ for (int i = 0; i < n_bases; ++i) {
+ // For each base
+ int base = bases[i];
+ for (int fn = 0; fn < N_FUNCS*FUNCSPACING; ++fn) {
+ // For each possible function
+ int new_base = final_override[base][fn];
+ if (new_base == 0)
+ // If the base didn't have a final overrider, skip
+ continue;
+
+ int prev_base = final_override[s][fn];
+ if (prev_base == s)
+ // Skip functions defined in this class
+ continue;
+
+ // If we don't want to change the info, skip
+ if (prev_base == new_base)
+ continue;
+
+ if (prev_base == 0) {
+ // record the final override
+ final_override[s][fn] = new_base;
+ continue;
+ }
+
+ if (base_present[prev_base][new_base]) {
+ // The previous base dominates the new base, no update necessary
+ printf(" // No override for fun%d in s%d as s%d dominates s%d.\n",
+ fn, s, prev_base, new_base);
+ continue;
+ }
+
+ if (base_present[new_base][prev_base]) {
+ // The new base dominates the old base, no override necessary
+ printf(" // No override for fun%d in s%d as s%d dominates s%d.\n",
+ fn, s, new_base, prev_base);
+ // record the final override
+ final_override[s][fn] = new_base;
+ continue;
+ }
+
+ printf(" // Found we needed override for fun%d in s%d.\n", fn, s);
+
+ // record the final override
+ funcs[n_funcs++] = fn;
+ if (n_funcs == (N_FUNCS*FUNCSPACING-1))
+ abort();
+ int ret_type = 0;
+ if (COVARIANT) {
+ if (!ret_types[s][fn]) {
+ ret_types[s][fn] = ret_type = s;
+ } else {
+ ret_type = ret_types[s][fn];
+ if (ret_type != s)
+ printf(" // Calculated return type in s%d as s%d* fun%d.\n",
+ s, ret_type, fn);
+ }
+ }
+ if (ret_type) {
+ g(" virtual s"); g(ret_type); g("* fun");
+ } else
+ g(" virtual void fun");
+ g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
+ if (ret_type)
+ gl("); return 0; }");
+ else
+ gl("); }");
+ final_override[s][fn] = s;
+ }
+ }
+
+ gl("public:");
+ gl(" void calc(char *t) {");
+
+ // mix in the type number
+ g(" mix(\"type num\", "); g(s); gl(");");
+ // mix in the size
+ g(" mix(\"type size\", sizeof (s"); g(s); gl("));");
+ // mix in the this offset
+ gl(" mix(\"subobject offset\", (char *)this - t);");
+ if (n_funcs)
+ polymorphic = true;
+ if (polymorphic) {
+ // mix in offset to the complete object under construction
+ gl(" mix(\"real top v current top\", t - (char *)dynamic_cast<void*>(this));");
+ }
+
+ /* check base layout and overrides */
+ for (int i = 0; i < n_bases; ++i) {
+ g(" calc_s"); g(bases[i]); gl("(t);");
+ }
+
+ if (polymorphic) {
+ /* check dynamic_cast to each direct base */
+ for (int i = 0; i < n_bases; ++i) {
+ g(" if ((char *)dynamic_cast<s"); g(bases[i]); gl("*>(this))");
+ g(" mix(\"base dyn cast\", t - (char *)dynamic_cast<s"); g(bases[i]); gl("*>(this));");
+ g(" else mix(\"no dyncast\", "); g(++uuid); gl(");");
+ }
+ }
+
+ /* check field layout */
+ for (int i = 0; i < n_fields; ++i) {
+ g(" mix(\"field offset\", (char *)&field"); g(i); gl(" - (char *)this);");
+ }
+ if (n_fields == 0) {
+ g(" mix(\"no fields\", "); g(++uuid); gl(");");
+ }
+
+ /* check functions */
+ for (int i = 0; i < n_funcs; ++i) {
+ g(" fun"); g(funcs[i]); gl("(t);");
+ }
+ if (n_funcs == 0) {
+ g(" mix(\"no funcs\", "); g(++uuid); gl(");");
+ }
+
+ gl(" }");
+
+ // default ctor
+ g(" s"); g(s); g("() ");
+ first_base = true;
+ for (int i = 0; i < n_bases; ++i) {
+ if (first_base) {
+ g(": ");
+ first_base = false;
+ } else
+ g(", ");
+ g("s"); g(bases[i]); g("((char *)this)");
+ }
+ gl(" { calc((char *)this); }");
+ g(" ~s"); g(s); gl("() { calc((char *)this); }");
+
+ // ctor with this to the complete object
+ g(" s"); g(s); gl("(char *t) { calc(t); }");
+ g(" void calc_s"); g(s); gl("(char *t) { calc(t); }");
+ g("} a"); g(s); gl(";");
+}
+
+main(int argc, char **argv) {
+ unsigned seed = 0;
+ char state[16];
+ if (argc > 1)
+ seed = atol(argv[1]);
+
+ initstate(seed, state, sizeof(state));
+ gl("extern \"C\" int printf(const char *...);");
+ gl("");
+ gl("long long sum;");
+ gl("void mix(const char *desc, long long i) {");
+ // If this ever becomes too slow, we can remove this after we improve the
+ // mixing function
+ gl(" printf(\"%s: %lld\\n\", desc, i);");
+ gl(" sum += ((sum ^ i) << 3) + (sum<<1) - i;");
+ gl("}");
+ gl("");
+ // PARAM: Randomly size testcases or large testcases?
+ int n_structs = /* random() % */ N_STRUCTS;
+ for (int i = 1; i < n_structs; ++i)
+ gs(i);
+ gl("int main() {");
+ gl(" printf(\"%llx\\n\", sum);");
+ gl("}");
+ return 0;
+}
diff --git a/utils/clang-completion-mode.el b/utils/clang-completion-mode.el
index 4164eac7ac84..873127f5cd33 100644
--- a/utils/clang-completion-mode.el
+++ b/utils/clang-completion-mode.el
@@ -144,12 +144,21 @@ This variable will typically contain include paths, e.g., -I~/MyProject."
))))
(defun clang-complete ()
- (let ((ccstring (concat (buffer-file-name)
- ":"
- (number-to-string (+ 1 (current-line)))
- ":"
- (number-to-string (+ 1 (current-column)))))
- (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
+ (let* ((cc-point (concat (buffer-file-name)
+ ":"
+ (number-to-string (+ 1 (current-line)))
+ ":"
+ (number-to-string (+ 1 (current-column)))))
+ (cc-pch (if (equal clang-completion-prefix-header "") nil
+ (list "-include-pch"
+ (concat clang-completion-prefix-header ".pch"))))
+ (cc-flags (if (listp clang-flags) clang-flags nil))
+ (cc-command (append `(,clang "-cc1" "-fsyntax-only")
+ cc-flags
+ cc-pch
+ `("-code-completion-at" ,cc-point)
+ (list (buffer-file-name))))
+ (cc-buffer-name (concat "*Clang Completion for " (buffer-name) "*")))
;; Start the code-completion process
(if (buffer-file-name)
(progn
@@ -162,18 +171,9 @@ This variable will typically contain include paths, e.g., -I~/MyProject."
(setq clang-result-string "")
(setq clang-completion-buffer cc-buffer-name)
- (let ((cc-proc
- (if (equal clang-completion-prefix-header "")
- (start-process "Clang Code-Completion" cc-buffer-name
- clang "-cc1" "-fsyntax-only"
- "-code-completion-at" ccstring
- (buffer-file-name))
- (start-process "Clang Code-Completion" cc-buffer-name
- clang "-cc1" "-fsyntax-only"
- "-code-completion-at" ccstring
- "-include-pch"
- (concat clang-completion-prefix-header ".pch")
- (buffer-file-name)))))
+ (let ((cc-proc (apply 'start-process
+ (append (list "Clang Code-Completion" cc-buffer-name)
+ cc-command))))
(set-process-filter cc-proc 'clang-completion-stash-filter)
(set-process-sentinel cc-proc 'clang-completion-sentinel)
)))))