summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--clang.xcodeproj/project.pbxproj42
-rw-r--r--examples/clang-interpreter/main.cpp3
-rw-r--r--include/clang/AST/ASTContext.h48
-rw-r--r--include/clang/AST/CXXInheritance.h132
-rw-r--r--include/clang/AST/CanonicalType.h11
-rw-r--r--include/clang/AST/Decl.h57
-rw-r--r--include/clang/AST/DeclBase.h43
-rw-r--r--include/clang/AST/DeclCXX.h35
-rw-r--r--include/clang/AST/DeclContextInternals.h24
-rw-r--r--include/clang/AST/DeclFriend.h6
-rw-r--r--include/clang/AST/DeclTemplate.h6
-rw-r--r--include/clang/AST/DeclarationName.h2
-rw-r--r--include/clang/AST/DependentDiagnostic.h183
-rw-r--r--include/clang/AST/Expr.h51
-rw-r--r--include/clang/AST/ExprCXX.h4
-rw-r--r--include/clang/AST/Type.h235
-rw-r--r--include/clang/AST/TypeLoc.h6
-rw-r--r--include/clang/AST/TypeNodes.def2
-rw-r--r--include/clang/Analysis/AnalysisContext.h31
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h45
-rw-r--r--include/clang/Basic/Builtins.def15
-rw-r--r--include/clang/Basic/BuiltinsX86.def8
-rw-r--r--include/clang/Basic/CMakeLists.txt8
-rw-r--r--include/clang/Basic/Diagnostic.h160
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticGroups.td5
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td22
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td82
-rw-r--r--include/clang/Basic/PartialDiagnostic.h177
-rw-r--r--include/clang/Basic/SourceLocation.h1
-rw-r--r--include/clang/Checker/BugReporter/BugReporter.h7
-rw-r--r--include/clang/Checker/BugReporter/BugType.h7
-rw-r--r--include/clang/Checker/BugReporter/PathDiagnostic.h18
-rw-r--r--include/clang/Checker/DomainSpecific/CocoaConventions.h1
-rw-r--r--include/clang/Checker/PathSensitive/BasicValueFactory.h1
-rw-r--r--include/clang/Checker/PathSensitive/Checker.h8
-rw-r--r--include/clang/Checker/PathSensitive/Environment.h5
-rw-r--r--include/clang/Checker/PathSensitive/ExplodedGraph.h4
-rw-r--r--include/clang/Checker/PathSensitive/GRBlockCounter.h9
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h10
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h24
-rw-r--r--include/clang/Checker/PathSensitive/GRSimpleAPICheck.h9
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h34
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h3
-rw-r--r--include/clang/Checker/PathSensitive/GRTransferFuncs.h10
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h10
-rw-r--r--include/clang/Checker/PathSensitive/Store.h3
-rw-r--r--include/clang/Checker/PathSensitive/SymbolManager.h10
-rw-r--r--include/clang/CodeGen/CodeGenOptions.h1
-rw-r--r--include/clang/Driver/CC1Options.td3
-rw-r--r--include/clang/Driver/CMakeLists.txt4
-rw-r--r--include/clang/Driver/Driver.h9
-rw-r--r--include/clang/Driver/Options.td3
-rw-r--r--include/clang/Frontend/HeaderSearchOptions.h6
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h2
-rw-r--r--include/clang/Frontend/TypeXML.def2
-rw-r--r--include/clang/Lex/PPCallbacks.h11
-rw-r--r--include/clang/Lex/Preprocessor.h4
-rw-r--r--include/clang/Lex/PreprocessorLexer.h1
-rw-r--r--include/clang/Parse/Action.h3
-rw-r--r--lib/AST/ASTContext.cpp194
-rw-r--r--lib/AST/ASTImporter.cpp22
-rw-r--r--lib/AST/CMakeLists.txt4
-rw-r--r--lib/AST/CXXInheritance.cpp237
-rw-r--r--lib/AST/Decl.cpp6
-rw-r--r--lib/AST/DeclBase.cpp96
-rw-r--r--lib/AST/DeclCXX.cpp133
-rw-r--r--lib/AST/Expr.cpp62
-rw-r--r--lib/AST/Type.cpp36
-rw-r--r--lib/AST/TypePrinter.cpp22
-rw-r--r--lib/Analysis/AnalysisContext.cpp28
-rw-r--r--lib/Analysis/CFG.cpp2
-rw-r--r--lib/Analysis/PrintfFormatString.cpp2
-rw-r--r--lib/Basic/Diagnostic.cpp85
-rw-r--r--lib/Basic/SourceManager.cpp20
-rw-r--r--lib/Basic/Targets.cpp1
-rw-r--r--lib/Checker/AdjustedReturnValueChecker.cpp4
-rw-r--r--lib/Checker/AggExprVisitor.cpp55
-rw-r--r--lib/Checker/ArrayBoundChecker.cpp4
-rw-r--r--lib/Checker/AttrNonNullChecker.cpp4
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp3
-rw-r--r--lib/Checker/BugReporter.cpp6
-rw-r--r--lib/Checker/BugReporterVisitors.cpp1
-rw-r--r--lib/Checker/CFRefCount.cpp3
-rw-r--r--lib/Checker/CMakeLists.txt17
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp6
-rw-r--r--lib/Checker/CastToStructChecker.cpp1
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp40
-rw-r--r--lib/Checker/DereferenceChecker.cpp59
-rw-r--r--lib/Checker/DivZeroChecker.cpp3
-rw-r--r--lib/Checker/Environment.cpp5
-rw-r--r--lib/Checker/FixedAddressChecker.cpp3
-rw-r--r--lib/Checker/GRBlockCounter.cpp43
-rw-r--r--lib/Checker/GRCoreEngine.cpp10
-rw-r--r--lib/Checker/GRExprEngine.cpp139
-rw-r--r--lib/Checker/GRState.cpp14
-rw-r--r--lib/Checker/MacOSXAPIChecker.cpp2
-rw-r--r--lib/Checker/MallocChecker.cpp1
-rw-r--r--lib/Checker/MemRegion.cpp4
-rw-r--r--lib/Checker/NSErrorChecker.cpp2
-rw-r--r--lib/Checker/NoReturnFunctionChecker.cpp82
-rw-r--r--lib/Checker/PathDiagnostic.cpp4
-rw-r--r--lib/Checker/PointerArithChecker.cpp3
-rw-r--r--lib/Checker/PointerSubChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp108
-rw-r--r--lib/Checker/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/Checker/ReturnStackAddressChecker.cpp2
-rw-r--r--lib/Checker/ReturnUndefChecker.cpp5
-rw-r--r--lib/Checker/SymbolManager.cpp2
-rw-r--r--lib/Checker/UndefBranchChecker.cpp1
-rw-r--r--lib/Checker/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--lib/Checker/UndefResultChecker.cpp2
-rw-r--r--lib/Checker/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/Checker/UndefinedAssignmentChecker.cpp40
-rw-r--r--lib/Checker/UnixAPIChecker.cpp5
-rw-r--r--lib/Checker/VLASizeChecker.cpp2
-rw-r--r--lib/CodeGen/CGBlocks.cpp20
-rw-r--r--lib/CodeGen/CGBlocks.h1
-rw-r--r--lib/CodeGen/CGBuiltin.cpp17
-rw-r--r--lib/CodeGen/CGCXX.cpp315
-rw-r--r--lib/CodeGen/CGCall.cpp48
-rw-r--r--lib/CodeGen/CGCall.h15
-rw-r--r--lib/CodeGen/CGClass.cpp327
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp72
-rw-r--r--lib/CodeGen/CGDebugInfo.h5
-rw-r--r--lib/CodeGen/CGExpr.cpp15
-rw-r--r--lib/CodeGen/CGExprAgg.cpp7
-rw-r--r--lib/CodeGen/CGExprCXX.cpp48
-rw-r--r--lib/CodeGen/CGExprComplex.cpp30
-rw-r--r--lib/CodeGen/CGExprConstant.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp9
-rw-r--r--lib/CodeGen/CGObjC.cpp27
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp6
-rw-r--r--lib/CodeGen/CGObjCMac.cpp23
-rw-r--r--lib/CodeGen/CGObjCRuntime.h1
-rw-r--r--lib/CodeGen/CGRTTI.cpp156
-rw-r--r--lib/CodeGen/CGRecordLayout.h95
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp176
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.h142
-rw-r--r--lib/CodeGen/CGStmt.cpp3
-rw-r--r--lib/CodeGen/CGTemporaries.cpp15
-rw-r--r--lib/CodeGen/CGVTT.cpp608
-rw-r--r--lib/CodeGen/CGVtable.cpp2089
-rw-r--r--lib/CodeGen/CGVtable.h257
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp8
-rw-r--r--lib/CodeGen/CodeGenFunction.h70
-rw-r--r--lib/CodeGen/CodeGenModule.cpp32
-rw-r--r--lib/CodeGen/CodeGenModule.h37
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp48
-rw-r--r--lib/CodeGen/CodeGenTypes.h82
-rw-r--r--lib/CodeGen/Mangle.cpp98
-rw-r--r--lib/CodeGen/Mangle.h16
-rw-r--r--lib/Driver/CMakeLists.txt2
-rw-r--r--lib/Driver/Driver.cpp26
-rw-r--r--lib/Driver/HostInfo.cpp10
-rw-r--r--lib/Driver/Tools.cpp65
-rw-r--r--lib/Frontend/ASTUnit.cpp2
-rw-r--r--lib/Frontend/CompilerInstance.cpp4
-rw-r--r--lib/Frontend/CompilerInvocation.cpp3
-rw-r--r--lib/Frontend/DependencyFile.cpp9
-rw-r--r--lib/Frontend/FixItRewriter.cpp14
-rw-r--r--lib/Frontend/FrontendAction.cpp4
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp3
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp11
-rw-r--r--lib/Frontend/PCHReader.cpp34
-rw-r--r--lib/Frontend/PCHWriter.cpp15
-rw-r--r--lib/Frontend/RewriteObjC.cpp51
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp14
-rw-r--r--lib/Headers/emmintrin.h426
-rw-r--r--lib/Headers/mm_malloc.h9
-rw-r--r--lib/Headers/mmintrin.h134
-rw-r--r--lib/Headers/pmmintrin.h26
-rw-r--r--lib/Headers/smmintrin.h128
-rw-r--r--lib/Headers/tmmintrin.h60
-rw-r--r--lib/Headers/wmmintrin.h67
-rw-r--r--lib/Headers/xmmintrin.h240
-rw-r--r--lib/Lex/Lexer.cpp3
-rw-r--r--lib/Lex/PPDirectives.cpp6
-rw-r--r--lib/Lex/PPLexerChange.cpp1
-rw-r--r--lib/Lex/PPMacroExpansion.cpp11
-rw-r--r--lib/Lex/Preprocessor.cpp5
-rw-r--r--lib/Lex/TokenConcatenation.cpp2
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Parse/DeclSpec.cpp4
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp25
-rw-r--r--lib/Parse/ParseDecl.cpp10
-rw-r--r--lib/Parse/ParseDeclCXX.cpp11
-rw-r--r--lib/Parse/ParseExprCXX.cpp4
-rw-r--r--lib/Parse/ParseInit.cpp7
-rw-r--r--lib/Parse/ParseObjc.cpp13
-rw-r--r--lib/Parse/ParseStmt.cpp8
-rw-r--r--lib/Parse/ParseTemplate.cpp2
-rw-r--r--lib/Parse/Parser.cpp10
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp110
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h42
-rw-r--r--lib/Sema/Lookup.h6
-rw-r--r--lib/Sema/Sema.cpp27
-rw-r--r--lib/Sema/Sema.h162
-rw-r--r--lib/Sema/SemaAccess.cpp760
-rw-r--r--lib/Sema/SemaCXXCast.cpp58
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp8
-rw-r--r--lib/Sema/SemaChecking.cpp64
-rw-r--r--lib/Sema/SemaDecl.cpp391
-rw-r--r--lib/Sema/SemaDeclAttr.cpp31
-rw-r--r--lib/Sema/SemaDeclCXX.cpp704
-rw-r--r--lib/Sema/SemaDeclObjC.cpp48
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp154
-rw-r--r--lib/Sema/SemaExpr.cpp243
-rw-r--r--lib/Sema/SemaExprCXX.cpp249
-rw-r--r--lib/Sema/SemaExprObjC.cpp5
-rw-r--r--lib/Sema/SemaInit.cpp86
-rw-r--r--lib/Sema/SemaInit.h10
-rw-r--r--lib/Sema/SemaLookup.cpp21
-rw-r--r--lib/Sema/SemaObjCProperty.cpp29
-rw-r--r--lib/Sema/SemaOverload.cpp130
-rw-r--r--lib/Sema/SemaStmt.cpp57
-rw-r--r--lib/Sema/SemaTemplate.cpp672
-rw-r--r--lib/Sema/SemaTemplate.h34
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp273
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp131
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp316
-rw-r--r--lib/Sema/SemaType.cpp84
-rw-r--r--lib/Sema/TreeTransform.h126
-rw-r--r--test/Analysis/PR3991.m20
-rw-r--r--test/Analysis/inline.c2
-rw-r--r--test/Analysis/misc-ps-region-store.m45
-rw-r--r--test/Analysis/no-outofbounds.c3
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/outofbound.c23
-rw-r--r--test/Analysis/plist-output.m40
-rw-r--r--test/Analysis/pr4209.m8
-rw-r--r--test/Analysis/retain-release-region-store.m16
-rw-r--r--test/Analysis/retain-release.m9
-rw-r--r--test/Analysis/uninit-vals-ps-region.m7
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp12
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp13
-rw-r--r--test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp9
-rw-r--r--test/CXX/class.access/class.access.base/p5.cpp75
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp43
-rw-r--r--test/CXX/class.access/p4.cpp69
-rw-r--r--test/CXX/class.derived/class.abstract/p4.cpp80
-rw-r--r--test/CXX/class.derived/class.abstract/p5.cpp23
-rw-r--r--test/CXX/class.derived/class.virtual/p2.cpp37
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp43
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp14
-rw-r--r--test/CXX/stmt.stmt/stmt.select/p3.cpp11
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp4
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp80
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp131
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp26
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp31
-rw-r--r--test/CXX/temp/temp.res/temp.local/p1.cpp3
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp2
-rw-r--r--test/CodeGen/atomic.c6
-rw-r--r--test/CodeGen/mangle.c4
-rw-r--r--test/CodeGen/palignr.c2
-rw-r--r--test/CodeGen/regparm.c11
-rw-r--r--test/CodeGen/restrict.c26
-rw-r--r--test/CodeGenCXX/constructor-init.cpp21
-rw-r--r--test/CodeGenCXX/copy-constructor-synthesis.cpp54
-rw-r--r--test/CodeGenCXX/member-expressions.cpp40
-rw-r--r--test/CodeGenCXX/multi-dim-operator-new.cpp49
-rw-r--r--test/CodeGenCXX/references.cpp8
-rw-r--r--test/CodeGenCXX/rtti-fundamental.cpp71
-rw-r--r--test/CodeGenCXX/rtti-linkage.cpp1
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp76
-rw-r--r--test/CodeGenCXX/temporaries.cpp13
-rw-r--r--test/CodeGenCXX/thunks.cpp137
-rw-r--r--test/CodeGenCXX/virt.cpp52
-rw-r--r--test/CodeGenCXX/virtual-bases.cpp23
-rw-r--r--test/CodeGenCXX/vtable-layout-abi-examples.cpp1
-rw-r--r--test/CodeGenCXX/vtable-layout.cpp49
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp20
-rw-r--r--test/CodeGenObjC/complex-property.m32
-rw-r--r--test/CodeGenObjC/objc2-nonfragile-abi-impl.m15
-rw-r--r--test/Driver/nostdincxx.cpp4
-rw-r--r--test/FixIt/fixit.cpp3
-rw-r--r--test/Headers/c89.c10
-rw-r--r--test/Headers/x86-intrinsics-headers.c (renamed from test/Sema/x86-intrinsics-headers.c)0
-rw-r--r--test/Index/Inputs/remap-complete-to.c7
-rw-r--r--test/Index/cindex-on-invalid.m7
-rw-r--r--test/Index/print-usrs.c17
-rw-r--r--test/Index/recover-bad-code-rdar_7487294.c1
-rw-r--r--test/Index/remap-complete.c7
-rw-r--r--test/PCH/changed-files.c36
-rw-r--r--test/Parser/cxx-default-args.cpp9
-rw-r--r--test/Parser/objc-messaging-neg-1.m6
-rw-r--r--test/Parser/statements.c5
-rw-r--r--test/Preprocessor/dependencies-and-pp.c26
-rw-r--r--test/Preprocessor/macro_disable.c34
-rw-r--r--test/Preprocessor/macro_disable2.c8
-rw-r--r--test/Preprocessor/macro_disable3.c10
-rw-r--r--test/Preprocessor/macro_disable4.c6
-rw-r--r--test/Preprocessor/output_paste_avoid.c4
-rw-r--r--test/Sema/attr-format.c (renamed from test/Sema/format-attribute.c)46
-rw-r--r--test/Sema/attr-sentinel.c (renamed from test/Sema/function-sentinel-attr.c)24
-rw-r--r--test/Sema/attr-unused.c17
-rw-r--r--test/Sema/format-attr-pr4470.c12
-rw-r--r--test/Sema/format-attribute-printf0.c26
-rw-r--r--test/Sema/format-strings.c13
-rw-r--r--test/Sema/function-pointer-sentinel-attribute.c20
-rw-r--r--test/Sema/init.c3
-rw-r--r--test/Sema/nested-redef.c3
-rw-r--r--test/Sema/return.c17
-rw-r--r--test/Sema/struct-packed-align.c8
-rw-r--r--test/Sema/warn-gnu-designators.c2
-rw-r--r--test/Sema/warn-shadow.c5
-rw-r--r--test/SemaCXX/PR6618.cpp13
-rw-r--r--test/SemaCXX/class-base-member-init.cpp44
-rw-r--r--test/SemaCXX/class-layout.cpp7
-rw-r--r--test/SemaCXX/conditional-expr.cpp18
-rw-r--r--test/SemaCXX/destructor.cpp5
-rw-r--r--test/SemaCXX/exception-spec.cpp6
-rw-r--r--test/SemaCXX/invalid-member-expr.cpp18
-rw-r--r--test/SemaCXX/namespace-alias.cpp10
-rw-r--r--test/SemaCXX/namespace.cpp22
-rw-r--r--test/SemaCXX/nested-name-spec.cpp2
-rw-r--r--test/SemaCXX/new-delete-predefined-decl-2.cpp13
-rw-r--r--test/SemaCXX/qual-id-test.cpp9
-rw-r--r--test/SemaCXX/static-cast.cpp4
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp12
-rw-r--r--test/SemaObjC/block-type-safety.m8
-rw-r--r--test/SemaObjC/category-1.m6
-rw-r--r--test/SemaObjC/compare-qualified-id.m7
-rw-r--r--test/SemaObjC/comptypes-7.m5
-rw-r--r--test/SemaObjC/conditional-expr.m4
-rw-r--r--test/SemaObjC/gcc-cast-ext.m6
-rw-r--r--test/SemaObjC/ivar-in-class-extension-error.m15
-rw-r--r--test/SemaObjC/ivar-in-implementations.m23
-rw-r--r--test/SemaObjC/ivar-sem-check-1.m3
-rw-r--r--test/SemaObjC/method-arg-decay.m10
-rw-r--r--test/SemaObjC/method-undef-category-warn-1.m22
-rw-r--r--test/SemaObjC/method-undef-extension-warn-1.m10
-rw-r--r--test/SemaObjC/method-undefined-warn-1.m16
-rw-r--r--test/SemaObjC/method-warn-unused-attribute.m12
-rw-r--r--test/SemaObjC/no-protocol-option-tests.m32
-rw-r--r--test/SemaObjC/nsobject-attribute.m6
-rw-r--r--test/SemaObjC/property-expression-error.m5
-rw-r--r--test/SemaObjC/property-in-class-extension.m15
-rw-r--r--test/SemaObjC/property-ivar-mismatch.m4
-rw-r--r--test/SemaObjC/property.m4
-rw-r--r--test/SemaObjC/undef-protocol-methods-1.m34
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp2
-rw-r--r--test/SemaTemplate/friend-template.cpp8
-rw-r--r--test/SemaTemplate/instantiate-declref.cpp2
-rw-r--r--test/SemaTemplate/instantiate-elab-type-specifier.cpp13
-rw-r--r--test/SemaTemplate/instantiate-expr-4.cpp13
-rw-r--r--test/SemaTemplate/instantiate-function-params.cpp57
-rw-r--r--test/SemaTemplate/instantiate-init.cpp18
-rw-r--r--test/SemaTemplate/instantiate-member-class.cpp30
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp6
-rw-r--r--test/SemaTemplate/instantiation-default-2.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp33
-rw-r--r--tools/CIndex/CIndex.cpp7
-rw-r--r--tools/CIndex/CIndexDiagnostic.cpp3
-rw-r--r--tools/CIndex/CIndexUSRs.cpp21
-rw-r--r--tools/CIndex/CMakeLists.txt4
-rw-r--r--tools/c-index-test/c-index-test.c191
-rw-r--r--tools/driver/Makefile8
-rw-r--r--tools/driver/cc1_main.cpp53
-rw-r--r--tools/driver/driver.cpp28
-rwxr-xr-xtools/scan-build/scan-build11
-rw-r--r--utils/VtableTest/Makefile9
-rwxr-xr-xutils/VtableTest/check-ztt8
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/get_started.html2
367 files changed, 11197 insertions, 6519 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e84d94..2001c71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,6 +92,12 @@ install(DIRECTORY include/
PATTERN ".svn" EXCLUDE
)
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
+ DESTINATION include
+ FILES_MATCHING
+ PATTERN "*.inc"
+ )
+
add_definitions( -D_GNU_SOURCE )
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs." OFF)
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index 7bf6335..efdc3b3 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -12,7 +12,6 @@
1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; };
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; };
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; };
- 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */; };
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */; };
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */; };
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */; };
@@ -70,6 +69,8 @@
1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; };
1AE4EE3E103B89ED00888A23 /* StmtProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */; };
1AF1B50F109A4FB800AFAFAC /* CGException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AF1B50E109A4FB800AFAFAC /* CGException.cpp */; };
+ 1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8701161085D00AE030A /* ASTMerge.cpp */; };
+ 1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */; };
1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; };
3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; };
352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; };
@@ -149,6 +150,11 @@
90FD6D85103C3D49005F5B73 /* SelectorMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6D7A103C3D49005F5B73 /* SelectorMap.cpp */; };
90FD6DB6103D977E005F5B73 /* index-test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FD6DB5103D977E005F5B73 /* index-test.cpp */; };
BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; };
+ BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */; };
+ BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */; };
+ BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3F811595A01001C2D68 /* SemaType.cpp */; };
+ BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */; };
+ BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */; };
DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; };
DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; };
DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; };
@@ -365,7 +371,6 @@
1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; };
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisConsumer.cpp; path = lib/Frontend/AnalysisConsumer.cpp; sourceTree = "<group>"; };
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ASTConsumers.cpp; path = lib/Frontend/ASTConsumers.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Backend.cpp; path = lib/Frontend/Backend.cpp; sourceTree = "<group>"; };
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CacheTokens.cpp; path = lib/Frontend/CacheTokens.cpp; sourceTree = "<group>"; };
1A2A54A80FD1DD1C00F4CE45 /* DependencyFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DependencyFile.cpp; path = lib/Frontend/DependencyFile.cpp; sourceTree = "<group>"; };
1A2A54A90FD1DD1C00F4CE45 /* DiagChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DiagChecker.cpp; path = lib/Frontend/DiagChecker.cpp; sourceTree = "<group>"; };
@@ -446,8 +451,9 @@
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TreeTransform.h; path = lib/Sema/TreeTransform.h; sourceTree = "<group>"; tabWidth = 2; };
1AE4EE3D103B89ED00888A23 /* StmtProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = StmtProfile.cpp; path = lib/AST/StmtProfile.cpp; sourceTree = "<group>"; tabWidth = 2; };
1AF1B50E109A4FB800AFAFAC /* CGException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGException.cpp; path = lib/CodeGen/CGException.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ 1AFDD8701161085D00AE030A /* ASTMerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTMerge.cpp; path = lib/Frontend/ASTMerge.cpp; sourceTree = "<group>"; };
+ 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeGenAction.cpp; path = lib/Frontend/CodeGenAction.cpp; sourceTree = "<group>"; };
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; };
- 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; };
3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; };
352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; };
352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; };
@@ -618,6 +624,15 @@
90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
+ BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnalysisBasedWarnings.h; path = lib/Sema/AnalysisBasedWarnings.h; sourceTree = "<group>"; };
+ BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisBasedWarnings.cpp; path = lib/Sema/AnalysisBasedWarnings.cpp; sourceTree = "<group>"; };
+ BF89C3E311595835001C2D68 /* Lookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Lookup.h; path = lib/Sema/Lookup.h; sourceTree = "<group>"; };
+ BF89C3E411595855001C2D68 /* SemaInit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaInit.h; path = lib/Sema/SemaInit.h; sourceTree = "<group>"; };
+ BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetAttributesSema.h; path = lib/Sema/TargetAttributesSema.h; sourceTree = "<group>"; };
+ BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaObjCProperty.cpp; path = lib/Sema/SemaObjCProperty.cpp; sourceTree = "<group>"; };
+ BF89C3F811595A01001C2D68 /* SemaType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaType.cpp; path = lib/Sema/SemaType.cpp; sourceTree = "<group>"; };
+ BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaCodeComplete.cpp; path = lib/Sema/SemaCodeComplete.cpp; sourceTree = "<group>"; };
+ BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaExceptionSpec.cpp; path = lib/Sema/SemaExceptionSpec.cpp; sourceTree = "<group>"; };
DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; };
DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; };
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; tabWidth = 2; };
@@ -948,10 +963,11 @@
352246E00F5C6BC000D0D279 /* Frontend */ = {
isa = PBXGroup;
children = (
+ 1AFDD8701161085D00AE030A /* ASTMerge.cpp */,
9012911C1048068D0083456D /* ASTUnit.cpp */,
1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */,
1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */,
- 1A2A54A60FD1DD1C00F4CE45 /* Backend.cpp */,
+ 1AFDD8711161085D00AE030A /* CodeGenAction.cpp */,
1A2A54A70FD1DD1C00F4CE45 /* CacheTokens.cpp */,
1ACB57DB1105820D0047B991 /* CompilerInstance.cpp */,
1ACB57DC1105820D0047B991 /* CompilerInvocation.cpp */,
@@ -1257,29 +1273,36 @@
DE67E7070C020EAB00F66BC5 /* Sema */ = {
isa = PBXGroup;
children = (
+ BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */,
+ BF89C3E0115957FF001C2D68 /* AnalysisBasedWarnings.h */,
35585DBD0EAFBC4500D0A97A /* CXXFieldCollector.h */,
1A6B6CD110693FC900BB4A8F /* CodeCompleteConsumer.cpp */,
3527124F0DAFE54700C76352 /* IdentifierResolver.h */,
352712500DAFE54700C76352 /* IdentifierResolver.cpp */,
DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */,
+ BF89C3E311595835001C2D68 /* Lookup.h */,
DE67E7190C020F4F00F66BC5 /* ParseAST.cpp */,
DE67E7140C020EDF00F66BC5 /* Sema.h */,
DE67E7160C020EE400F66BC5 /* Sema.cpp */,
1A701B630F7C8FE400FEC4D1 /* SemaAccess.cpp */,
DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */,
DEF2F00F0C6CFED5000C4259 /* SemaChecking.cpp */,
+ BF89C3FA11595A37001C2D68 /* SemaCodeComplete.cpp */,
35E194670ECB82FB00F21733 /* SemaCXXScopeSpec.cpp */,
DE67E7120C020ED900F66BC5 /* SemaDecl.cpp */,
DE22BCF10E14197E0094DC60 /* SemaDeclAttr.cpp */,
35EF676F0DAD1D2C00B19414 /* SemaDeclCXX.cpp */,
DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */,
+ BF89C3FC11595A5D001C2D68 /* SemaExceptionSpec.cpp */,
DE67E7100C020ED400F66BC5 /* SemaExpr.cpp */,
DE47999B0D2EBE1A00706D2D /* SemaExprObjC.cpp */,
DE67E70E0C020ECF00F66BC5 /* SemaExprCXX.cpp */,
+ BF89C3E411595855001C2D68 /* SemaInit.h */,
3599299A0DE2425300A8A33E /* SemaInit.cpp */,
357EA27C0F2526F300439B60 /* SemaLookup.cpp */,
1A6B6CD210693FC900BB4A8F /* SemaCodeComplete.cpp */,
35E194680ECB82FB00F21733 /* SemaCXXCast.cpp */,
+ BF89C3E81159594A001C2D68 /* SemaObjCProperty.cpp */,
35585DBE0EAFBC4500D0A97A /* SemaOverload.cpp */,
35585DBF0EAFBC4500D0A97A /* SemaOverload.h */,
DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */,
@@ -1288,7 +1311,9 @@
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */,
35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */,
1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */,
+ BF89C3F811595A01001C2D68 /* SemaType.cpp */,
1AE4EE3B103B89CA00888A23 /* TreeTransform.h */,
+ BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */,
);
name = Sema;
sourceTree = "<group>";
@@ -1334,7 +1359,6 @@
DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */,
3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */,
1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */,
- 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */,
1A6C01F6108128710072DEE4 /* CGRTTI.cpp */,
DE4772F90C10EAE5002239E8 /* CGStmt.cpp */,
1A6FE7080FD6F85800E00CA9 /* CGTemporaries.cpp */,
@@ -1930,7 +1954,6 @@
DECB78170FA5882F00F5FBC7 /* PCHWriterStmt.cpp in Sources */,
1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */,
1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */,
- 1A2A54B70FD1DD1C00F4CE45 /* Backend.cpp in Sources */,
1A2A54B80FD1DD1C00F4CE45 /* CacheTokens.cpp in Sources */,
1A2A54B90FD1DD1C00F4CE45 /* DependencyFile.cpp in Sources */,
1A2A54BA0FD1DD1C00F4CE45 /* DiagChecker.cpp in Sources */,
@@ -1997,6 +2020,13 @@
1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */,
1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */,
1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */,
+ BF89C3E211595818001C2D68 /* AnalysisBasedWarnings.cpp in Sources */,
+ BF89C3E91159594A001C2D68 /* SemaObjCProperty.cpp in Sources */,
+ BF89C3F911595A01001C2D68 /* SemaType.cpp in Sources */,
+ BF89C3FB11595A37001C2D68 /* SemaCodeComplete.cpp in Sources */,
+ BF89C3FD11595A5D001C2D68 /* SemaExceptionSpec.cpp in Sources */,
+ 1AFDD8721161085D00AE030A /* ASTMerge.cpp in Sources */,
+ 1AFDD8731161085D00AE030A /* CodeGenAction.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index b739b71..4eaa1dd 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -71,7 +71,8 @@ int main(int argc, const char **argv, char * const *envp) {
Diagnostic Diags(&DiagClient);
Driver TheDriver(Path.getBasename(), Path.getDirname(),
llvm::sys::getHostTriple(),
- "a.out", /*IsProduction=*/false, Diags);
+ "a.out", /*IsProduction=*/false, /*CXXIsProduction=*/false,
+ Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index e77dcf8..c41857e 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -17,6 +17,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
@@ -57,6 +58,7 @@ namespace clang {
class ObjCIvarRefExpr;
class ObjCPropertyDecl;
class RecordDecl;
+ class StoredDeclsMap;
class TagDecl;
class TemplateTypeParmDecl;
class TranslationUnitDecl;
@@ -115,7 +117,7 @@ class ASTContext {
llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes;
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
- llvm::FoldingSet<TypenameType> TypenameTypes;
+ llvm::FoldingSet<DependentNameType> DependentNameTypes;
llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
llvm::FoldingSet<ElaboratedType> ElaboratedTypes;
@@ -264,6 +266,9 @@ class ASTContext {
llvm::MallocAllocator MallocAlloc;
llvm::BumpPtrAllocator BumpAlloc;
+ /// \brief Allocator for partial diagnostics.
+ PartialDiagnostic::StorageAllocator DiagAllocator;
+
public:
const TargetInfo &Target;
IdentifierTable &Idents;
@@ -289,6 +294,11 @@ public:
if (FreeMemory)
MallocAlloc.Deallocate(Ptr);
}
+
+ PartialDiagnostic::StorageAllocator &getDiagAllocator() {
+ return DiagAllocator;
+ }
+
const LangOptions& getLangOptions() const { return LangOpts; }
FullSourceLoc getFullLoc(SourceLocation Loc) const {
@@ -437,6 +447,11 @@ public:
/// allowable type.
QualType getCallConvType(QualType T, CallingConv CallConv);
+ /// getRegParmType - Sets the specified regparm attribute to
+ /// the given type, which must be a FunctionType or a pointer to an
+ /// allowable type.
+ QualType getRegParmType(QualType T, unsigned RegParm);
+
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
QualType getComplexType(QualType T);
@@ -554,8 +569,12 @@ public:
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
- QualType getFunctionNoProtoType(QualType ResultTy, bool NoReturn = false,
- CallingConv CallConv = CC_Default);
+ QualType getFunctionNoProtoType(QualType ResultTy,
+ const FunctionType::ExtInfo &Info);
+
+ QualType getFunctionNoProtoType(QualType ResultTy) {
+ return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo());
+ }
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
@@ -564,8 +583,7 @@ public:
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec,
unsigned NumExs, const QualType *ExArray,
- bool NoReturn,
- CallingConv CallConv);
+ const FunctionType::ExtInfo &Info);
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
@@ -612,12 +630,14 @@ public:
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
QualType NamedType);
- QualType getTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon = QualType());
- QualType getTypenameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon = QualType());
QualType getElaboratedType(QualType UnderlyingType,
ElaboratedType::TagKind Tag);
@@ -937,8 +957,7 @@ public:
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
void CollectNonClassIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars);
- unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI);
- unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD);
+ unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI);
void CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols);
@@ -1273,9 +1292,8 @@ private:
// FIXME: This currently contains the set of StoredDeclMaps used
// by DeclContext objects. This probably should not be in ASTContext,
// but we include it here so that ASTContext can quickly deallocate them.
- std::vector<void*> SDMs;
+ llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM;
friend class DeclContext;
- void *CreateStoredDeclsMap();
void ReleaseDeclContextMaps();
};
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index c89e5e4..edd633e 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -19,6 +19,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include <list>
#include <map>
@@ -227,6 +228,137 @@ public:
/// object.
void swap(CXXBasePaths &Other);
};
+
+/// \brief Uniquely identifies a virtual method within a class
+/// hierarchy by the method itself and a class subobject number.
+struct UniqueVirtualMethod {
+ UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { }
+
+ UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject,
+ const CXXRecordDecl *InVirtualSubobject)
+ : Method(Method), Subobject(Subobject),
+ InVirtualSubobject(InVirtualSubobject) { }
+
+ /// \brief The overriding virtual method.
+ CXXMethodDecl *Method;
+
+ /// \brief The subobject in which the overriding virtual method
+ /// resides.
+ unsigned Subobject;
+
+ /// \brief The virtual base class subobject of which this overridden
+ /// virtual method is a part. Note that this records the closest
+ /// derived virtual base class subobject.
+ const CXXRecordDecl *InVirtualSubobject;
+
+ friend bool operator==(const UniqueVirtualMethod &X,
+ const UniqueVirtualMethod &Y) {
+ return X.Method == Y.Method && X.Subobject == Y.Subobject &&
+ X.InVirtualSubobject == Y.InVirtualSubobject;
+ }
+
+ friend bool operator!=(const UniqueVirtualMethod &X,
+ const UniqueVirtualMethod &Y) {
+ return !(X == Y);
+ }
+};
+
+/// \brief The set of methods that override a given virtual method in
+/// each subobject where it occurs.
+///
+/// The first part of the pair is the subobject in which the
+/// overridden virtual function occurs, while the second part of the
+/// pair is the virtual method that overrides it (including the
+/// subobject in which that virtual function occurs).
+class OverridingMethods {
+ llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ Overrides;
+
+public:
+ // Iterate over the set of subobjects that have overriding methods.
+ typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ ::iterator iterator;
+ typedef llvm::DenseMap<unsigned, llvm::SmallVector<UniqueVirtualMethod, 4> >
+ ::const_iterator const_iterator;
+ iterator begin() { return Overrides.begin(); }
+ const_iterator begin() const { return Overrides.begin(); }
+ iterator end() { return Overrides.end(); }
+ const_iterator end() const { return Overrides.end(); }
+ unsigned size() const { return Overrides.size(); }
+
+ // Iterate over the set of overriding virtual methods in a given
+ // subobject.
+ typedef llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ overriding_iterator;
+ typedef llvm::SmallVector<UniqueVirtualMethod, 4>::const_iterator
+ overriding_const_iterator;
+
+ // Add a new overriding method for a particular subobject.
+ void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding);
+
+ // Add all of the overriding methods from "other" into overrides for
+ // this method. Used when merging the overrides from multiple base
+ // class subobjects.
+ void add(const OverridingMethods &Other);
+
+ // Replace all overriding virtual methods in all subobjects with the
+ // given virtual method.
+ void replaceAll(UniqueVirtualMethod Overriding);
+};
+
+/// \brief A mapping from each virtual member function to its set of
+/// final overriders.
+///
+/// Within a class hierarchy for a given derived class, each virtual
+/// member function in that hierarchy has one or more "final
+/// overriders" (C++ [class.virtual]p2). A final overrider for a
+/// virtual function "f" is the virtual function that will actually be
+/// invoked when dispatching a call to "f" through the
+/// vtable. Well-formed classes have a single final overrider for each
+/// virtual function; in abstract classes, the final overrider for at
+/// least one virtual function is a pure virtual function. Due to
+/// multiple, virtual inheritance, it is possible for a class to have
+/// more than one final overrider. Athough this is an error (per C++
+/// [class.virtual]p2), it is not considered an error here: the final
+/// overrider map can represent multiple final overriders for a
+/// method, and it is up to the client to determine whether they are
+/// problem. For example, the following class \c D has two final
+/// overriders for the virtual function \c A::f(), one in \c C and one
+/// in \c D:
+///
+/// \code
+/// struct A { virtual void f(); };
+/// struct B : virtual A { virtual void f(); };
+/// struct C : virtual A { virtual void f(); };
+/// struct D : B, C { };
+/// \endcode
+///
+/// This data structure contaings a mapping from every virtual
+/// function *that does not override an existing virtual function* and
+/// in every subobject where that virtual function occurs to the set
+/// of virtual functions that override it. Thus, the same virtual
+/// function \c A::f can actually occur in multiple subobjects of type
+/// \c A due to multiple inheritance, and may be overriden by
+/// different virtual functions in each, as in the following example:
+///
+/// \code
+/// struct A { virtual void f(); };
+/// struct B : A { virtual void f(); };
+/// struct C : A { virtual void f(); };
+/// struct D : B, C { };
+/// \endcode
+///
+/// Unlike in the previous example, where the virtual functions \c
+/// B::f and \c C::f both overrode \c A::f in the same subobject of
+/// type \c A, in this example the two virtual functions both override
+/// \c A::f but in *different* subobjects of type A. This is
+/// represented by numbering the subobjects in which the overridden
+/// and the overriding virtual member functions are located. Subobject
+/// 0 represents the virtua base class subobject of that type, while
+/// subobject numbers greater than 0 refer to non-virtual base class
+/// subobjects of that type.
+class CXXFinalOverriderMap
+ : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { };
} // end namespace clang
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 1f459b0..b2a87f6 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -165,6 +165,8 @@ public:
// (dynamic) type.
static CanQual<T> CreateUnsafe(QualType Other);
+ void dump() const { Stored.dump(); }
+
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(getAsOpaquePtr());
}
@@ -562,24 +564,21 @@ struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> {
template<>
struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
};
template<>
struct CanProxyAdaptor<FunctionNoProtoType>
: public CanProxyBase<FunctionNoProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
};
template<>
struct CanProxyAdaptor<FunctionProtoType>
: public CanProxyBase<FunctionProtoType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs)
CanQualType getArgType(unsigned i) const {
return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i));
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index e23811d..2cdb983 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -224,18 +224,26 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
// NextNamespace points to the next extended declaration.
// OrigNamespace points to the original namespace declaration.
// OrigNamespace of the first namespace decl points to itself.
- NamespaceDecl *OrigNamespace, *NextNamespace;
+ NamespaceDecl *NextNamespace;
- // The (most recently entered) anonymous namespace inside this
- // namespace.
- NamespaceDecl *AnonymousNamespace;
+ /// \brief A pointer to either the original namespace definition for
+ /// this namespace (if the boolean value is false) or the anonymous
+ /// namespace that lives just inside this namespace (if the boolean
+ /// value is true).
+ ///
+ /// We can combine these two notions because the anonymous namespace
+ /// must only be stored in one of the namespace declarations (so all
+ /// of the namespace declarations can find it). We therefore choose
+ /// the original namespace declaration, since all of the namespace
+ /// declarations have a link directly to it; the original namespace
+ /// declaration itself only needs to know that it is the original
+ /// namespace declaration (which the boolean indicates).
+ llvm::PointerIntPair<NamespaceDecl *, 1, bool> OrigOrAnonNamespace;
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
- : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
- OrigNamespace = this;
- NextNamespace = 0;
- AnonymousNamespace = 0;
- }
+ : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace),
+ NextNamespace(0), OrigOrAnonNamespace(0, true) { }
+
public:
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id);
@@ -258,22 +266,33 @@ public:
void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; }
NamespaceDecl *getOriginalNamespace() const {
- return OrigNamespace;
+ if (OrigOrAnonNamespace.getInt())
+ return const_cast<NamespaceDecl *>(this);
+
+ return OrigOrAnonNamespace.getPointer();
+ }
+
+ void setOriginalNamespace(NamespaceDecl *ND) {
+ if (ND != this) {
+ OrigOrAnonNamespace.setPointer(ND);
+ OrigOrAnonNamespace.setInt(false);
+ }
}
- void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
NamespaceDecl *getAnonymousNamespace() const {
- return AnonymousNamespace;
+ return getOriginalNamespace()->OrigOrAnonNamespace.getPointer();
}
void setAnonymousNamespace(NamespaceDecl *D) {
assert(!D || D->isAnonymousNamespace());
assert(!D || D->getParent() == this);
- AnonymousNamespace = D;
+ getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D);
}
- virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
- const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
+ virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); }
+ const NamespaceDecl *getCanonicalDecl() const {
+ return getOriginalNamespace();
+ }
virtual SourceRange getSourceRange() const {
return SourceRange(getLocation(), RBracLoc);
@@ -1819,12 +1838,12 @@ class RecordDecl : public TagDecl {
/// If so, this cannot be contained in arrays or other structs as a member.
bool HasFlexibleArrayMember : 1;
- /// AnonymousStructOrUnion - Whether this is the type of an
- /// anonymous struct or union.
+ /// AnonymousStructOrUnion - Whether this is the type of an anonymous struct
+ /// or union.
bool AnonymousStructOrUnion : 1;
- /// HasObjectMember - This is true if this struct has at least one
- /// member containing an object
+ /// HasObjectMember - This is true if this struct has at least one member
+ /// containing an object.
bool HasObjectMember : 1;
protected:
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 6f82844..d5913e2 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -41,6 +41,8 @@ class LinkageSpecDecl;
class BlockDecl;
class DeclarationName;
class CompoundStmt;
+class StoredDeclsMap;
+class DependentDiagnostic;
}
namespace llvm {
@@ -450,15 +452,23 @@ public:
/// same entity may not (and probably don't) share this property.
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
unsigned OldNS = IdentifierNamespace;
- assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
- OldNS == (IDNS_Tag | IDNS_Ordinary))
- && "unsupported namespace for undeclared friend");
- if (!PreviouslyDeclared) IdentifierNamespace = 0;
-
- if (OldNS == IDNS_Tag)
+ assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes neither ordinary nor tag");
+ assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary |
+ IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
+ "namespace includes other than ordinary or tag");
+
+ IdentifierNamespace = 0;
+ if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- else
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag;
+ }
+
+ if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
+ if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+ }
}
enum FriendObjectKind {
@@ -545,9 +555,9 @@ class DeclContext {
mutable bool ExternalVisibleStorage : 1;
/// \brief Pointer to the data structure used to lookup declarations
- /// within this context, which is a DenseMap<DeclarationName,
- /// StoredDeclsList>.
- mutable void* LookupPtr;
+ /// within this context (or a DependentStoredDeclsMap if this is a
+ /// dependent context).
+ mutable StoredDeclsMap *LookupPtr;
/// FirstDecl - The first declaration stored within this declaration
/// context.
@@ -674,6 +684,9 @@ public:
/// "primary" DeclContext structure, which will contain the
/// information needed to perform name lookup into this context.
DeclContext *getPrimaryContext();
+ const DeclContext *getPrimaryContext() const {
+ return const_cast<DeclContext*>(this)->getPrimaryContext();
+ }
/// getLookupContext - Retrieve the innermost non-transparent
/// context of this context, which corresponds to the innermost
@@ -976,10 +989,15 @@ public:
return getUsingDirectives().second;
}
+ // These are all defined in DependentDiagnostic.h.
+ class ddiag_iterator;
+ inline ddiag_iterator ddiag_begin() const;
+ inline ddiag_iterator ddiag_end() const;
+
// Low-level accessors
/// \brief Retrieve the internal representation of the lookup structure.
- void* getLookupPtr() const { return LookupPtr; }
+ StoredDeclsMap* getLookupPtr() const { return LookupPtr; }
/// \brief Whether this DeclContext has external storage containing
/// additional declarations that are lexically in this context.
@@ -1013,6 +1031,9 @@ private:
void LoadLexicalDeclsFromExternalStorage() const;
void LoadVisibleDeclsFromExternalStorage() const;
+ friend class DependentDiagnostic;
+ StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
+
void buildLookup(DeclContext *DCtx);
void makeDeclVisibleInContextImpl(NamedDecl *D);
};
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 6b04ed5..23769af 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -33,6 +33,7 @@ class CXXDestructorDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class CXXMemberLookupCriteria;
+class CXXFinalOverriderMap;
class FriendDecl;
/// \brief Represents any kind of function declaration, whether it is a
@@ -328,6 +329,10 @@ class CXXRecordDecl : public RecordDecl {
/// instantiated or specialized.
llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
+
+#ifndef NDEBUG
+ void CheckConversionFunction(NamedDecl *D);
+#endif
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -549,17 +554,26 @@ public:
return getConversionFunctions()->replace(Old, New);
}
+ /// Removes a conversion function from this class. The conversion
+ /// function must currently be a member of this class. Furthermore,
+ /// this class must currently be in the process of being defined.
+ void removeConversion(const NamedDecl *Old);
+
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
const UnresolvedSetImpl *getVisibleConversionFunctions();
- /// addConversionFunction - Add a new conversion function to the
- /// list of conversion functions.
- void addConversionFunction(CXXConversionDecl *ConvDecl);
+ /// addConversionFunction - Registers a conversion function which
+ /// this class declares directly.
+ void addConversionFunction(NamedDecl *Decl) {
+#ifndef NDEBUG
+ CheckConversionFunction(Decl);
+#endif
- /// \brief Add a new conversion function template to the list of conversion
- /// functions.
- void addConversionFunction(FunctionTemplateDecl *ConvDecl);
+ // We intentionally don't use the decl's access here because it
+ // hasn't been set yet. That's really just a misdesign in Sema.
+ data().Conversions.addDecl(Decl);
+ }
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
@@ -879,7 +893,12 @@ public:
static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *UserData);
-
+
+ /// \brief Retrieve the final overriders for each virtual member
+ /// function in the class hierarchy where this class is the
+ /// most-derived class in the class hierarchy.
+ void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const;
+
/// viewInheritance - Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
@@ -935,7 +954,7 @@ public:
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
}
-
+
/// \brief Determine whether this is a usual deallocation function
/// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded
/// delete or delete[] operator with a particular signature.
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 32405ee..16cb491 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -24,6 +24,8 @@
namespace clang {
+class DependentDiagnostic;
+
/// StoredDeclsList - This is an array of decls optimized a common case of only
/// containing one entry.
struct StoredDeclsList {
@@ -258,8 +260,28 @@ public:
}
};
-typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
+class StoredDeclsMap
+ : public llvm::DenseMap<DeclarationName, StoredDeclsList> {
+
+public:
+ static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
+
+private:
+ friend class ASTContext; // walks the chain deleting these
+ friend class DeclContext;
+ llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
+};
+class DependentStoredDeclsMap : public StoredDeclsMap {
+public:
+ DependentStoredDeclsMap() : FirstDiagnostic(0) {}
+
+private:
+ friend class DependentDiagnostic;
+ friend class DeclContext; // iterates over diagnostics
+
+ DependentDiagnostic *FirstDiagnostic;
+};
} // end namespace clang
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 5022ad0..99ef738 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -36,7 +36,7 @@ namespace clang {
/// The semantic context of a friend decl is its declaring class.
class FriendDecl : public Decl {
public:
- typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+ typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
private:
// The declaration that's a friend of this class.
@@ -73,8 +73,8 @@ public:
/// possibly dependent) type, return the type; otherwise
/// return null. This is used only for C++0x's unelaborated
/// friend type declarations.
- Type *getFriendType() const {
- return Friend.dyn_cast<Type*>();
+ TypeSourceInfo *getFriendType() const {
+ return Friend.dyn_cast<TypeSourceInfo*>();
}
/// If this friend declaration doesn't name an unelaborated
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 560ce46..8d1a4ca 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -1238,7 +1238,7 @@ public:
/// template <typename U> friend class Foo<T>::Nested; // friend template
class FriendTemplateDecl : public Decl {
public:
- typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
+ typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion;
private:
// The number of template parameters; always non-zero.
@@ -1277,8 +1277,8 @@ public:
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
/// type; otherwise return null.
- Type *getFriendType() const {
- return Friend.dyn_cast<Type*>();
+ TypeSourceInfo *getFriendType() const {
+ return Friend.dyn_cast<TypeSourceInfo*>();
}
/// If this friend declaration names a templated function (or
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index 2254724..6225069 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -378,7 +378,7 @@ inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
Diagnostic::ak_declarationname);
return PD;
}
-
+
} // end namespace clang
namespace llvm {
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
new file mode 100644
index 0000000..1954a28
--- /dev/null
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -0,0 +1,183 @@
+//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines interfaces for diagnostics which may or may
+// fire based on how a template is instantiated.
+//
+// At the moment, the only consumer of this interface is access
+// control.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
+#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
+
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclContextInternals.h"
+
+namespace clang {
+
+class ASTContext;
+class CXXRecordDecl;
+class NamedDecl;
+
+/// A dependently-generated diagnostic.
+class DependentDiagnostic {
+public:
+ enum AccessNonce { Access = 0 };
+
+ static DependentDiagnostic *Create(ASTContext &Context,
+ DeclContext *Parent,
+ AccessNonce _,
+ SourceLocation Loc,
+ bool IsMemberAccess,
+ AccessSpecifier AS,
+ NamedDecl *TargetDecl,
+ CXXRecordDecl *NamingClass,
+ const PartialDiagnostic &PDiag) {
+ DependentDiagnostic *DD = Create(Context, Parent, PDiag);
+ DD->AccessData.Loc = Loc.getRawEncoding();
+ DD->AccessData.IsMember = IsMemberAccess;
+ DD->AccessData.Access = AS;
+ DD->AccessData.TargetDecl = TargetDecl;
+ DD->AccessData.NamingClass = NamingClass;
+ return DD;
+ }
+
+ unsigned getKind() const {
+ return Access;
+ }
+
+ bool isAccessToMember() const {
+ assert(getKind() == Access);
+ return AccessData.IsMember;
+ }
+
+ AccessSpecifier getAccess() const {
+ assert(getKind() == Access);
+ return AccessSpecifier(AccessData.Access);
+ }
+
+ SourceLocation getAccessLoc() const {
+ assert(getKind() == Access);
+ return SourceLocation::getFromRawEncoding(AccessData.Loc);
+ }
+
+ NamedDecl *getAccessTarget() const {
+ assert(getKind() == Access);
+ return AccessData.TargetDecl;
+ }
+
+ NamedDecl *getAccessNamingClass() const {
+ assert(getKind() == Access);
+ return AccessData.NamingClass;
+ }
+
+ const PartialDiagnostic &getDiagnostic() const {
+ return Diag;
+ }
+
+private:
+ DependentDiagnostic(const PartialDiagnostic &PDiag,
+ PartialDiagnostic::Storage *Storage)
+ : Diag(PDiag, Storage) {}
+
+ static DependentDiagnostic *Create(ASTContext &Context,
+ DeclContext *Parent,
+ const PartialDiagnostic &PDiag);
+
+ friend class DependentStoredDeclsMap;
+ friend class DeclContext::ddiag_iterator;
+ DependentDiagnostic *NextDiagnostic;
+
+ PartialDiagnostic Diag;
+
+ union {
+ struct {
+ unsigned Loc;
+ unsigned Access : 2;
+ unsigned IsMember : 1;
+ NamedDecl *TargetDecl;
+ CXXRecordDecl *NamingClass;
+ } AccessData;
+ };
+};
+
+///
+
+/// An iterator over the dependent diagnostics in a dependent context.
+class DeclContext::ddiag_iterator {
+public:
+ ddiag_iterator() : Ptr(0) {}
+ explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
+
+ typedef DependentDiagnostic *value_type;
+ typedef DependentDiagnostic *reference;
+ typedef DependentDiagnostic *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ reference operator*() const { return Ptr; }
+
+ ddiag_iterator &operator++() {
+ assert(Ptr && "attempt to increment past end of diag list");
+ Ptr = Ptr->NextDiagnostic;
+ return *this;
+ }
+
+ ddiag_iterator operator++(int) {
+ ddiag_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ bool operator==(ddiag_iterator Other) const {
+ return Ptr == Other.Ptr;
+ }
+
+ bool operator!=(ddiag_iterator Other) const {
+ return Ptr != Other.Ptr;
+ }
+
+ ddiag_iterator &operator+=(difference_type N) {
+ assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
+ while (N--)
+ ++*this;
+ return *this;
+ }
+
+ ddiag_iterator operator+(difference_type N) const {
+ ddiag_iterator tmp = *this;
+ tmp += N;
+ return tmp;
+ }
+
+private:
+ DependentDiagnostic *Ptr;
+};
+
+inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const {
+ assert(isDependentContext()
+ && "cannot iterate dependent diagnostics of non-dependent context");
+ const DependentStoredDeclsMap *Map
+ = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->LookupPtr);
+
+ if (!Map) return ddiag_iterator();
+ return ddiag_iterator(Map->FirstDiagnostic);
+}
+
+inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const {
+ return ddiag_iterator();
+}
+
+}
+
+#endif
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 6b14e47..507a61c 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -1263,6 +1263,11 @@ public:
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
///
class MemberExpr : public Expr {
+ /// Extra data stored in some member expressions.
+ struct MemberNameQualifier : public NameQualifier {
+ NamedDecl *FoundDecl;
+ };
+
/// Base - the expression for the base pointer or structure references. In
/// X.F, this is "X".
Stmt *Base;
@@ -1278,27 +1283,26 @@ class MemberExpr : public Expr {
bool IsArrow : 1;
/// \brief True if this member expression used a nested-name-specifier to
- /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier
+ /// refer to the member, e.g., "x->Base::f", or found its member via a using
+ /// declaration. When true, a MemberNameQualifier
/// structure is allocated immediately after the MemberExpr.
- bool HasQualifier : 1;
+ bool HasQualifierOrFoundDecl : 1;
/// \brief True if this member expression specified a template argument list
/// explicitly, e.g., x->f<int>. When true, an ExplicitTemplateArgumentList
/// structure (and its TemplateArguments) are allocated immediately after
/// the MemberExpr or, if the member expression also has a qualifier, after
- /// the NameQualifier structure.
+ /// the MemberNameQualifier structure.
bool HasExplicitTemplateArgumentList : 1;
/// \brief Retrieve the qualifier that preceded the member name, if any.
- NameQualifier *getMemberQualifier() {
- if (!HasQualifier)
- return 0;
-
- return reinterpret_cast<NameQualifier *> (this + 1);
+ MemberNameQualifier *getMemberQualifier() {
+ assert(HasQualifierOrFoundDecl);
+ return reinterpret_cast<MemberNameQualifier *> (this + 1);
}
/// \brief Retrieve the qualifier that preceded the member name, if any.
- const NameQualifier *getMemberQualifier() const {
+ const MemberNameQualifier *getMemberQualifier() const {
return const_cast<MemberExpr *>(this)->getMemberQualifier();
}
@@ -1308,7 +1312,7 @@ class MemberExpr : public Expr {
if (!HasExplicitTemplateArgumentList)
return 0;
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
return reinterpret_cast<ExplicitTemplateArgumentList *>(
@@ -1321,26 +1325,22 @@ class MemberExpr : public Expr {
return const_cast<MemberExpr *>(this)->getExplicitTemplateArgumentList();
}
- MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
- SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l,
- const TemplateArgumentListInfo *targs, QualType ty);
-
public:
MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl,
SourceLocation l, QualType ty)
: Expr(MemberExprClass, ty,
base->isTypeDependent(), base->isValueDependent()),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(false), HasExplicitTemplateArgumentList(false) {}
+ HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {}
/// \brief Build an empty member reference expression.
explicit MemberExpr(EmptyShell Empty)
- : Expr(MemberExprClass, Empty), HasQualifier(false),
+ : Expr(MemberExprClass, Empty), HasQualifierOrFoundDecl(false),
HasExplicitTemplateArgumentList(false) { }
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, SourceRange qualrange,
- ValueDecl *memberdecl,
+ ValueDecl *memberdecl, NamedDecl *founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty);
@@ -1355,16 +1355,23 @@ public:
ValueDecl *getMemberDecl() const { return MemberDecl; }
void setMemberDecl(ValueDecl *D) { MemberDecl = D; }
+ /// \brief Retrieves the declaration found by lookup.
+ NamedDecl *getFoundDecl() const {
+ if (!HasQualifierOrFoundDecl)
+ return getMemberDecl();
+ return getMemberQualifier()->FoundDecl;
+ }
+
/// \brief Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo.
- bool hasQualifier() const { return HasQualifier; }
+ bool hasQualifier() const { return getQualifier() != 0; }
/// \brief If the member name was qualified, retrieves the source range of
/// the nested-name-specifier that precedes the member name. Otherwise,
/// returns an empty source range.
SourceRange getQualifierRange() const {
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return SourceRange();
return getMemberQualifier()->Range;
@@ -1374,7 +1381,7 @@ public:
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
NestedNameSpecifier *getQualifier() const {
- if (!HasQualifier)
+ if (!HasQualifierOrFoundDecl)
return 0;
return getMemberQualifier()->NNS;
@@ -1545,6 +1552,10 @@ public:
/// CK_DerivedToBase - Derived to base class casts.
CK_DerivedToBase,
+ /// CK_UncheckedDerivedToBase - Derived to base class casts that
+ /// assume that the derived pointer is not null.
+ CK_UncheckedDerivedToBase,
+
/// CK_Dynamic - Dynamic cast.
CK_Dynamic,
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index d1351b8..6e2e832 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1095,8 +1095,8 @@ public:
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
false, 0, false,
- false, 0, 0, false,
- CC_Default)),
+ false, 0, 0,
+ FunctionType::ExtInfo())),
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 111be55..7279365 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -17,6 +17,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Linkage.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateName.h"
#include "llvm/Support/Casting.h"
@@ -678,14 +679,6 @@ public:
return getObjCGCAttr() == Qualifiers::Strong;
}
- /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
- /// false otherwise.
- bool getNoReturnAttr() const;
-
- /// getCallConv - Returns the calling convention of the type if the type
- /// is a function type, CC_Default otherwise.
- CallingConv getCallConv() const;
-
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -902,6 +895,9 @@ public:
bool isDependentType() const { return Dependent; }
bool isOverloadableType() const;
+ /// \brief Determine wither this type is a C++ elaborated-type-specifier.
+ bool isElaboratedTypeSpecifier() const;
+
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
/// pointers, and Objective-C interface, qualified id, and qualified
@@ -1747,25 +1743,101 @@ class FunctionType : public Type {
/// NoReturn - Indicates if the function type is attribute noreturn.
unsigned NoReturn : 1;
+ /// RegParm - How many arguments to pass inreg.
+ unsigned RegParm : 3;
+
/// CallConv - The calling convention used by the function.
unsigned CallConv : 2;
// The type returned by the function.
QualType ResultType;
+
+ public:
+ // This class is used for passing arround the information needed to
+ // construct a call. It is not actually used for storage, just for
+ // factoring together common arguments.
+ // If you add a field (say Foo), other than the obvious places (both, constructors,
+ // compile failures), what you need to update is
+ // * Operetor==
+ // * getFoo
+ // * withFoo
+ // * functionType. Add Foo, getFoo.
+ // * ASTContext::getFooType
+ // * ASTContext::mergeFunctionTypes
+ // * FunctionNoProtoType::Profile
+ // * FunctionProtoType::Profile
+ // * TypePrinter::PrintFunctionProto
+ // * PCH read and write
+ // * Codegen
+
+ class ExtInfo {
+ public:
+ // Constructor with no defaults. Use this when you know that you
+ // have all the elements (when reading a PCH file for example).
+ ExtInfo(bool noReturn, unsigned regParm, CallingConv cc) :
+ NoReturn(noReturn), RegParm(regParm), CC(cc) {}
+
+ // Constructor with all defaults. Use when for example creating a
+ // function know to use defaults.
+ ExtInfo() : NoReturn(false), RegParm(0), CC(CC_Default) {}
+
+ bool getNoReturn() const { return NoReturn; }
+ unsigned getRegParm() const { return RegParm; }
+ CallingConv getCC() const { return CC; }
+
+ bool operator==(const ExtInfo &Other) const {
+ return getNoReturn() == Other.getNoReturn() &&
+ getRegParm() == Other.getRegParm() &&
+ getCC() == Other.getCC();
+ }
+ bool operator!=(const ExtInfo &Other) const {
+ return !(*this == Other);
+ }
+
+ // Note that we don't have setters. That is by design, use
+ // the following with methods instead of mutating these objects.
+
+ ExtInfo withNoReturn(bool noReturn) const {
+ return ExtInfo(noReturn, getRegParm(), getCC());
+ }
+
+ ExtInfo withRegParm(unsigned RegParm) const {
+ return ExtInfo(getNoReturn(), RegParm, getCC());
+ }
+
+ ExtInfo withCallingConv(CallingConv cc) const {
+ return ExtInfo(getNoReturn(), getRegParm(), cc);
+ }
+
+ private:
+ // True if we have __attribute__((noreturn))
+ bool NoReturn;
+ // The value passed to __attribute__((regparm(x)))
+ unsigned RegParm;
+ // The calling convention as specified via
+ // __attribute__((cdecl|stdcall||fastcall))
+ CallingConv CC;
+ };
+
protected:
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
unsigned typeQuals, QualType Canonical, bool Dependent,
- bool noReturn = false, CallingConv callConv = CC_Default)
+ const ExtInfo &Info)
: Type(tc, Canonical, Dependent),
- SubClassData(SubclassInfo), TypeQuals(typeQuals), NoReturn(noReturn),
- CallConv(callConv), ResultType(res) {}
+ SubClassData(SubclassInfo), TypeQuals(typeQuals),
+ NoReturn(Info.getNoReturn()),
+ RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {}
bool getSubClassData() const { return SubClassData; }
unsigned getTypeQuals() const { return TypeQuals; }
public:
QualType getResultType() const { return ResultType; }
+ unsigned getRegParmType() const { return RegParm; }
bool getNoReturnAttr() const { return NoReturn; }
CallingConv getCallConv() const { return (CallingConv)CallConv; }
+ ExtInfo getExtInfo() const {
+ return ExtInfo(NoReturn, RegParm, (CallingConv)CallConv);
+ }
static llvm::StringRef getNameForCallConv(CallingConv CC);
@@ -1780,9 +1852,9 @@ public:
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical,
- bool NoReturn = false, CallingConv CallConv = CC_Default)
+ const ExtInfo &Info)
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
- /*Dependent=*/false, NoReturn, CallConv) {}
+ /*Dependent=*/false, Info) {}
friend class ASTContext; // ASTContext creates these.
public:
// No additional state past what FunctionType provides.
@@ -1791,12 +1863,13 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), getNoReturnAttr(), getCallConv());
+ Profile(ID, getResultType(), getExtInfo());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
- bool NoReturn, CallingConv CallConv) {
- ID.AddInteger(CallConv);
- ID.AddInteger(NoReturn);
+ const ExtInfo &Info) {
+ ID.AddInteger(Info.getCC());
+ ID.AddInteger(Info.getRegParm());
+ ID.AddInteger(Info.getNoReturn());
ID.AddPointer(ResultType.getAsOpaquePtr());
}
@@ -1827,12 +1900,12 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
- unsigned numExs, QualType Canonical, bool NoReturn,
- CallingConv CallConv)
+ unsigned numExs, QualType Canonical,
+ const ExtInfo &Info)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
(Result->isDependentType() ||
- hasAnyDependentType(ArgArray, numArgs)), NoReturn,
- CallConv),
+ hasAnyDependentType(ArgArray, numArgs)),
+ Info),
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs) {
// Fill in the trailing argument array.
@@ -1918,7 +1991,7 @@ public:
bool isVariadic, unsigned TypeQuals,
bool hasExceptionSpec, bool anyExceptionSpec,
unsigned NumExceptions, exception_iterator Exs,
- bool NoReturn, CallingConv CallConv);
+ const ExtInfo &ExtInfo);
};
@@ -2481,6 +2554,24 @@ public:
static bool classof(const InjectedClassNameType *T) { return true; }
};
+/// \brief The elaboration keyword that precedes a qualified type name or
+/// introduces an elaborated-type-specifier.
+enum ElaboratedTypeKeyword {
+ /// \brief No keyword precedes the qualified type name.
+ ETK_None,
+ /// \brief The "typename" keyword precedes the qualified type name, e.g.,
+ /// \c typename T::type.
+ ETK_Typename,
+ /// \brief The "class" keyword introduces the elaborated-type-specifier.
+ ETK_Class,
+ /// \brief The "struct" keyword introduces the elaborated-type-specifier.
+ ETK_Struct,
+ /// \brief The "union" keyword introduces the elaborated-type-specifier.
+ ETK_Union,
+ /// \brief The "enum" keyword introduces the elaborated-type-specifier.
+ ETK_Enum
+};
+
/// \brief Represents a type that was referred to via a qualified
/// name, e.g., N::M::type.
///
@@ -2531,19 +2622,19 @@ public:
static bool classof(const QualifiedNameType *T) { return true; }
};
-/// \brief Represents a 'typename' specifier that names a type within
-/// a dependent type, e.g., "typename T::type".
+/// \brief Represents a qualified type name for which the type name is
+/// dependent.
///
-/// TypenameType has a very similar structure to QualifiedNameType,
-/// which also involves a nested-name-specifier following by a type,
-/// and (FIXME!) both can even be prefixed by the 'typename'
-/// keyword. However, the two types serve very different roles:
-/// QualifiedNameType is a non-semantic type that serves only as sugar
-/// to show how a particular type was written in the source
-/// code. TypenameType, on the other hand, only occurs when the
-/// nested-name-specifier is dependent, such that we cannot resolve
-/// the actual type until after instantiation.
-class TypenameType : public Type, public llvm::FoldingSetNode {
+/// DependentNameType represents a class of dependent types that involve a
+/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
+/// name of a type. The DependentNameType may start with a "typename" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a
+/// dependent elaborated-type-specifier), or nothing (in contexts where we
+/// know that we must be referring to a type, e.g., in a base class specifier).
+class DependentNameType : public Type, public llvm::FoldingSetNode {
+ /// \brief The keyword used to elaborate this type.
+ ElaboratedTypeKeyword Keyword;
+
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
@@ -2553,23 +2644,28 @@ class TypenameType : public Type, public llvm::FoldingSetNode {
/// \brief The type that this typename specifier refers to.
NameType Name;
- TypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
- QualType CanonType)
- : Type(Typename, CanonType, true), NNS(NNS), Name(Name) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Name) {
assert(NNS->isDependent() &&
- "TypenameType requires a dependent nested-name-specifier");
+ "DependentNameType requires a dependent nested-name-specifier");
}
- TypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
- QualType CanonType)
- : Type(Typename, CanonType, true), NNS(NNS), Name(Ty) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *Ty, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Ty) {
assert(NNS->isDependent() &&
- "TypenameType requires a dependent nested-name-specifier");
+ "DependentNameType requires a dependent nested-name-specifier");
}
friend class ASTContext; // ASTContext creates these
public:
+ /// \brief Retrieve the keyword used to elaborate this type.
+ ElaboratedTypeKeyword getKeyword() const { return Keyword; }
+
/// \brief Retrieve the qualification on this type.
NestedNameSpecifier *getQualifier() const { return NNS; }
@@ -2593,19 +2689,20 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, NNS, Name);
+ Profile(ID, Keyword, NNS, Name);
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- NameType Name) {
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, NameType Name) {
+ ID.AddInteger(Keyword);
ID.AddPointer(NNS);
ID.AddPointer(Name.getOpaqueValue());
}
static bool classof(const Type *T) {
- return T->getTypeClass() == Typename;
+ return T->getTypeClass() == DependentName;
}
- static bool classof(const TypenameType *T) { return true; }
+ static bool classof(const DependentNameType *T) { return true; }
};
/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
@@ -2936,37 +3033,18 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
return Qualifiers::GCNone;
}
- /// getNoReturnAttr - Returns true if the type has the noreturn attribute,
- /// false otherwise.
-inline bool QualType::getNoReturnAttr() const {
- QualType CT = getTypePtr()->getCanonicalTypeInternal();
- if (const PointerType *PT = getTypePtr()->getAs<PointerType>()) {
+inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
+ if (const PointerType *PT = t.getAs<PointerType>()) {
if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>())
- return FT->getNoReturnAttr();
- } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
- return FT->getNoReturnAttr();
+ return FT->getExtInfo();
+ } else if (const FunctionType *FT = t.getAs<FunctionType>())
+ return FT->getExtInfo();
- return false;
+ return FunctionType::ExtInfo();
}
-/// getCallConv - Returns the calling convention of the type if the type
-/// is a function type, CC_Default otherwise.
-inline CallingConv QualType::getCallConv() const {
- if (const PointerType *PT = getTypePtr()->getAs<PointerType>())
- return PT->getPointeeType().getCallConv();
- else if (const ReferenceType *RT = getTypePtr()->getAs<ReferenceType>())
- return RT->getPointeeType().getCallConv();
- else if (const MemberPointerType *MPT =
- getTypePtr()->getAs<MemberPointerType>())
- return MPT->getPointeeType().getCallConv();
- else if (const BlockPointerType *BPT =
- getTypePtr()->getAs<BlockPointerType>()) {
- if (const FunctionType *FT = BPT->getPointeeType()->getAs<FunctionType>())
- return FT->getCallConv();
- } else if (const FunctionType *FT = getTypePtr()->getAs<FunctionType>())
- return FT->getCallConv();
-
- return CC_Default;
+inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
+ return getFunctionExtInfo(*t);
}
/// isMoreQualifiedThan - Determine whether this type is more
@@ -3152,6 +3230,15 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
return DB;
}
+/// Insertion operator for partial diagnostics. This allows sending QualType's
+/// into a diagnostic with <<.
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ QualType T) {
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
+ Diagnostic::ak_qualtype);
+ return PD;
+}
+
// Helper class template that is used by Type::getAs to ensure that one does
// not try to look through a qualified type to get to an array type.
template<typename T,
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 27659bd..a51da74 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1242,9 +1242,9 @@ class QualifiedNameTypeLoc :
};
// FIXME: locations for the typename keyword and nested name specifier.
-class TypenameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TypenameTypeLoc,
- TypenameType> {
+class DependentNameTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
+ DependentNameTypeLoc,
+ DependentNameType> {
};
}
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index e75202e..7e8b73c 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -92,7 +92,7 @@ NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
NON_CANONICAL_TYPE(QualifiedName, Type)
NON_CANONICAL_TYPE(InjectedClassName, Type)
-DEPENDENT_TYPE(Typename, Type)
+DEPENDENT_TYPE(DependentName, Type)
TYPE(ObjCInterface, Type)
TYPE(ObjCObjectPointer, Type)
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index bde4417..9ebd93b 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -33,7 +33,7 @@ class ParentMap;
class ImplicitParamDecl;
class LocationContextManager;
class StackFrameContext;
-
+
/// AnalysisContext contains the context data for the function or method under
/// analysis.
class AnalysisContext {
@@ -41,6 +41,7 @@ class AnalysisContext {
// AnalysisContext owns the following data.
CFG *cfg;
+ bool builtCFG;
LiveVariables *liveness;
ParentMap *PM;
llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
@@ -48,8 +49,8 @@ class AnalysisContext {
bool AddEHEdges;
public:
AnalysisContext(const Decl *d, bool addehedges = false)
- : D(d), cfg(0), liveness(0), PM(0), ReferencedBlockVars(0),
- AddEHEdges(addehedges) {}
+ : D(d), cfg(0), builtCFG(false), liveness(0), PM(0),
+ ReferencedBlockVars(0), AddEHEdges(addehedges) {}
~AnalysisContext();
@@ -69,7 +70,7 @@ public:
std::pair<referenced_decls_iterator, referenced_decls_iterator>
getReferencedBlockVars(const BlockDecl *BD);
-
+
/// Return the ImplicitParamDecl* associated with 'self' if this
/// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise.
const ImplicitParamDecl *getSelfDecl() const;
@@ -82,7 +83,7 @@ public:
~AnalysisContextManager();
AnalysisContext *getContext(const Decl *D);
-
+
// Discard all previously created AnalysisContexts.
void clear();
};
@@ -103,7 +104,7 @@ protected:
public:
virtual ~LocationContext();
-
+
ContextKind getKind() const { return Kind; }
AnalysisContext *getAnalysisContext() const { return Ctx; }
@@ -120,14 +121,14 @@ public:
return getAnalysisContext()->getLiveVariables();
}
- ParentMap &getParentMap() const {
+ ParentMap &getParentMap() const {
return getAnalysisContext()->getParentMap();
}
const ImplicitParamDecl *getSelfDecl() const {
return Ctx->getSelfDecl();
}
-
+
const StackFrameContext *getCurrentStackFrame() const;
const StackFrameContext *
getStackFrameForDeclContext(const DeclContext *DC) const;
@@ -157,7 +158,7 @@ class StackFrameContext : public LocationContext {
friend class LocationContextManager;
StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s, const CFGBlock *blk, unsigned idx)
- : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
+ : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
Index(idx) {}
public:
@@ -170,9 +171,9 @@ public:
unsigned getIndex() const { return Index; }
void Profile(llvm::FoldingSetNodeID &ID);
-
+
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
- const LocationContext *parent, const Stmt *s,
+ const LocationContext *parent, const Stmt *s,
const CFGBlock *blk, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
ID.AddPointer(blk);
@@ -186,7 +187,7 @@ public:
class ScopeContext : public LocationContext {
const Stmt *Enter;
-
+
friend class LocationContextManager;
ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
const Stmt *s)
@@ -229,7 +230,7 @@ public:
const LocationContext *parent, const BlockDecl *bd) {
ProfileCommon(ID, Block, ctx, parent, bd);
}
-
+
static bool classof(const LocationContext* Ctx) {
return Ctx->getKind() == Block;
}
@@ -239,7 +240,7 @@ class LocationContextManager {
llvm::FoldingSet<LocationContext> Contexts;
public:
~LocationContextManager();
-
+
const StackFrameContext *getStackFrame(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s, const CFGBlock *blk,
@@ -248,7 +249,7 @@ public:
const ScopeContext *getScope(AnalysisContext *ctx,
const LocationContext *parent,
const Stmt *s);
-
+
/// Discard all previously created LocationContext objects.
void clear();
private:
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index cbf7010..3c76201 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -17,7 +17,8 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "functional" // STL
namespace clang {
@@ -28,23 +29,30 @@ namespace clang {
//===----------------------------------------------------------------------===//
class DataflowWorkListTy {
- typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
- BlockSet wlist;
+ llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
+ llvm::SmallVector<const CFGBlock *, 10> BlockQueue;
public:
/// enqueue - Add a block to the worklist. Blocks already on the
/// worklist are not added a second time.
- void enqueue(const CFGBlock* B) { wlist.insert(B); }
+ void enqueue(const CFGBlock* B) {
+ unsigned char &x = BlockSet[B];
+ if (x == 1)
+ return;
+ x = 1;
+ BlockQueue.push_back(B);
+ }
/// dequeue - Remove a block from the worklist.
const CFGBlock* dequeue() {
- assert (!wlist.empty());
- const CFGBlock* B = *wlist.begin();
- wlist.erase(B);
+ assert(!BlockQueue.empty());
+ const CFGBlock *B = BlockQueue.back();
+ BlockQueue.pop_back();
+ BlockSet[B] = 0;
return B;
}
/// isEmpty - Return true if the worklist is empty.
- bool isEmpty() const { return wlist.empty(); }
+ bool isEmpty() const { return BlockQueue.empty(); }
};
//===----------------------------------------------------------------------===//
@@ -188,10 +196,7 @@ private:
/// SolveDataflowEquations - Perform the actual worklist algorithm
/// to compute dataflow values.
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
- // Enqueue all blocks to ensure the dataflow values are computed
- // for every block. Not all blocks are guaranteed to reach the exit block.
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
- WorkList.enqueue(&**I);
+ EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
@@ -201,6 +206,22 @@ private:
}
}
+ void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) {
+ // Enqueue all blocks to ensure the dataflow values are computed
+ // for every block. Not all blocks are guaranteed to reach the exit block.
+ for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
+ WorkList.enqueue(&**I);
+ }
+
+ void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) {
+ // Enqueue all blocks to ensure the dataflow values are computed
+ // for every block. Not all blocks are guaranteed to reach the exit block.
+ // Enqueue in reverse order since that will more likely match with
+ // the order they should ideally processed by the dataflow algorithm.
+ for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I)
+ WorkList.enqueue(&**I);
+ }
+
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
ValTy& V = TF.getVal();
TF.SetTopValue(V);
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 3afdaf5..453f660 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -397,13 +397,6 @@ BUILTIN(__sync_fetch_and_xor_4, "ii*i.", "n")
BUILTIN(__sync_fetch_and_xor_8, "LLiLLi*LLi.", "n")
BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLi*LLLi.", "n")
-BUILTIN(__sync_fetch_and_nand, "v.", "")
-BUILTIN(__sync_fetch_and_nand_1, "cc*c.", "n")
-BUILTIN(__sync_fetch_and_nand_2, "ss*s.", "n")
-BUILTIN(__sync_fetch_and_nand_4, "ii*i.", "n")
-BUILTIN(__sync_fetch_and_nand_8, "LLiLLi*LLi.", "n")
-BUILTIN(__sync_fetch_and_nand_16, "LLLiLLLi*LLLi.", "n")
-
BUILTIN(__sync_add_and_fetch, "v.", "")
BUILTIN(__sync_add_and_fetch_1, "cc*c.", "n")
@@ -440,14 +433,6 @@ BUILTIN(__sync_xor_and_fetch_4, "ii*i.", "n")
BUILTIN(__sync_xor_and_fetch_8, "LLiLLi*LLi.", "n")
BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLi*LLLi.", "n")
-BUILTIN(__sync_nand_and_fetch, "v.", "")
-BUILTIN(__sync_nand_and_fetch_1, "cc*c.", "n")
-BUILTIN(__sync_nand_and_fetch_2, "ss*s.", "n")
-BUILTIN(__sync_nand_and_fetch_4, "ii*i.", "n")
-BUILTIN(__sync_nand_and_fetch_8, "LLiLLi*LLi.", "n")
-BUILTIN(__sync_nand_and_fetch_16, "LLLiLLLi*LLLi.", "n")
-
-
BUILTIN(__sync_bool_compare_and_swap, "v.", "")
BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "n")
BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "n")
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 00b076a..5c75d37 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -317,4 +317,12 @@ BUILTIN(__builtin_ia32_crc32qi, "iic", "")
BUILTIN(__builtin_ia32_crc32hi, "iis", "")
BUILTIN(__builtin_ia32_crc32si, "iii", "")
BUILTIN(__builtin_ia32_crc32di, "LLiLLiLLi", "")
+
+// AES
+BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "")
+BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLii", "")
#undef BUILTIN
diff --git a/include/clang/Basic/CMakeLists.txt b/include/clang/Basic/CMakeLists.txt
index 9e643bb..c2a4e13 100644
--- a/include/clang/Basic/CMakeLists.txt
+++ b/include/clang/Basic/CMakeLists.txt
@@ -1,8 +1,8 @@
macro(clang_diag_gen component)
- tablegen(Diagnostic${component}Kinds.inc
- -gen-clang-diags-defs -clang-component=${component})
+ tablegen(Diagnostic${component}Kinds.inc
+ -gen-clang-diags-defs -clang-component=${component})
add_custom_target(ClangDiagnostic${component}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Diagnostic${component}Kinds.inc)
+ DEPENDS Diagnostic${component}Kinds.inc)
endmacro(clang_diag_gen)
set(LLVM_TARGET_DEFINITIONS Diagnostic.td)
@@ -17,4 +17,4 @@ clang_diag_gen(Sema)
tablegen(DiagnosticGroups.inc
-gen-clang-diag-groups)
add_custom_target(ClangDiagnosticGroups
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/DiagnosticGroups.inc)
+ DEPENDS DiagnosticGroups.inc)
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index d6c8797..6438685 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -95,7 +95,7 @@ namespace clang {
/// should also provide full recovery from such errors, such that
/// suppressing the diagnostic output can still result in successful
/// compilation.
-class CodeModificationHint {
+class FixItHint {
public:
/// \brief Tokens that should be removed to correct the error.
SourceRange RemoveRange;
@@ -110,7 +110,7 @@ public:
/// \brief Empty code modification hint, indicating that no code
/// modification is known.
- CodeModificationHint() : RemoveRange(), InsertionLoc() { }
+ FixItHint() : RemoveRange(), InsertionLoc() { }
bool isNull() const {
return !RemoveRange.isValid() && !InsertionLoc.isValid();
@@ -118,9 +118,9 @@ public:
/// \brief Create a code modification hint that inserts the given
/// code string at a specific location.
- static CodeModificationHint CreateInsertion(SourceLocation InsertionLoc,
- llvm::StringRef Code) {
- CodeModificationHint Hint;
+ static FixItHint CreateInsertion(SourceLocation InsertionLoc,
+ llvm::StringRef Code) {
+ FixItHint Hint;
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert = Code;
return Hint;
@@ -128,17 +128,17 @@ public:
/// \brief Create a code modification hint that removes the given
/// source range.
- static CodeModificationHint CreateRemoval(SourceRange RemoveRange) {
- CodeModificationHint Hint;
+ static FixItHint CreateRemoval(SourceRange RemoveRange) {
+ FixItHint Hint;
Hint.RemoveRange = RemoveRange;
return Hint;
}
/// \brief Create a code modification hint that replaces the given
/// source range with the given code string.
- static CodeModificationHint CreateReplacement(SourceRange RemoveRange,
- llvm::StringRef Code) {
- CodeModificationHint Hint;
+ static FixItHint CreateReplacement(SourceRange RemoveRange,
+ llvm::StringRef Code) {
+ FixItHint Hint;
Hint.RemoveRange = RemoveRange;
Hint.InsertionLoc = RemoveRange.getBegin();
Hint.CodeToInsert = Code;
@@ -234,6 +234,18 @@ private:
void *Cookie);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
+
+ /// \brief ID of the "delayed" diagnostic, which is a (typically
+ /// fatal) diagnostic that had to be delayed because it was found
+ /// while emitting another diagnostic.
+ unsigned DelayedDiagID;
+
+ /// \brief First string argument for the delayed diagnostic.
+ std::string DelayedDiagArg1;
+
+ /// \brief Second string argument for the delayed diagnostic.
+ std::string DelayedDiagArg2;
+
public:
explicit Diagnostic(DiagnosticClient *client = 0);
~Diagnostic();
@@ -377,6 +389,28 @@ public:
/// the diagnostic, this returns null.
static const char *getWarningOptionForDiag(unsigned DiagID);
+ /// \brief Enumeration describing how the the emission of a diagnostic should
+ /// be treated when it occurs during C++ template argument deduction.
+ enum SFINAEResponse {
+ /// \brief The diagnostic should not be reported, but it should cause
+ /// template argument deduction to fail.
+ ///
+ /// The vast majority of errors that occur during template argument
+ /// deduction fall into this category.
+ SFINAE_SubstitutionFailure,
+
+ /// \brief The diagnostic should be suppressed entirely.
+ ///
+ /// Warnings generally fall into this category.
+ SFINAE_Suppress,
+
+ /// \brief The diagnostic should be reported.
+ ///
+ /// The diagnostic should be reported. Various fatal errors (e.g.,
+ /// template instantiation depth exceeded) fall into this category.
+ SFINAE_Report
+ };
+
/// \brief Determines whether the given built-in diagnostic ID is
/// for an error that is suppressed if it occurs during C++ template
/// argument deduction.
@@ -385,7 +419,7 @@ public:
/// deduction fails but no diagnostic is emitted. Certain classes of
/// errors, such as those errors that involve C++ access control,
/// are not SFINAE errors.
- static bool isBuiltinSFINAEDiag(unsigned DiagID);
+ static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
@@ -400,10 +434,41 @@ public:
inline DiagnosticBuilder Report(FullSourceLoc Pos, unsigned DiagID);
inline DiagnosticBuilder Report(unsigned DiagID);
+ /// \brief Determine whethere there is already a diagnostic in flight.
+ bool isDiagnosticInFlight() const { return CurDiagID != ~0U; }
+
+ /// \brief Set the "delayed" diagnostic that will be emitted once
+ /// the current diagnostic completes.
+ ///
+ /// If a diagnostic is already in-flight but the front end must
+ /// report a problem (e.g., with an inconsistent file system
+ /// state), this routine sets a "delayed" diagnostic that will be
+ /// emitted after the current diagnostic completes. This should
+ /// only be used for fatal errors detected at inconvenient
+ /// times. If emitting a delayed diagnostic causes a second delayed
+ /// diagnostic to be introduced, that second delayed diagnostic
+ /// will be ignored.
+ ///
+ /// \param DiagID The ID of the diagnostic being delayed.
+ ///
+ /// \param Arg1 A string argument that will be provided to the
+ /// diagnostic. A copy of this string will be stored in the
+ /// Diagnostic object itself.
+ ///
+ /// \param Arg2 A string argument that will be provided to the
+ /// diagnostic. A copy of this string will be stored in the
+ /// Diagnostic object itself.
+ void SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1 = "",
+ llvm::StringRef Arg2 = "");
+
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
private:
+ /// \brief Report the delayed diagnostic.
+ void ReportDelayed();
+
+
/// getDiagnosticMappingInfo - Return the mapping info currently set for the
/// specified builtin diagnostic. This returns the high bit encoding, or zero
/// if the field is completely uninitialized.
@@ -454,8 +519,8 @@ private:
/// NumRanges - This is the number of ranges in the DiagRanges array.
unsigned char NumDiagRanges;
/// \brief The number of code modifications hints in the
- /// CodeModificationHints array.
- unsigned char NumCodeModificationHints;
+ /// FixItHints array.
+ unsigned char NumFixItHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
@@ -477,11 +542,11 @@ private:
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
- enum { MaxCodeModificationHints = 3 };
+ enum { MaxFixItHints = 3 };
- /// CodeModificationHints - If valid, provides a hint with some code
+ /// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
- CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
+ FixItHint FixItHints[MaxFixItHints];
/// ProcessDiag - This is the method used to report a diagnostic that is
/// finally fully formed.
@@ -508,13 +573,12 @@ private:
/// for example.
class DiagnosticBuilder {
mutable Diagnostic *DiagObj;
- mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
+ mutable unsigned NumArgs, NumRanges, NumFixItHints;
void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
friend class Diagnostic;
explicit DiagnosticBuilder(Diagnostic *diagObj)
- : DiagObj(diagObj), NumArgs(0), NumRanges(0),
- NumCodeModificationHints(0) {}
+ : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixItHints(0) {}
public:
/// Copy constructor. When copied, this "takes" the diagnostic info from the
@@ -524,7 +588,7 @@ public:
D.DiagObj = 0;
NumArgs = D.NumArgs;
NumRanges = D.NumRanges;
- NumCodeModificationHints = D.NumCodeModificationHints;
+ NumFixItHints = D.NumFixItHints;
}
/// \brief Simple enumeration value used to give a name to the
@@ -534,7 +598,7 @@ public:
/// \brief Create an empty DiagnosticBuilder object that represents
/// no actual diagnostic.
explicit DiagnosticBuilder(SuppressKind)
- : DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { }
+ : DiagObj(0), NumArgs(0), NumRanges(0), NumFixItHints(0) { }
/// \brief Force the diagnostic builder to emit the diagnostic now.
///
@@ -543,29 +607,7 @@ public:
///
/// \returns true if a diagnostic was emitted, false if the
/// diagnostic was suppressed.
- bool Emit() {
- // If DiagObj is null, then its soul was stolen by the copy ctor
- // or the user called Emit().
- if (DiagObj == 0) return false;
-
- // When emitting diagnostics, we set the final argument count into
- // the Diagnostic object.
- DiagObj->NumDiagArgs = NumArgs;
- DiagObj->NumDiagRanges = NumRanges;
- DiagObj->NumCodeModificationHints = NumCodeModificationHints;
-
- // Process the diagnostic, sending the accumulated information to the
- // DiagnosticClient.
- bool Emitted = DiagObj->ProcessDiag();
-
- // Clear out the current diagnostic object.
- DiagObj->Clear();
-
- // This diagnostic is dead.
- DiagObj = 0;
-
- return Emitted;
- }
+ bool Emit();
/// Destructor - The dtor emits the diagnostic if it hasn't already
/// been emitted.
@@ -605,14 +647,14 @@ public:
DiagObj->DiagRanges[NumRanges++] = R;
}
- void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ void AddFixItHint(const FixItHint &Hint) const {
if (Hint.isNull())
return;
- assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints &&
- "Too many code modification hints!");
+ assert(NumFixItHints < Diagnostic::MaxFixItHints &&
+ "Too many fix-it hints!");
if (DiagObj)
- DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
+ DiagObj->FixItHints[NumFixItHints++] = Hint;
}
};
@@ -673,8 +715,8 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
- const CodeModificationHint &Hint) {
- DB.AddCodeModificationHint(Hint);
+ const FixItHint &Hint) {
+ DB.AddFixItHint(Hint);
return DB;
}
@@ -770,17 +812,17 @@ public:
return DiagObj->DiagRanges[Idx];
}
- unsigned getNumCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints;
+ unsigned getNumFixItHints() const {
+ return DiagObj->NumFixItHints;
}
- const CodeModificationHint &getCodeModificationHint(unsigned Idx) const {
- return DiagObj->CodeModificationHints[Idx];
+ const FixItHint &getFixItHint(unsigned Idx) const {
+ return DiagObj->FixItHints[Idx];
}
- const CodeModificationHint *getCodeModificationHints() const {
- return DiagObj->NumCodeModificationHints?
- &DiagObj->CodeModificationHints[0] : 0;
+ const FixItHint *getFixItHints() const {
+ return DiagObj->NumFixItHints?
+ &DiagObj->FixItHints[0] : 0;
}
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
@@ -803,7 +845,7 @@ class StoredDiagnostic {
FullSourceLoc Loc;
std::string Message;
std::vector<SourceRange> Ranges;
- std::vector<CodeModificationHint> FixIts;
+ std::vector<FixItHint> FixIts;
public:
StoredDiagnostic();
@@ -823,7 +865,7 @@ public:
range_iterator range_end() const { return Ranges.end(); }
unsigned range_size() const { return Ranges.size(); }
- typedef std::vector<CodeModificationHint>::const_iterator fixit_iterator;
+ typedef std::vector<FixItHint>::const_iterator fixit_iterator;
fixit_iterator fixit_begin() const { return FixIts.begin(); }
fixit_iterator fixit_end() const { return FixIts.end(); }
unsigned fixit_size() const { return FixIts.size(); }
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 3a28282..2e0b4ba 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -22,7 +22,7 @@ def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
DefaultFatal;
def err_fe_dependency_file_requires_MT : Error<
- "-dependency-file requires at least one -MT option">;
+ "-dependency-file requires at least one -MT or -MQ option">;
def err_fe_incompatible_options : Error<
"'%0' cannot be used with '%1'">, DefaultFatal;
def err_fe_no_fixit_and_codegen : Error<
@@ -57,6 +57,9 @@ def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_error_at_end_block : Error<
"error at end of module block in PCH file: '%0'">, DefaultFatal;
+def err_fe_pch_file_modified : Error<
+ "file '%0' has been modified since the precompiled header was built">,
+ DefaultFatal;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
def err_fe_unable_to_open_logfile : Error<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 203ab1e..b0c016b 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -31,6 +31,7 @@ def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
def : DiagGroup<"ctor-dtor-privacy">;
def : DiagGroup<"declaration-after-statement">;
+def GNUDesignator : DiagGroup<"gnu-designator">;
def Deprecated : DiagGroup<"deprecated">;
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
@@ -115,6 +116,7 @@ def UnusedVariable : DiagGroup<"unused-variable">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
def Reorder : DiagGroup<"reorder">;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
+def Protocol : DiagGroup<"protocol">;
def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
def : DiagGroup<"variadic-macros">;
def VariadicMacros : DiagGroup<"variadic-macros">;
@@ -185,3 +187,6 @@ def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment
// but which aren't on by default in GCC.
def NonGCC : DiagGroup<"non-gcc",
[SignCompare, Conversion, LiteralRange]>;
+
+// A warning group for warnings about GCC extensions.
+def GNU : DiagGroup<"gnu", [GNUDesignator]>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 9d001d4..facf15f 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -50,22 +50,26 @@ def ext_enumerator_list_comma : Extension<
"feature">;
def ext_gnu_indirect_goto : Extension<
- "use of GNU indirect-goto extension">;
+ "use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<
- "use of GNU address-of-label extension">;
+ "use of GNU address-of-label extension">, InGroup<GNU>;
def ext_gnu_statement_expr : Extension<
- "use of GNU statement expression extension">;
+ "use of GNU statement expression extension">, InGroup<GNU>;
def ext_gnu_conditional_expr : Extension<
- "use of GNU ?: expression extension, eliding middle term">;
+ "use of GNU ?: expression extension, eliding middle term">, InGroup<GNU>;
def ext_gnu_empty_initializer : Extension<
- "use of GNU empty initializer extension">;
-def ext_gnu_array_range : Extension<"use of GNU array range extension">;
+ "use of GNU empty initializer extension">, InGroup<GNU>;
+def ext_gnu_array_range : Extension<"use of GNU array range extension">,
+ InGroup<GNUDesignator>;
def ext_gnu_missing_equal_designator : ExtWarn<
- "use of GNU 'missing =' extension in designator">;
+ "use of GNU 'missing =' extension in designator">,
+ InGroup<GNUDesignator>;
def err_expected_equal_designator : Error<"expected '=' or another designator">;
def ext_gnu_old_style_field_designator : ExtWarn<
- "use of GNU old-style field designator extension">;
-def ext_gnu_case_range : Extension<"use of GNU case range extension">;
+ "use of GNU old-style field designator extension">,
+ InGroup<GNUDesignator>;
+def ext_gnu_case_range : Extension<"use of GNU case range extension">,
+ InGroup<GNU>;
// Generic errors.
def err_parse_error : Error<"parse error">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 752be5d..be00972 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -68,7 +68,7 @@ def err_designator_into_flexible_array_member : Error<
def note_flexible_array_member : Note<
"initialized flexible array member %0 is here">;
def ext_flexible_array_init : Extension<
- "flexible array initialization is a GNU extension">;
+ "flexible array initialization is a GNU extension">, InGroup<GNU>;
// Declarations.
def ext_vla : Extension<
@@ -268,8 +268,6 @@ def err_duplicate_ivar_declaration : Error<
"instance variable is already declared">;
def warn_on_superclass_use : Warning<
"class implementation may not have super class">;
-def err_non_private_ivar_declaration : Error<
- "only private ivars may be declared in implementation">;
def err_conflicting_ivar_bitwidth : Error<
"instance variable %0 has conflicting bit-field width">;
def err_conflicting_ivar_name : Error<
@@ -277,7 +275,9 @@ def err_conflicting_ivar_name : Error<
def err_inconsistant_ivar_count : Error<
"inconsistent number of instance variables specified">;
def warn_incomplete_impl : Warning<"incomplete implementation">;
-def warn_undef_method_impl : Warning<"method definition for %0 not found">;
+def note_undef_method_impl : Note<"method definition for %0 not found">;
+def note_required_for_protocol_at :
+ Note<"required for direct or indirect protocol %0">;
def warn_conflicting_ret_types : Warning<
"conflicting return type in implementation of %0: %1 vs %2">;
@@ -350,7 +350,7 @@ def error_synthesized_ivar_yet_not_supported : Error<
" (need to declare %0 explicitly)">;
def error_property_ivar_type : Error<
- "type of property %0 does not match type of ivar %1">;
+ "type of property %0 (%1) does not match type of ivar %2 (%3)">;
def error_ivar_in_superclass_use : Error<
"property %0 attempting to use ivar %1 declared in super class %2">;
def error_weak_property : Error<
@@ -367,6 +367,8 @@ def warn_objc_property_attr_mutually_exclusive : Warning<
InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
+def warn_unimplemented_protocol_method : Warning<
+ "method in protocol not implemented">, InGroup<Protocol>;
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
@@ -393,7 +395,11 @@ def err_abstract_type_in_decl : Error<
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;
def err_allocation_of_abstract_type : Error<
"allocation of an object of abstract type %0">;
-
+
+def err_multiple_final_overriders : Error<
+ "virtual function %q0 has more than one final overrider in %1">;
+def note_final_overrider : Note<"final overrider of %q0 in %1">;
+
def err_type_defined_in_type_specifier : Error<
"%0 can not be defined in a type specifier">;
def err_type_defined_in_result_type : Error<
@@ -432,6 +438,8 @@ def err_incompatible_exception_specs : Error<
"target exception specification is not superset of source">;
def err_deep_exception_specs_differ : Error<
"exception specifications of %select{return|argument}0 types differ">;
+def warn_missing_exception_specification : Warning<
+ "%0 is missing exception specification '%1'">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
@@ -532,6 +540,7 @@ def err_implicit_object_parameter_init : Error<
"of type %1">;
def note_field_decl : Note<"member is declared here">;
+def note_ivar_decl : Note<"ivar is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_member_synthesized_at : Note<
@@ -776,8 +785,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">;
-def warn_attribute_void_function : Warning<
- "attribute %0 cannot be applied to functions without return value">;
+def warn_attribute_void_function_method : Warning<
+ "attribute %0 cannot be applied to "
+ "%select{functions|Objective-C method}1 without return value">;
def warn_attribute_weak_on_field : Warning<
"__weak attribute cannot be specified on a field declaration">;
def warn_attribute_weak_on_local : Warning<
@@ -1199,26 +1209,40 @@ def err_template_arg_not_integral_or_enumeral : Error<
def err_template_arg_not_ice : Error<
"non-type template argument of type %0 is not an integral constant "
"expression">;
+def err_deduced_non_type_template_arg_type_mismatch : Error<
+ "deduced non-type template argument does not have the same type as the "
+ "its corresponding template parameter (%0 vs %1)">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
-def err_template_arg_negative : Error<
- "non-type template argument provides negative value '%0' for unsigned "
- "template parameter of type %1">;
-def err_template_arg_too_large : Error<
- "non-type template argument value '%0' is too large for template "
- "parameter of type %1">;
+def warn_template_arg_negative : Warning<
+ "non-type template argument with value '%0' converted to '%1' for unsigned "
+ "template parameter of type %2">;
+def warn_template_arg_too_large : Warning<
+ "non-type template argument value '%0' truncated to '%1' for "
+ "template parameter of type %2">;
def err_template_arg_no_ref_bind : Error<
"non-type template parameter of reference type %0 cannot bind to template "
"argument of type %1">;
def err_template_arg_ref_bind_ignores_quals : Error<
"reference binding of non-type template parameter of type %0 to template "
"argument of type %1 ignores qualifiers">;
+def err_template_arg_unresolved_overloaded_function : Error<
+ "overloaded function cannot be resolved to a non-type template parameter of "
+ "type %0">;
def err_template_arg_not_decl_ref : Error<
"non-type template argument does not refer to any declaration">;
def err_template_arg_not_object_or_func_form : Error<
"non-type template argument does not directly refer to an object or "
"function">;
+def err_template_arg_not_address_of : Error<
+ "non-type template argument for template parameter of pointer type %0 must "
+ "have its address taken">;
+def err_template_arg_address_of_non_pointer : Error<
+ "address taken in non-type template argument for template parameter of "
+ "reference type %0">;
+def err_template_arg_reference_var : Error<
+ "non-type template argument of reference type %0 is not an object">;
def err_template_arg_field : Error<
"non-type template argument refers to non-static data member %0">;
def err_template_arg_method : Error<
@@ -1251,6 +1275,8 @@ def err_template_spec_decl_function_scope : Error<
"explicit specialization of %0 in function scope">;
def err_template_spec_decl_class_scope : Error<
"explicit specialization of %0 in class scope">;
+def err_template_spec_decl_friend : Error<
+ "cannot declare an explicit specialization in a friend">;
def err_template_spec_decl_out_of_scope_global : Error<
"%select{class template|class template partial|function template|member "
"function|static data member|member class}0 specialization of %1 must "
@@ -1372,13 +1398,13 @@ def note_default_function_arg_instantiation_here : Note<
"for '%0' required here">;
def note_explicit_template_arg_substitution_here : Note<
"while substituting explicitly-specified template arguments into function "
- "template %f, here">;
+ "template %0 %1">;
def note_function_template_deduction_instantiation_here : Note<
- "while substituting deduced template arguments into function template %0, "
- "here">;
+ "while substituting deduced template arguments into function template %0 "
+ "%1">;
def note_partial_spec_deduct_instantiation_here : Note<
"during template argument deduction for class template partial "
- "specialization %0, here">;
+ "specialization %0 %1">;
def note_prior_template_arg_substitution : Note<
"while substituting prior template arguments into %select{non-type|template}0"
" template parameter%1 %2">;
@@ -1537,7 +1563,8 @@ def err_forward_ref_enum : Error<
"ISO C++ forbids forward references to 'enum' types">;
def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">;
def err_duplicate_member : Error<"duplicate member %0">;
-def err_misplaced_ivar : Error<"ivars may not be placed in categories">;
+def err_misplaced_ivar : Error<
+ "ivars may not be placed in %select{categories|class extension}0">;
def ext_enum_value_not_int : Extension<
"ISO C restricts enumerator values to range of 'int' (%0 is too "
"%select{small|large}1)">;
@@ -1575,6 +1602,8 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
"pointer to function type %0 may not be 'restrict' qualified">;
def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">;
+def err_typecheck_zero_array_size : Error<
+ "zero-length arrays are not permitted in C++">;
def err_at_least_one_initializer_needed_to_size_array : Error<
"at least one initializer value required to size array">;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
@@ -1664,7 +1693,7 @@ def err_field_declared_as_function : Error<"field %0 declared as a function">;
def err_field_incomplete : Error<"field has incomplete type %0">;
def ext_variable_sized_type_in_struct : ExtWarn<
"field %0 with variable sized type %1 not at the end of a struct or class is"
- " a GNU extension">;
+ " a GNU extension">, InGroup<GNU>;
def err_flexible_array_empty_struct : Error<
"flexible array %0 not allowed in otherwise empty struct">;
@@ -2164,7 +2193,7 @@ def err_invalid_declarator_global_scope : Error<
def err_invalid_declarator_in_function : Error<
"definition or redeclaration of %0 not allowed inside a function">;
def err_not_tag_in_scope : Error<
- "%0 does not name a tag member in the specified scope">;
+ "no %select{struct|union|class|enum}0 named %1 in %2">;
def err_cannot_form_pointer_to_member_of_reference_type : Error<
"cannot form a pointer-to-member to member %0 of reference type %1">;
@@ -2322,7 +2351,8 @@ def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn<
def err_typecheck_choose_expr_requires_constant : Error<
"'__builtin_choose_expr' requires a constant expression">;
def ext_typecheck_expression_not_constant_but_accepted : Extension<
- "expression is not a constant, but is accepted as one by GNU extensions">;
+ "expression is not a constant, but is accepted as one by GNU extensions">,
+ InGroup<GNU>;
def warn_unused_expr : Warning<"expression result unused">,
InGroup<UnusedValue>;
def warn_unused_property_expr : Warning<
@@ -2334,6 +2364,7 @@ def warn_unused_call : Warning<
def err_incomplete_type_used_in_type_trait_expr : Error<
"incomplete type %0 used in type trait expression">;
+def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
// inline asm.
def err_asm_wide_character : Error<"wide string is invalid in 'asm'">;
@@ -2413,9 +2444,9 @@ def err_in_class_initializer_non_constant : Error<
// C++ anonymous unions and GNU anonymous structs/unions
def ext_anonymous_union : Extension<
- "anonymous unions are a GNU extension in C">;
+ "anonymous unions are a GNU extension in C">, InGroup<GNU>;
def ext_anonymous_struct : Extension<
- "anonymous structs are a GNU extension">;
+ "anonymous structs are a GNU extension">, InGroup<GNU>;
def err_anonymous_union_not_static : Error<
"anonymous unions at namespace or global scope must be declared 'static'">;
def err_anonymous_union_with_storage_spec : Error<
@@ -2584,6 +2615,9 @@ def warn_printf_missing_format_string : Warning<
def warn_printf_conversion_argument_type_mismatch : Warning<
"conversion specifies type %0 but the argument has type %1">,
InGroup<Format>;
+def warn_printf_positional_arg_exceeds_data_args : Warning <
+ "data argument position '%0' exceeds the number of data arguments (%1)">,
+ InGroup<Format>;
def warn_printf_zero_positional_specifier : Warning<
"position arguments in format strings start counting at 1 (not 0)">,
InGroup<Format>;
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index fb861dc..89fae87 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -15,19 +15,18 @@
#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
#define LLVM_CLANG_PARTIALDIAGNOSTIC_H
-#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/System/DataTypes.h"
+#include <cassert>
namespace clang {
-class DeclarationName;
-
class PartialDiagnostic {
+public:
struct Storage {
- Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) {
- }
+ Storage() : NumDiagArgs(0), NumDiagRanges(0), NumFixItHints(0) { }
enum {
/// MaxArguments - The maximum number of arguments we can hold. We
@@ -44,8 +43,8 @@ class PartialDiagnostic {
unsigned char NumDiagRanges;
/// \brief The number of code modifications hints in the
- /// CodeModificationHints array.
- unsigned char NumCodeModificationHints;
+ /// FixItHints array.
+ unsigned char NumFixItHints;
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
/// values, with one for each argument. This specifies whether the argument
@@ -62,13 +61,49 @@ class PartialDiagnostic {
/// only support 10 ranges, could easily be extended if needed.
SourceRange DiagRanges[10];
- enum { MaxCodeModificationHints = 3 };
+ enum { MaxFixItHints = 3 };
- /// CodeModificationHints - If valid, provides a hint with some code
+ /// FixItHints - If valid, provides a hint with some code
/// to insert, remove, or modify at a particular position.
- CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
+ FixItHint FixItHints[MaxFixItHints];
};
+ /// \brief An allocator for Storage objects, which uses a small cache to
+ /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
+ class StorageAllocator {
+ static const unsigned NumCached = 4;
+ Storage Cached[NumCached];
+ Storage *FreeList[NumCached];
+ unsigned NumFreeListEntries;
+
+ public:
+ StorageAllocator();
+ ~StorageAllocator();
+
+ /// \brief Allocate new storage.
+ Storage *Allocate() {
+ if (NumFreeListEntries == 0)
+ return new Storage;
+
+ Storage *Result = FreeList[--NumFreeListEntries];
+ Result->NumDiagArgs = 0;
+ Result->NumDiagRanges = 0;
+ Result->NumFixItHints = 0;
+ return Result;
+ }
+
+ /// \brief Free the given storage object.
+ void Deallocate(Storage *S) {
+ if (S >= Cached && S <= Cached + NumCached) {
+ FreeList[NumFreeListEntries++] = S;
+ return;
+ }
+
+ delete S;
+ }
+ };
+
+private:
// NOTE: Sema assumes that PartialDiagnostic is location-invariant
// in the sense that its bits can be safely memcpy'ed and destructed
// in the new location.
@@ -76,22 +111,40 @@ class PartialDiagnostic {
/// DiagID - The diagnostic ID.
mutable unsigned DiagID;
- /// DiagStorare - Storge for args and ranges.
+ /// DiagStorage - Storage for args and ranges.
mutable Storage *DiagStorage;
- void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
- if (!DiagStorage)
+ /// \brief Allocator used to allocate storage for this diagnostic.
+ StorageAllocator *Allocator;
+
+ /// \brief Retrieve storage for this particular diagnostic.
+ Storage *getStorage() const {
+ if (DiagStorage)
+ return DiagStorage;
+
+ if (Allocator)
+ DiagStorage = Allocator->Allocate();
+ else {
+ assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
DiagStorage = new Storage;
+ }
+ return DiagStorage;
+ }
+
+ void freeStorage() {
+ if (!DiagStorage)
+ return;
- assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
- "Too many arguments to diagnostic!");
- DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
- DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+ if (Allocator)
+ Allocator->Deallocate(DiagStorage);
+ else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
+ delete DiagStorage;
+ DiagStorage = 0;
}
-
+
void AddSourceRange(const SourceRange &R) const {
if (!DiagStorage)
- DiagStorage = new Storage;
+ DiagStorage = getStorage();
assert(DiagStorage->NumDiagRanges <
llvm::array_lengthof(DiagStorage->DiagRanges) &&
@@ -99,53 +152,70 @@ class PartialDiagnostic {
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
}
- void AddCodeModificationHint(const CodeModificationHint &Hint) const {
+ void AddFixItHint(const FixItHint &Hint) const {
if (Hint.isNull())
return;
if (!DiagStorage)
- DiagStorage = new Storage;
+ DiagStorage = getStorage();
- assert(DiagStorage->NumCodeModificationHints <
- Storage::MaxCodeModificationHints &&
+ assert(DiagStorage->NumFixItHints < Storage::MaxFixItHints &&
"Too many code modification hints!");
- DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++]
+ DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
= Hint;
}
public:
- PartialDiagnostic(unsigned DiagID)
- : DiagID(DiagID), DiagStorage(0) { }
-
+ PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
+ : DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
+
PartialDiagnostic(const PartialDiagnostic &Other)
- : DiagID(Other.DiagID), DiagStorage(0)
+ : DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
{
- if (Other.DiagStorage)
- DiagStorage = new Storage(*Other.DiagStorage);
+ if (Other.DiagStorage) {
+ DiagStorage = getStorage();
+ *DiagStorage = *Other.DiagStorage;
+ }
}
+ PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
+ : DiagID(Other.DiagID), DiagStorage(DiagStorage),
+ Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
+ {
+ if (Other.DiagStorage)
+ *this->DiagStorage = *Other.DiagStorage;
+ }
+
PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
DiagID = Other.DiagID;
if (Other.DiagStorage) {
- if (DiagStorage)
- *DiagStorage = *Other.DiagStorage;
- else
- DiagStorage = new Storage(*Other.DiagStorage);
+ if (!DiagStorage)
+ DiagStorage = getStorage();
+
+ *DiagStorage = *Other.DiagStorage;
} else {
- delete DiagStorage;
- DiagStorage = 0;
+ freeStorage();
}
return *this;
}
~PartialDiagnostic() {
- delete DiagStorage;
+ freeStorage();
}
-
unsigned getDiagID() const { return DiagID; }
+ void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
+ if (!DiagStorage)
+ DiagStorage = getStorage();
+
+ assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
+ "Too many arguments to diagnostic!");
+ DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
+ DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+ }
+
void Emit(const DiagnosticBuilder &DB) const {
if (!DiagStorage)
return;
@@ -161,17 +231,19 @@ public:
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
// Add all code modification hints
- for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i)
- DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]);
+ for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
+ DB.AddFixItHint(DiagStorage->FixItHints[i]);
}
- friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- QualType T) {
- PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
- Diagnostic::ak_qualtype);
- return PD;
+ /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
+ /// and removing all of its arguments, ranges, and fix-it hints.
+ void Reset(unsigned DiagID = 0) {
+ this->DiagID = DiagID;
+ freeStorage();
}
-
+
+ bool hasStorage() const { return DiagStorage != 0; }
+
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
unsigned I) {
PD.AddTaggedVal(I, Diagnostic::ak_uint);
@@ -197,20 +269,13 @@ public:
}
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- DeclarationName N);
-
- friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
- const CodeModificationHint &Hint) {
- PD.AddCodeModificationHint(Hint);
+ const FixItHint &Hint) {
+ PD.AddFixItHint(Hint);
return PD;
}
};
-inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
- return PartialDiagnostic(DiagID);
-}
-
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const PartialDiagnostic &PD) {
PD.Emit(DB);
@@ -219,4 +284,4 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
} // end namespace clang
-#endif
+#endif
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index f7ea331..555e6f5 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -28,7 +28,6 @@ namespace llvm {
namespace clang {
class SourceManager;
-class FileEntry;
/// FileID - This is an opaque identifier used by SourceManager which refers to
/// a source file (MemoryBuffer) along with its #include path and #line data.
diff --git a/include/clang/Checker/BugReporter/BugReporter.h b/include/clang/Checker/BugReporter/BugReporter.h
index 2c15f2a..6170342 100644
--- a/include/clang/Checker/BugReporter/BugReporter.h
+++ b/include/clang/Checker/BugReporter/BugReporter.h
@@ -15,17 +15,12 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
#define LLVM_CLANG_ANALYSIS_BUGREPORTER
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Checker/BugReporter/BugType.h"
-#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallString.h"
#include <list>
namespace clang {
@@ -35,6 +30,8 @@ class PathDiagnosticPiece;
class PathDiagnosticClient;
class ASTContext;
class Diagnostic;
+class ExplodedNode;
+class ExplodedGraph;
class BugReporter;
class BugReporterContext;
class GRExprEngine;
diff --git a/include/clang/Checker/BugReporter/BugType.h b/include/clang/Checker/BugReporter/BugType.h
index 4f1523a..afc07c8 100644
--- a/include/clang/Checker/BugReporter/BugType.h
+++ b/include/clang/Checker/BugReporter/BugType.h
@@ -14,15 +14,12 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
-#include <llvm/ADT/FoldingSet.h>
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "llvm/ADT/FoldingSet.h"
#include <string>
namespace clang {
-class BugReportEquivClass;
-class BugReporter;
-class BuiltinBugReport;
-class BugReporterContext;
class ExplodedNode;
class GRExprEngine;
diff --git a/include/clang/Checker/BugReporter/PathDiagnostic.h b/include/clang/Checker/BugReporter/PathDiagnostic.h
index d380c45..24c75ce 100644
--- a/include/clang/Checker/BugReporter/PathDiagnostic.h
+++ b/include/clang/Checker/BugReporter/PathDiagnostic.h
@@ -168,7 +168,7 @@ public:
private:
const std::string str;
- std::vector<CodeModificationHint> CodeModificationHints;
+ std::vector<FixItHint> FixItHints;
const Kind kind;
const DisplayHint Hint;
std::vector<SourceRange> ranges;
@@ -203,8 +203,8 @@ public:
ranges.push_back(SourceRange(B,E));
}
- void addCodeModificationHint(const CodeModificationHint& Hint) {
- CodeModificationHints.push_back(Hint);
+ void addFixItHint(const FixItHint& Hint) {
+ FixItHints.push_back(Hint);
}
typedef const SourceRange* range_iterator;
@@ -217,15 +217,15 @@ public:
return ranges_begin() + ranges.size();
}
- typedef const CodeModificationHint *code_modifications_iterator;
+ typedef const FixItHint *fixit_iterator;
- code_modifications_iterator code_modifications_begin() const {
- return CodeModificationHints.empty()? 0 : &CodeModificationHints[0];
+ fixit_iterator fixit_begin() const {
+ return FixItHints.empty()? 0 : &FixItHints[0];
}
- code_modifications_iterator code_modifications_end() const {
- return CodeModificationHints.empty()? 0
- : &CodeModificationHints[0] + CodeModificationHints.size();
+ fixit_iterator fixit_end() const {
+ return FixItHints.empty()? 0
+ : &FixItHints[0] + FixItHints.size();
}
static inline bool classof(const PathDiagnosticPiece* P) {
diff --git a/include/clang/Checker/DomainSpecific/CocoaConventions.h b/include/clang/Checker/DomainSpecific/CocoaConventions.h
index ee3d648..4bbdab0 100644
--- a/include/clang/Checker/DomainSpecific/CocoaConventions.h
+++ b/include/clang/Checker/DomainSpecific/CocoaConventions.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_CHECKER_DS_COCOA
#define LLVM_CLANG_CHECKER_DS_COCOA
-#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/Type.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/BasicValueFactory.h b/include/clang/Checker/PathSensitive/BasicValueFactory.h
index 2f0b6c2..59dd919 100644
--- a/include/clang/Checker/PathSensitive/BasicValueFactory.h
+++ b/include/clang/Checker/PathSensitive/BasicValueFactory.h
@@ -16,7 +16,6 @@
#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
-#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h
index 2401a72..8cb9cc8 100644
--- a/include/clang/Checker/PathSensitive/Checker.h
+++ b/include/clang/Checker/PathSensitive/Checker.h
@@ -14,21 +14,15 @@
#ifndef LLVM_CLANG_ANALYSIS_CHECKER
#define LLVM_CLANG_ANALYSIS_CHECKER
+
#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
-#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
//===----------------------------------------------------------------------===//
// Checker interface.
//===----------------------------------------------------------------------===//
namespace clang {
- class GRExprEngine;
class CheckerContext {
ExplodedNodeSet &Dst;
diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h
index 6051654..b9bbebc 100644
--- a/include/clang/Checker/PathSensitive/Environment.h
+++ b/include/clang/Checker/PathSensitive/Environment.h
@@ -18,11 +18,8 @@
// typedefs.
#include "clang/Checker/PathSensitive/Store.h"
-#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/Checker/PathSensitive/SVals.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h
index d6c4436..c09c893 100644
--- a/include/clang/Checker/PathSensitive/ExplodedGraph.h
+++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h
@@ -9,6 +9,10 @@
//
// This file defines the template classes ExplodedNode and ExplodedGraph,
// which represent a path-sensitive, intra-procedural "exploded graph."
+// See "Precise interprocedural dataflow analysis via graph reachability"
+// by Reps, Horwitz, and Sagiv
+// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
+// exploded graph.
//
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Checker/PathSensitive/GRBlockCounter.h b/include/clang/Checker/PathSensitive/GRBlockCounter.h
index 67ed953..b7d0e8a 100644
--- a/include/clang/Checker/PathSensitive/GRBlockCounter.h
+++ b/include/clang/Checker/PathSensitive/GRBlockCounter.h
@@ -22,6 +22,8 @@ namespace llvm {
namespace clang {
+class StackFrameContext;
+
class GRBlockCounter {
void* Data;
@@ -30,7 +32,8 @@ class GRBlockCounter {
public:
GRBlockCounter() : Data(0) {}
- unsigned getNumVisited(unsigned BlockID) const;
+ unsigned getNumVisited(const StackFrameContext *CallSite,
+ unsigned BlockID) const;
class Factory {
void* F;
@@ -39,7 +42,9 @@ public:
~Factory();
GRBlockCounter GetEmptyCounter();
- GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
+ GRBlockCounter IncrementCount(GRBlockCounter BC,
+ const StackFrameContext *CallSite,
+ unsigned BlockID);
};
friend class Factory;
diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
index c5bf513..a3ff0db 100644
--- a/include/clang/Checker/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -82,7 +82,7 @@ class GRCoreEngine {
void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder);
- bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+ bool ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
GRBlockCounter BC);
@@ -174,7 +174,9 @@ public:
GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(B.getBlockID());
+ return getBlockCounter().getNumVisited(
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ B.getBlockID());
}
ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
@@ -434,7 +436,9 @@ public:
}
unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(B.getBlockID());
+ return getBlockCounter().getNumVisited(
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ B.getBlockID());
}
ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 916511e..161cb28 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -16,7 +16,6 @@
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
-#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRSubEngine.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
@@ -28,11 +27,9 @@
#include "clang/AST/ExprCXX.h"
namespace clang {
-
- class PathDiagnosticClient;
- class Diagnostic;
- class ObjCForCollectionStmt;
- class Checker;
+class AnalysisManager;
+class Checker;
+class ObjCForCollectionStmt;
class GRExprEngine : public GRSubEngine {
AnalysisManager &AMgr;
@@ -153,7 +150,7 @@ public:
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
- bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC);
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
@@ -216,7 +213,7 @@ public:
const GRState* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
const void *tag = 0);
-protected:
+
/// CheckerVisit - Dispatcher for performing checker-specific logic
/// at specific statements.
void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
@@ -351,10 +348,21 @@ protected:
void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+
+ void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ void VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
/// Create a C++ temporary object for an rvalue.
void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
+ /// Synthesize CXXThisRegion.
+ const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *MD,
+ const StackFrameContext *SFC);
+
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
diff --git a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
index 383463b..6d85e5f 100644
--- a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
+++ b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
@@ -17,18 +17,9 @@
#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
#include "clang/Checker/PathSensitive/GRAuditor.h"
-#include "clang/Checker/PathSensitive/GRState.h"
namespace clang {
-class Diagnostic;
-class BugReporter;
-class ASTContext;
-class GRExprEngine;
-class PathDiagnosticClient;
-class ExplodedGraph;
-
-
class GRSimpleAPICheck : public GRAuditor {
public:
GRSimpleAPICheck() {}
diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
index 657266b..25ba1f8 100644
--- a/include/clang/Checker/PathSensitive/GRState.h
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -14,30 +14,22 @@
#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
-// FIXME: Reduce the number of includes.
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Checker/PathSensitive/ConstraintManager.h"
#include "clang/Checker/PathSensitive/Environment.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/Store.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/DataTypes.h"
-#include <functional>
-namespace clang {
+namespace llvm {
+class APSInt;
+class BumpPtrAllocator;
+class raw_ostream;
+}
+namespace clang {
+class ASTContext;
class GRStateManager;
class Checker;
@@ -302,6 +294,8 @@ public:
template<typename T>
const GRState *remove(typename GRStateTrait<T>::key_type K,
typename GRStateTrait<T>::context_type C) const;
+ template <typename T>
+ const GRState *remove() const;
template<typename T>
const GRState *set(typename GRStateTrait<T>::data_type D) const;
@@ -464,6 +458,7 @@ public:
// Methods that manipulate the GDM.
const GRState* addGDM(const GRState* St, void* Key, void* Data);
+ const GRState *removeGDM(const GRState *state, void *Key);
// Methods that query & manipulate the Store.
@@ -528,6 +523,10 @@ public:
GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
}
+ template <typename T>
+ const GRState *remove(const GRState *st) {
+ return removeGDM(st, GRStateTrait<T>::GDMIndex());
+ }
void* FindGDMContext(void* index,
void* (*CreateContext)(llvm::BumpPtrAllocator&),
@@ -702,6 +701,11 @@ const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
return getStateManager().remove<T>(this, K, C);
}
+template <typename T>
+const GRState *GRState::remove() const {
+ return getStateManager().remove<T>(this);
+}
+
template<typename T>
const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
return getStateManager().set<T>(this, D);
diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h
index f2cd048..d2e7457 100644
--- a/include/clang/Checker/PathSensitive/GRSubEngine.h
+++ b/include/clang/Checker/PathSensitive/GRSubEngine.h
@@ -20,6 +20,7 @@ namespace clang {
class Stmt;
class CFGBlock;
class CFGElement;
+class ExplodedNode;
class GRState;
class GRStateManager;
class GRBlockCounter;
@@ -47,7 +48,7 @@ public:
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
- virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ virtual bool ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC) = 0;
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
index 04634ef..13325ed 100644
--- a/include/clang/Checker/PathSensitive/GRTransferFuncs.h
+++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
@@ -15,16 +15,18 @@
#ifndef LLVM_CLANG_ANALYSIS_GRTF
#define LLVM_CLANG_ANALYSIS_GRTF
-#include "clang/Checker/PathSensitive/SVals.h"
-#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/SVals.h"
#include <vector>
namespace clang {
-
+class ExplodedNode;
+class ExplodedNodeSet;
+class GREndPathNodeBuilder;
class GRExprEngine;
-class ObjCMessageExpr;
+class GRStmtNodeBuilder;
class GRStmtNodeBuilderRef;
+class ObjCMessageExpr;
class GRTransferFuncs {
public:
diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
index be89d2a..57ea8a3 100644
--- a/include/clang/Checker/PathSensitive/MemRegion.h
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -18,17 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Checker/PathSensitive/SymbolManager.h"
#include "clang/Checker/PathSensitive/SVals.h"
-#include "clang/AST/ASTContext.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ImmutableList.h"
-#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/Support/Allocator.h"
#include <string>
-namespace llvm { class raw_ostream; }
+namespace llvm {
+class BumpPtrAllocator;
+class raw_ostream;
+}
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
index edc3380..72565f4 100644
--- a/include/clang/Checker/PathSensitive/Store.h
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -18,9 +18,6 @@
#include "clang/Checker/PathSensitive/SVals.h"
#include "clang/Checker/PathSensitive/ValueManager.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallVector.h"
namespace clang {
diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h
index b6630c3..dea877c 100644
--- a/include/clang/Checker/PathSensitive/SymbolManager.h
+++ b/include/clang/Checker/PathSensitive/SymbolManager.h
@@ -17,14 +17,14 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/System/DataTypes.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseSet.h"
namespace llvm {
- class raw_ostream;
+class BumpPtrAllocator;
+class raw_ostream;
}
namespace clang {
@@ -34,9 +34,6 @@ namespace clang {
class TypedRegion;
class VarRegion;
class StackFrameContext;
-}
-
-namespace clang {
class SymExpr : public llvm::FoldingSetNode {
public:
@@ -247,6 +244,7 @@ public:
QualType t)
: SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+ BinaryOperator::Opcode getOpcode() const { return Op; }
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
diff --git a/include/clang/CodeGen/CodeGenOptions.h b/include/clang/CodeGen/CodeGenOptions.h
index 85c6c3e..638ed51 100644
--- a/include/clang/CodeGen/CodeGenOptions.h
+++ b/include/clang/CodeGen/CodeGenOptions.h
@@ -15,7 +15,6 @@
#define LLVM_CLANG_CODEGEN_CODEGENOPTIONS_H
#include <string>
-#include <vector>
namespace clang {
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index feebbc7..124288a 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -156,6 +156,7 @@ def dependency_file : Separate<"-dependency-file">,
HelpText<"Filename (or -) to write dependency output to">;
def sys_header_deps : Flag<"-sys-header-deps">,
HelpText<"Include system headers in dependency output">;
+def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">;
def MT : Separate<"-MT">, HelpText<"Specify target for dependency">;
def MP : Flag<"-MP">,
HelpText<"Create phony target for each dependency (other than main file)">;
@@ -407,6 +408,8 @@ def fwritable_strings : Flag<"-fwritable-strings">,
def nostdinc : Flag<"-nostdinc">,
HelpText<"Disable standard #include directories">;
+def nostdincxx : Flag<"-nostdinc++">,
+ HelpText<"Disable standard #include directories for the C++ standard library">;
def nobuiltininc : Flag<"-nobuiltininc">,
HelpText<"Disable builtin #include directories">;
def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">,
diff --git a/include/clang/Driver/CMakeLists.txt b/include/clang/Driver/CMakeLists.txt
index f720d15..ed9825b 100644
--- a/include/clang/Driver/CMakeLists.txt
+++ b/include/clang/Driver/CMakeLists.txt
@@ -2,10 +2,10 @@ set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(Options.inc
-gen-opt-parser-defs)
add_custom_target(ClangDriverOptions
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Options.inc)
+ DEPENDS Options.inc)
set(LLVM_TARGET_DEFINITIONS CC1Options.td)
tablegen(CC1Options.inc
-gen-opt-parser-defs)
add_custom_target(ClangCC1Options
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CC1Options.inc)
+ DEPENDS CC1Options.inc)
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index f49c3b9..90c3a0d 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -64,6 +64,12 @@ public:
/// The path to the compiler resource directory.
std::string ResourceDir;
+ /// A prefix directory used to emulated a limited subset of GCC's '-Bprefix'
+ /// functionality.
+ /// FIXME: This type of customization should be removed in favor of the
+ /// universal driver when it is ready.
+ std::string PrefixDir;
+
/// Default host triple.
std::string DefaultHostTriple;
@@ -133,7 +139,8 @@ public:
Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
llvm::StringRef _DefaultHostTriple,
llvm::StringRef _DefaultImageName,
- bool IsProduction, Diagnostic &_Diags);
+ bool IsProduction, bool CXXIsProduction,
+ Diagnostic &_Diags);
~Driver();
/// @name Accessors
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 71258f9..d088be0 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -118,7 +118,7 @@ def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>,
HelpText<"Print the commands to run for this compilation">;
def A : JoinedOrSeparate<"-A">;
-def B : JoinedOrSeparate<"-B">, Flags<[Unsupported]>;
+def B : JoinedOrSeparate<"-B">;
def CC : Flag<"-CC">;
def C : Flag<"-C">;
def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>;
@@ -470,6 +470,7 @@ def noprebind : Flag<"-noprebind">;
def noseglinkedit : Flag<"-noseglinkedit">;
def nostartfiles : Flag<"-nostartfiles">;
def nostdinc : Flag<"-nostdinc">;
+def nostdincxx : Flag<"-nostdinc++">;
def nostdlib : Flag<"-nostdlib">;
def object : Flag<"-object">;
def o : JoinedOrSeparate<"-o">, Flags<[DriverOption, RenderAsInput]>,
diff --git a/include/clang/Frontend/HeaderSearchOptions.h b/include/clang/Frontend/HeaderSearchOptions.h
index 6904085..c668245 100644
--- a/include/clang/Frontend/HeaderSearchOptions.h
+++ b/include/clang/Frontend/HeaderSearchOptions.h
@@ -71,13 +71,17 @@ public:
/// Include the system standard include search directories.
unsigned UseStandardIncludes : 1;
+ /// Include the system standard C++ library include search directories.
+ unsigned UseStandardCXXIncludes : 1;
+
/// Whether header search information should be output as for -v.
unsigned Verbose : 1;
public:
HeaderSearchOptions(llvm::StringRef _Sysroot = "/")
: Sysroot(_Sysroot), UseBuiltinIncludes(true),
- UseStandardIncludes(true), Verbose(false) {}
+ UseStandardIncludes(true), UseStandardCXXIncludes(true),
+ Verbose(false) {}
/// AddPath - Add the \arg Path path to the specified \arg Group list.
void AddPath(llvm::StringRef Path, frontend::IncludeDirGroup Group,
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index d09e51f..157876b 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -69,7 +69,7 @@ public:
void EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges, unsigned NumRanges,
SourceManager &SM,
- const CodeModificationHint *Hints,
+ const FixItHint *Hints,
unsigned NumHints,
unsigned Columns);
diff --git a/include/clang/Frontend/TypeXML.def b/include/clang/Frontend/TypeXML.def
index dd5018a..3add99a 100644
--- a/include/clang/Frontend/TypeXML.def
+++ b/include/clang/Frontend/TypeXML.def
@@ -233,7 +233,7 @@ NODE_XML(QualifiedNameType, "QualifiedNameType")
TYPE_ATTRIBUTE_XML(getNamedType())
END_NODE_XML
-NODE_XML(TypenameType, "TypenameType")
+NODE_XML(DependentNameType, "DependentNameType")
ID_ATTRIBUTE_XML
END_NODE_XML
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index dd24fb7..e891e94 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -44,6 +44,12 @@ public:
SrcMgr::CharacteristicKind FileType) {
}
+
+ /// EndOfMainFile - This callback is invoked when the end of the main file is
+ /// reach, no subsequent callbacks will be made.
+ virtual void EndOfMainFile() {
+ }
+
/// Ident - This callback is invoked when a #ident or #sccs directive is read.
///
virtual void Ident(SourceLocation Loc, const std::string &str) {
@@ -90,6 +96,11 @@ public:
Second->FileChanged(Loc, Reason, FileType);
}
+ virtual void EndOfMainFile() {
+ First->EndOfMainFile();
+ Second->EndOfMainFile();
+ }
+
virtual void Ident(SourceLocation Loc, const std::string &str) {
First->Ident(Loc, str);
Second->Ident(Loc, str);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 23c118d..312a760 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -368,6 +368,10 @@ public:
/// which implicitly adds the builtin defines etc.
bool EnterMainSourceFile();
+ /// EndSourceFile - Inform the preprocessor callbacks that processing is
+ /// complete.
+ void EndSourceFile();
+
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer. Return true
/// and fill in ErrorStr with the error information on failure.
diff --git a/include/clang/Lex/PreprocessorLexer.h b/include/clang/Lex/PreprocessorLexer.h
index 85c44c5..477a213 100644
--- a/include/clang/Lex/PreprocessorLexer.h
+++ b/include/clang/Lex/PreprocessorLexer.h
@@ -21,6 +21,7 @@
namespace clang {
+class FileEntry;
class Preprocessor;
class PreprocessorLexer {
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index b79e698..59cc0d2 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -1761,7 +1761,8 @@ public:
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac) {
+ SourceLocation RBrac,
+ AttributeList *AttrList) {
}
//===---------------------------C++ Templates----------------------------===//
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7f5c9b1..c77acce 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -45,7 +45,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t),
Idents(idents), Selectors(sels),
- BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
+ BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts),
+ LastSDM(0, 0) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
ObjCSelRedefinitionType = QualType();
@@ -858,34 +859,22 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
}
-unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
- unsigned count = 0;
- for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
- E = PD->prop_end(); I != E; ++I)
- if ((*I)->getPropertyIvarDecl())
- ++count;
-
- // Also look into nested protocols.
- for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
- E = PD->protocol_end(); P != E; ++P)
- count += CountProtocolSynthesizedIvars(*P);
- return count;
-}
-
-unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) {
- unsigned count = 0;
- for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
- E = OI->prop_end(); I != E; ++I) {
- if ((*I)->getPropertyIvarDecl())
+unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) {
+ unsigned count = 0;
+ // Count ivars declared in class extension.
+ if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) {
+ for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
+ E = CDecl->ivar_end(); I != E; ++I) {
++count;
+ }
}
- // Also look into interface's protocol list for properties declared
- // in the protocol and whose ivars are synthesized.
- for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
- PE = OI->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *PD = (*P);
- count += CountProtocolSynthesizedIvars(PD);
- }
+
+ // Count ivar defined in this class's implementation. This
+ // includes synthesized ivars.
+ if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I)
+ ++count;
return count;
}
@@ -966,7 +955,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
// Add in synthesized ivar count if laying out an implementation.
if (Impl) {
- unsigned SynthCount = CountSynthesizedIvars(D);
+ unsigned SynthCount = CountNonClassIvars(D);
// If there aren't any sythesized ivars then reuse the interface
// entry. Note we can't cache this because we simply free all
// entries later; however we shouldn't look up implementations
@@ -1108,14 +1097,12 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
-static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
- bool AddNoReturn,
- CallingConv CallConv) {
+static QualType getExtFunctionType(ASTContext& Context, QualType T,
+ const FunctionType::ExtInfo &Info) {
QualType ResultType;
if (const PointerType *Pointer = T->getAs<PointerType>()) {
QualType Pointee = Pointer->getPointeeType();
- ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
- CallConv);
+ ResultType = getExtFunctionType(Context, Pointee, Info);
if (ResultType == Pointee)
return T;
@@ -1123,19 +1110,18 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
} else if (const BlockPointerType *BlockPointer
= T->getAs<BlockPointerType>()) {
QualType Pointee = BlockPointer->getPointeeType();
- ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
- CallConv);
+ ResultType = getExtFunctionType(Context, Pointee, Info);
if (ResultType == Pointee)
return T;
ResultType = Context.getBlockPointerType(ResultType);
} else if (const FunctionType *F = T->getAs<FunctionType>()) {
- if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv)
+ if (F->getExtInfo() == Info)
return T;
if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(),
- AddNoReturn, CallConv);
+ Info);
} else {
const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
ResultType
@@ -1146,7 +1132,7 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
FPT->hasAnyExceptionSpec(),
FPT->getNumExceptions(),
FPT->exception_begin(),
- AddNoReturn, CallConv);
+ Info);
}
} else
return T;
@@ -1155,11 +1141,21 @@ static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
}
QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
- return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv());
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withNoReturn(AddNoReturn));
}
QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
- return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv);
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withCallingConv(CallConv));
+}
+
+QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) {
+ FunctionType::ExtInfo Info = getFunctionExtInfo(T);
+ return getExtFunctionType(*this, T,
+ Info.withRegParm(RegParm));
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -1617,12 +1613,13 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
-QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
- CallingConv CallConv) {
+QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
+ const FunctionType::ExtInfo &Info) {
+ const CallingConv CallConv = Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv);
+ FunctionNoProtoType::Profile(ID, ResultTy, Info);
void *InsertPos = 0;
if (FunctionNoProtoType *FT =
@@ -1632,8 +1629,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
QualType Canonical;
if (!ResultTy.isCanonical() ||
getCanonicalCallConv(CallConv) != CallConv) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
- getCanonicalCallConv(CallConv));
+ Canonical =
+ getFunctionNoProtoType(getCanonicalType(ResultTy),
+ Info.withCallingConv(getCanonicalCallConv(CallConv)));
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1642,7 +1640,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
}
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv);
+ FunctionNoProtoType(ResultTy, Canonical, Info);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
@@ -1654,14 +1652,15 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec, unsigned NumExs,
- const QualType *ExArray, bool NoReturn,
- CallingConv CallConv) {
+ const QualType *ExArray,
+ const FunctionType::ExtInfo &Info) {
+ const CallingConv CallConv= Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- NumExs, ExArray, NoReturn, CallConv);
+ NumExs, ExArray, Info);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1686,8 +1685,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
- false, 0, 0, NoReturn,
- getCanonicalCallConv(CallConv));
+ false, 0, 0,
+ Info.withCallingConv(getCanonicalCallConv(CallConv)));
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1704,7 +1703,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
NumExs*sizeof(QualType), TypeAlignment);
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- ExArray, NumExs, Canonical, NoReturn, CallConv);
+ ExArray, NumExs, Canonical, Info);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1963,66 +1962,76 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
return QualType(T, 0);
}
-QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon) {
+QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
- if (CanonNNS != NNS)
- Canon = getTypenameType(CanonNNS, Name);
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+
+ if (CanonNNS != NNS || CanonKeyword != Keyword)
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
}
llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, Name);
+ DependentNameType::Profile(ID, Keyword, NNS, Name);
void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *T
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
- T = new (*this) TypenameType(NNS, Name, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
Types.push_back(T);
- TypenameTypes.InsertNode(T, InsertPos);
+ DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
QualType
-ASTContext::getTypenameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon) {
+ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
- TypenameType::Profile(ID, NNS, TemplateId);
+ DependentNameType::Profile(ID, Keyword, NNS, TemplateId);
void *InsertPos = 0;
- TypenameType *T
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *T
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
- if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+ if (CanonNNS != NNS || CanonKeyword != Keyword ||
+ CanonType != QualType(TemplateId, 0)) {
const TemplateSpecializationType *CanonTemplateId
= CanonType->getAs<TemplateSpecializationType>();
assert(CanonTemplateId &&
"Canonical type must also be a template specialization type");
- Canon = getTypenameType(CanonNNS, CanonTemplateId);
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId);
}
- TypenameType *CheckT
- = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentNameType *CheckT
+ = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
}
- T = new (*this) TypenameType(NNS, TemplateId, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon);
Types.push_back(T);
- TypenameTypes.InsertNode(T, InsertPos);
+ DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
@@ -4127,14 +4136,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT) {
- if (RHSOPT->isObjCBuiltinType())
+ if (RHSOPT->isObjCBuiltinType() ||
+ LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
}
- if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
+ if (RHSOPT->isObjCQualifiedIdType())
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
QualType(RHSOPT,0),
false);
@@ -4315,13 +4325,22 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
allRTypes = false;
// FIXME: double check this
- bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
- if (NoReturn != lbase->getNoReturnAttr())
+ // FIXME: should we error if lbase->getRegParmAttr() != 0 &&
+ // rbase->getRegParmAttr() != 0 &&
+ // lbase->getRegParmAttr() != rbase->getRegParmAttr()?
+ FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo();
+ FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
+ unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() :
+ lbaseInfo.getRegParm();
+ bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
+ if (NoReturn != lbaseInfo.getNoReturn() ||
+ RegParm != lbaseInfo.getRegParm())
allLTypes = false;
- if (NoReturn != rbase->getNoReturnAttr())
+ if (NoReturn != rbaseInfo.getNoReturn() ||
+ RegParm != rbaseInfo.getRegParm())
allRTypes = false;
- CallingConv lcc = lbase->getCallConv();
- CallingConv rcc = rbase->getCallConv();
+ CallingConv lcc = lbaseInfo.getCC();
+ CallingConv rcc = rbaseInfo.getCC();
// Compatible functions must have compatible calling conventions
if (!isSameCallConv(lcc, rcc))
return QualType();
@@ -4360,7 +4379,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- false, false, 0, 0, NoReturn, lcc);
+ false, false, 0, 0,
+ FunctionType::ExtInfo(NoReturn, RegParm, lcc));
}
if (lproto) allRTypes = false;
@@ -4393,13 +4413,15 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
proto->getNumArgs(), proto->isVariadic(),
- proto->getTypeQuals(),
- false, false, 0, 0, NoReturn, lcc);
+ proto->getTypeQuals(),
+ false, false, 0, 0,
+ FunctionType::ExtInfo(NoReturn, RegParm, lcc));
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- return getFunctionNoProtoType(retType, NoReturn, lcc);
+ FunctionType::ExtInfo Info(NoReturn, RegParm, lcc);
+ return getFunctionNoProtoType(retType, Info);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
@@ -4903,7 +4925,7 @@ QualType ASTContext::GetBuiltinType(unsigned id,
// FIXME: Should we create noreturn types?
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
TypeStr[0] == '.', 0, false, false, 0, 0,
- false, CC_Default);
+ FunctionType::ExtInfo());
}
QualType
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index dd2528a..75cf138 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -73,7 +73,7 @@ namespace {
// FIXME: SubstTemplateTypeParmType
// FIXME: TemplateSpecializationType
QualType VisitQualifiedNameType(QualifiedNameType *T);
- // FIXME: TypenameType
+ // FIXME: DependentNameType
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
@@ -484,10 +484,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Function1->getResultType(),
Function2->getResultType()))
return false;
- if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr())
- return false;
- if (Function1->getCallConv() != Function2->getCallConv())
- return false;
+ if (Function1->getExtInfo() != Function2->getExtInfo())
+ return false;
break;
}
@@ -620,9 +618,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
- case Type::Typename: {
- const TypenameType *Typename1 = cast<TypenameType>(T1);
- const TypenameType *Typename2 = cast<TypenameType>(T2);
+ case Type::DependentName: {
+ const DependentNameType *Typename1 = cast<DependentNameType>(T1);
+ const DependentNameType *Typename2 = cast<DependentNameType>(T2);
if (!IsStructurallyEquivalent(Context,
Typename1->getQualifier(),
Typename2->getQualifier()))
@@ -1200,10 +1198,9 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
QualType ToResultType = Importer.Import(T->getResultType());
if (ToResultType.isNull())
return QualType();
-
+
return Importer.getToContext().getFunctionNoProtoType(ToResultType,
- T->getNoReturnAttr(),
- T->getCallConv());
+ T->getExtInfo());
}
QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
@@ -1241,8 +1238,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
T->hasAnyExceptionSpec(),
ExceptionTypes.size(),
ExceptionTypes.data(),
- T->getNoReturnAttr(),
- T->getCallConv());
+ T->getExtInfo());
}
QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 3408a1e..91aaddc 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangAST
AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
+ DeclarationName.cpp
DeclBase.cpp
DeclCXX.cpp
DeclFriend.cpp
@@ -16,10 +17,9 @@ add_clang_library(clangAST
DeclObjC.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- DeclarationName.cpp
Expr.cpp
- ExprCXX.cpp
ExprConstant.cpp
+ ExprCXX.cpp
FullExpr.cpp
InheritViz.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 70f8ee4..a9f2230 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -416,3 +416,240 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
return false;
}
+
+void OverridingMethods::add(unsigned OverriddenSubobject,
+ UniqueVirtualMethod Overriding) {
+ llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ = Overrides[OverriddenSubobject];
+ if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
+ Overriding) == SubobjectOverrides.end())
+ SubobjectOverrides.push_back(Overriding);
+}
+
+void OverridingMethods::add(const OverridingMethods &Other) {
+ for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {
+ for (overriding_const_iterator M = I->second.begin(),
+ MEnd = I->second.end();
+ M != MEnd;
+ ++M)
+ add(I->first, *M);
+ }
+}
+
+void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {
+ for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {
+ I->second.clear();
+ I->second.push_back(Overriding);
+ }
+}
+
+
+namespace {
+ class FinalOverriderCollector {
+ /// \brief The number of subobjects of a given class type that
+ /// occur within the class hierarchy.
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
+
+ /// \brief Overriders for each virtual base subobject.
+ llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
+
+ CXXFinalOverriderMap FinalOverriders;
+
+ public:
+ ~FinalOverriderCollector();
+
+ void Collect(const CXXRecordDecl *RD, bool VirtualBase,
+ const CXXRecordDecl *InVirtualSubobject,
+ CXXFinalOverriderMap &Overriders);
+ };
+}
+
+void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
+ bool VirtualBase,
+ const CXXRecordDecl *InVirtualSubobject,
+ CXXFinalOverriderMap &Overriders) {
+ unsigned SubobjectNumber = 0;
+ if (!VirtualBase)
+ SubobjectNumber
+ = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
+
+ for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
+ BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
+ if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
+ const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (!BaseDecl->isPolymorphic())
+ continue;
+
+ if (Overriders.empty() && !Base->isVirtual()) {
+ // There are no other overriders of virtual member functions,
+ // so let the base class fill in our overriders for us.
+ Collect(BaseDecl, false, InVirtualSubobject, Overriders);
+ continue;
+ }
+
+ // Collect all of the overridders from the base class subobject
+ // and merge them into the set of overridders for this class.
+ // For virtual base classes, populate or use the cached virtual
+ // overrides so that we do not walk the virtual base class (and
+ // its base classes) more than once.
+ CXXFinalOverriderMap ComputedBaseOverriders;
+ CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
+ if (Base->isVirtual()) {
+ CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
+ if (!MyVirtualOverriders) {
+ MyVirtualOverriders = new CXXFinalOverriderMap;
+ Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);
+ }
+
+ BaseOverriders = MyVirtualOverriders;
+ } else
+ Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);
+
+ // Merge the overriders from this base class into our own set of
+ // overriders.
+ for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),
+ OMEnd = BaseOverriders->end();
+ OM != OMEnd;
+ ++OM) {
+ const CXXMethodDecl *CanonOM
+ = cast<CXXMethodDecl>(OM->first->getCanonicalDecl());
+ Overriders[CanonOM].add(OM->second);
+ }
+ }
+ }
+
+ for (CXXRecordDecl::method_iterator M = RD->method_begin(),
+ MEnd = RD->method_end();
+ M != MEnd;
+ ++M) {
+ // We only care about virtual methods.
+ if (!M->isVirtual())
+ continue;
+
+ CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl());
+
+ if (CanonM->begin_overridden_methods()
+ == CanonM->end_overridden_methods()) {
+ // This is a new virtual function that does not override any
+ // other virtual function. Add it to the map of virtual
+ // functions for which we are tracking overridders.
+
+ // C++ [class.virtual]p2:
+ // For convenience we say that any virtual function overrides itself.
+ Overriders[CanonM].add(SubobjectNumber,
+ UniqueVirtualMethod(CanonM, SubobjectNumber,
+ InVirtualSubobject));
+ continue;
+ }
+
+ // This virtual method overrides other virtual methods, so it does
+ // not add any new slots into the set of overriders. Instead, we
+ // replace entries in the set of overriders with the new
+ // overrider. To do so, we dig down to the original virtual
+ // functions using data recursion and update all of the methods it
+ // overrides.
+ typedef std::pair<CXXMethodDecl::method_iterator,
+ CXXMethodDecl::method_iterator> OverriddenMethods;
+ llvm::SmallVector<OverriddenMethods, 4> Stack;
+ Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(),
+ CanonM->end_overridden_methods()));
+ while (!Stack.empty()) {
+ OverriddenMethods OverMethods = Stack.back();
+ Stack.pop_back();
+
+ for (; OverMethods.first != OverMethods.second; ++OverMethods.first) {
+ const CXXMethodDecl *CanonOM
+ = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl());
+ if (CanonOM->begin_overridden_methods()
+ == CanonOM->end_overridden_methods()) {
+ // C++ [class.virtual]p2:
+ // A virtual member function C::vf of a class object S is
+ // a final overrider unless the most derived class (1.8)
+ // of which S is a base class subobject (if any) declares
+ // or inherits another member function that overrides vf.
+ //
+ // Treating this object like the most derived class, we
+ // replace any overrides from base classes with this
+ // overriding virtual function.
+ Overriders[CanonOM].replaceAll(
+ UniqueVirtualMethod(CanonM, SubobjectNumber,
+ InVirtualSubobject));
+ continue;
+ }
+
+ // Continue recursion to the methods that this virtual method
+ // overrides.
+ Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(),
+ CanonOM->end_overridden_methods()));
+ }
+ }
+ }
+}
+
+FinalOverriderCollector::~FinalOverriderCollector() {
+ for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
+ VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
+ VO != VOEnd;
+ ++VO)
+ delete VO->second;
+}
+
+void
+CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
+ FinalOverriderCollector Collector;
+ Collector.Collect(this, false, 0, FinalOverriders);
+
+ // Weed out any final overriders that come from virtual base class
+ // subobjects that were hidden by other subobjects along any path.
+ // This is the final-overrider variant of C++ [class.member.lookup]p10.
+ for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(),
+ OMEnd = FinalOverriders.end();
+ OM != OMEnd;
+ ++OM) {
+ for (OverridingMethods::iterator SO = OM->second.begin(),
+ SOEnd = OM->second.end();
+ SO != SOEnd;
+ ++SO) {
+ llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ if (Overriding.size() < 2)
+ continue;
+
+ for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ Pos = Overriding.begin(), PosEnd = Overriding.end();
+ Pos != PosEnd;
+ /* increment in loop */) {
+ if (!Pos->InVirtualSubobject) {
+ ++Pos;
+ continue;
+ }
+
+ // We have an overriding method in a virtual base class
+ // subobject (or non-virtual base class subobject thereof);
+ // determine whether there exists an other overriding method
+ // in a base class subobject that hides the virtual base class
+ // subobject.
+ bool Hidden = false;
+ for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator
+ OP = Overriding.begin(), OPEnd = Overriding.end();
+ OP != OPEnd && !Hidden;
+ ++OP) {
+ if (Pos == OP)
+ continue;
+
+ if (OP->Method->getParent()->isVirtuallyDerivedFrom(
+ const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject)))
+ Hidden = true;
+ }
+
+ if (Hidden) {
+ // The current overriding function is hidden by another
+ // overriding function; remove this one.
+ Pos = Overriding.erase(Pos);
+ PosEnd = Overriding.end();
+ } else {
+ ++Pos;
+ }
+ }
+ }
+ }
+}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6c9a45e..dc9fb59 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1413,10 +1413,8 @@ void TagDecl::startDefinition() {
CXXRecordDecl *D = cast<CXXRecordDecl>(this);
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
- do {
- D->DefinitionData = Data;
- D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration());
- } while (D);
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ cast<CXXRecordDecl>(*I)->DefinitionData = Data;
}
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 1aac7cf..c693e15 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
@@ -481,7 +482,7 @@ DeclContext::~DeclContext() {
// FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
// ~DeclContext() is not guaranteed to be called when ASTContext uses
// a BumpPtrAllocator.
- // delete static_cast<StoredDeclsMap*>(LookupPtr);
+ // delete LookupPtr;
}
void DeclContext::DestroyDecls(ASTContext &C) {
@@ -516,10 +517,16 @@ bool DeclContext::isDependentContext() const {
if (Record->getDescribedClassTemplate())
return true;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
if (Function->getDescribedFunctionTemplate())
return true;
+ // Friend function declarations are dependent if their *lexical*
+ // context is dependent.
+ if (cast<Decl>(this)->getFriendObjectKind())
+ return getLexicalParent()->isDependentContext();
+ }
+
return getParent() && getParent()->isDependentContext();
}
@@ -666,9 +673,7 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const {
// Load the declaration IDs for all of the names visible in this
// context.
assert(!LookupPtr && "Have a lookup map before de-serialization?");
- StoredDeclsMap *Map =
- (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap();
- LookupPtr = Map;
+ StoredDeclsMap *Map = CreateStoredDeclsMap(getParentASTContext());
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
}
@@ -727,10 +732,9 @@ void DeclContext::removeDecl(Decl *D) {
if (isa<NamedDecl>(D)) {
NamedDecl *ND = cast<NamedDecl>(D);
- void *OpaqueMap = getPrimaryContext()->LookupPtr;
- if (!OpaqueMap) return;
+ StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
+ if (!Map) return;
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap);
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
assert(Pos != Map->end() && "no lookup entry for decl");
Pos->second.remove(ND);
@@ -808,9 +812,8 @@ DeclContext::lookup(DeclarationName Name) {
return lookup_result(0, 0);
}
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr);
- StoredDeclsMap::iterator Pos = Map->find(Name);
- if (Pos == Map->end())
+ StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
+ if (Pos == LookupPtr->end())
return lookup_result(0, 0);
return Pos->second.getLookupResult(getParentASTContext());
}
@@ -878,12 +881,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
ASTContext *C = 0;
if (!LookupPtr) {
C = &getParentASTContext();
- LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap();
+ CreateStoredDeclsMap(*C);
}
// Insert this declaration into the map.
- StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr);
- StoredDeclsList &DeclNameEntries = Map[D->getDeclName()];
+ StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
@@ -952,13 +954,69 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) {
// Creation and Destruction of StoredDeclsMaps. //
//===----------------------------------------------------------------------===//
-void *ASTContext::CreateStoredDeclsMap() {
- StoredDeclsMap *M = new StoredDeclsMap();
- SDMs.push_back(M);
+StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
+ assert(!LookupPtr && "context already has a decls map");
+ assert(getPrimaryContext() == this &&
+ "creating decls map on non-primary context");
+
+ StoredDeclsMap *M;
+ bool Dependent = isDependentContext();
+ if (Dependent)
+ M = new DependentStoredDeclsMap();
+ else
+ M = new StoredDeclsMap();
+ M->Previous = C.LastSDM;
+ C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
+ LookupPtr = M;
return M;
}
void ASTContext::ReleaseDeclContextMaps() {
- for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I)
- delete (StoredDeclsMap*) *I;
+ // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap
+ // pointer because the subclass doesn't add anything that needs to
+ // be deleted.
+
+ StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt());
+}
+
+void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) {
+ while (Map) {
+ // Advance the iteration before we invalidate memory.
+ llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous;
+
+ if (Dependent)
+ delete static_cast<DependentStoredDeclsMap*>(Map);
+ else
+ delete Map;
+
+ Map = Next.getPointer();
+ Dependent = Next.getInt();
+ }
+}
+
+DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
+ DeclContext *Parent,
+ const PartialDiagnostic &PDiag) {
+ assert(Parent->isDependentContext()
+ && "cannot iterate dependent diagnostics of non-dependent context");
+ Parent = Parent->getPrimaryContext();
+ if (!Parent->LookupPtr)
+ Parent->CreateStoredDeclsMap(C);
+
+ DependentStoredDeclsMap *Map
+ = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr);
+
+ // Allocate the copy of the PartialDiagnostic via the ASTContext's
+ // BumpPtrAllocator, rather than the ASTContext itself.
+ PartialDiagnostic::Storage *DiagStorage = 0;
+ if (PDiag.hasStorage())
+ DiagStorage = new (C) PartialDiagnostic::Storage;
+
+ DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage);
+
+ // TODO: Maybe we shouldn't reverse the order during insertion.
+ DD->NextDiagnostic = Map->FirstDiagnostic;
+ Map->FirstDiagnostic = DD;
+
+ return DD;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 37f7479..94ed85c 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -83,9 +83,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (data().Bases)
C.Deallocate(data().Bases);
- int vbaseCount = 0;
- llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases;
- bool hasDirectVirtualBase = false;
+ // The set of seen virtual base types.
+ llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
+
+ // The virtual bases of this class.
+ llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases;
data().Bases = new(C) CXXBaseSpecifier [NumBases];
data().NumBases = NumBases;
@@ -99,58 +101,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
continue;
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- if (Base->isVirtual())
- hasDirectVirtualBase = true;
+
+ // Now go through all virtual bases of this base and add them.
for (CXXRecordDecl::base_class_iterator VBase =
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
- // Add this vbase to the array of vbases for current class if it is
- // not already in the list.
- // FIXME. Note that we do a linear search as number of such classes are
- // very few.
- int i;
- for (i = 0; i < vbaseCount; ++i)
- if (UniqueVbases[i]->getType() == VBase->getType())
- break;
- if (i == vbaseCount) {
- UniqueVbases.push_back(VBase);
- ++vbaseCount;
- }
+ // Add this base if it's not already in the list.
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ VBases.push_back(VBase);
}
- }
- if (hasDirectVirtualBase) {
- // Iterate one more time through the direct bases and add the virtual
- // base to the list of vritual bases for current class.
- for (unsigned i = 0; i < NumBases; ++i) {
- const CXXBaseSpecifier *VBase = Bases[i];
- if (!VBase->isVirtual())
- continue;
- int j;
- for (j = 0; j < vbaseCount; ++j)
- if (UniqueVbases[j]->getType() == VBase->getType())
- break;
- if (j == vbaseCount) {
- UniqueVbases.push_back(VBase);
- ++vbaseCount;
- }
+
+ if (Base->isVirtual()) {
+ // Add this base if it's not already in the list.
+ if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
+ VBases.push_back(Base);
}
+
}
- if (vbaseCount > 0) {
- // build AST for inhireted, direct or indirect, virtual bases.
- data().VBases = new (C) CXXBaseSpecifier [vbaseCount];
- data().NumVBases = vbaseCount;
- for (int i = 0; i < vbaseCount; i++) {
- QualType QT = UniqueVbases[i]->getType();
- // Skip dependent types; we can't do any checking on them now.
- if (QT->isDependentType())
- continue;
- CXXRecordDecl *VBaseClassDecl
- = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl());
- data().VBases[i] =
- CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
- VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
- UniqueVbases[i]->getAccessSpecifier(), QT);
- }
+
+ if (VBases.empty())
+ return;
+
+ // Create base specifier for any direct or indirect virtual bases.
+ data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
+ data().NumVBases = VBases.size();
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType VBaseType = VBases[I]->getType();
+
+ // Skip dependent types; we can't do any checking on them now.
+ if (VBaseType->isDependentType())
+ continue;
+
+ CXXRecordDecl *VBaseClassDecl
+ = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+
+ data().VBases[I] =
+ CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
+ VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
+ VBases[I]->getAccessSpecifier(), VBaseType);
}
}
@@ -320,6 +308,8 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
+ if (isa<UsingShadowDecl>(Conv))
+ Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
T = ConvTemp->getTemplatedDecl()->getResultType();
else
@@ -457,26 +447,45 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
return &data().VisibleConversions;
}
-void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
- assert(!ConvDecl->getDescribedFunctionTemplate() &&
- "Conversion function templates should cast to FunctionTemplateDecl.");
+#ifndef NDEBUG
+void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
assert(ConvDecl->getDeclContext() == this &&
"conversion function does not belong to this record");
- // We intentionally don't use the decl's access here because it
- // hasn't been set yet. That's really just a misdesign in Sema.
- data().Conversions.addDecl(ConvDecl);
+ ConvDecl = ConvDecl->getUnderlyingDecl();
+ if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
+ assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
+ } else {
+ assert(isa<CXXConversionDecl>(ConvDecl));
+ }
}
+#endif
+
+void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
+ // This operation is O(N) but extremely rare. Sema only uses it to
+ // remove UsingShadowDecls in a class that were followed by a direct
+ // declaration, e.g.:
+ // class A : B {
+ // using B::operator int;
+ // operator int();
+ // };
+ // This is uncommon by itself and even more uncommon in conjunction
+ // with sufficiently large numbers of directly-declared conversions
+ // that asymptotic behavior matters.
+
+ UnresolvedSetImpl &Convs = *getConversionFunctions();
+ for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
+ if (Convs[I].getDecl() == ConvDecl) {
+ Convs.erase(I);
+ assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end()
+ && "conversion was found multiple times in unresolved set");
+ return;
+ }
+ }
-void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
- assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
- "Function template is not a conversion function template");
- assert(ConvDecl->getDeclContext() == this &&
- "conversion function does not belong to this record");
- data().Conversions.addDecl(ConvDecl);
+ llvm_unreachable("conversion not found in set!");
}
-
void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
Method->setVirtualAsWritten(true);
setAggregate(false);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6a71e92..6764612 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -492,44 +492,45 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
-MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
- SourceRange qualrange, ValueDecl *memberdecl,
- SourceLocation l, const TemplateArgumentListInfo *targs,
- QualType ty)
- : Expr(MemberExprClass, ty,
- base->isTypeDependent() || (qual && qual->isDependent()),
- base->isValueDependent() || (qual && qual->isDependent())),
- Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) {
- // Initialize the qualifier, if any.
- if (HasQualifier) {
- NameQualifier *NQ = getMemberQualifier();
- NQ->NNS = qual;
- NQ->Range = qualrange;
- }
-
- // Initialize the explicit template argument list, if any.
- if (targs)
- getExplicitTemplateArgumentList()->initializeFrom(*targs);
-}
-
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
ValueDecl *memberdecl,
+ NamedDecl *founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
- if (qual != 0)
- Size += sizeof(NameQualifier);
+
+ bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
+ if (hasQualOrFound)
+ Size += sizeof(MemberNameQualifier);
if (targs)
Size += ExplicitTemplateArgumentList::sizeFor(*targs);
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
- return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
- targs, ty);
+ MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty);
+
+ if (hasQualOrFound) {
+ if (qual && qual->isDependent()) {
+ E->setValueDependent(true);
+ E->setTypeDependent(true);
+ }
+ E->HasQualifierOrFoundDecl = true;
+
+ MemberNameQualifier *NQ = E->getMemberQualifier();
+ NQ->NNS = qual;
+ NQ->Range = qualrange;
+ NQ->FoundDecl = founddecl;
+ }
+
+ if (targs) {
+ E->HasExplicitTemplateArgumentList = true;
+ E->getExplicitTemplateArgumentList()->initializeFrom(*targs);
+ }
+
+ return E;
}
const char *CastExpr::getCastKindName() const {
@@ -544,6 +545,8 @@ const char *CastExpr::getCastKindName() const {
return "BaseToDerived";
case CastExpr::CK_DerivedToBase:
return "DerivedToBase";
+ case CastExpr::CK_UncheckedDerivedToBase:
+ return "UncheckedDerivedToBase";
case CastExpr::CK_Dynamic:
return "Dynamic";
case CastExpr::CK_ToUnion:
@@ -914,8 +917,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case CXXConstructExprClass:
return false;
- case ObjCMessageExprClass:
+ case ObjCMessageExprClass: {
+ const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
+ Loc = getExprLoc();
+ return true;
+ }
return false;
+ }
case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send.
#if 0
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 8a64f8e..27a277d 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -750,7 +750,7 @@ bool Type::isSpecifierType() const {
case SubstTemplateTypeParm:
case TemplateSpecialization:
case QualifiedName:
- case Typename:
+ case DependentName:
case ObjCInterface:
case ObjCObjectPointer:
case Elaborated:
@@ -760,6 +760,27 @@ bool Type::isSpecifierType() const {
}
}
+bool Type::isElaboratedTypeSpecifier() const {
+ if (getTypeClass() == Elaborated)
+ return true;
+
+ if (const DependentNameType *Dependent = dyn_cast<DependentNameType>(this)) {
+ switch (Dependent->getKeyword()) {
+ case ETK_None:
+ case ETK_Typename:
+ return false;
+
+ case ETK_Class:
+ case ETK_Struct:
+ case ETK_Union:
+ case ETK_Enum:
+ return true;
+ }
+ }
+
+ return false;
+}
+
const char *Type::getTypeClassName() const {
switch (TC) {
default: assert(0 && "Type class not in TypeNodes.def!");
@@ -820,8 +841,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs, bool NoReturn,
- CallingConv CallConv) {
+ exception_iterator Exs,
+ const FunctionType::ExtInfo &Info) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -833,15 +854,16 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
for (unsigned i = 0; i != NumExceptions; ++i)
ID.AddPointer(Exs[i].getAsOpaquePtr());
}
- ID.AddInteger(NoReturn);
- ID.AddInteger(CallConv);
+ ID.AddInteger(Info.getNoReturn());
+ ID.AddInteger(Info.getRegParm());
+ ID.AddInteger(Info.getCC());
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin(), getNoReturnAttr(),
- getCallConv());
+ getNumExceptions(), exception_begin(),
+ getExtInfo());
}
void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID,
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0c4896d..4cf0922 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -282,7 +282,8 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ")";
- switch(T->getCallConv()) {
+ FunctionType::ExtInfo Info = T->getExtInfo();
+ switch(Info.getCC()) {
case CC_Default:
default: break;
case CC_C:
@@ -295,9 +296,11 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += " __attribute__((fastcall))";
break;
}
- if (T->getNoReturnAttr())
+ if (Info.getNoReturn())
S += " __attribute__((noreturn))";
-
+ if (Info.getRegParm())
+ S += " __attribute__((regparm (" +
+ llvm::utostr_32(Info.getRegParm()) + ")))";
if (T->hasExceptionSpec()) {
S += " throw(";
@@ -564,12 +567,20 @@ void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
S = MyString + ' ' + S;
}
-void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) {
+void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) {
std::string MyString;
{
llvm::raw_string_ostream OS(MyString);
- OS << "typename ";
+ switch (T->getKeyword()) {
+ case ETK_None: break;
+ case ETK_Typename: OS << "typename "; break;
+ case ETK_Class: OS << "class "; break;
+ case ETK_Struct: OS << "struct "; break;
+ case ETK_Union: OS << "union "; break;
+ case ETK_Enum: OS << "enum "; break;
+ }
+
T->getQualifier()->print(OS, Policy);
if (const IdentifierInfo *Ident = T->getIdentifier())
@@ -819,4 +830,3 @@ void QualType::getAsStringInternal(std::string &S,
TypePrinter Printer(Policy);
Printer.Print(*this, S);
}
-
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 5640c4a..06d8aec 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -54,8 +54,12 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
}
CFG *AnalysisContext::getCFG() {
- if (!cfg)
+ if (!builtCFG) {
cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
+ // Even when the cfg is not successfully built, we don't
+ // want to try building it again.
+ builtCFG = true;
+ }
return cfg;
}
@@ -126,9 +130,9 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx,
llvm::FoldingSetNodeID ID;
LOC::Profile(ID, ctx, parent, d);
void *InsertPos;
-
+
LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
-
+
if (!L) {
L = new LOC(ctx, parent, d);
Contexts.InsertNode(L, InsertPos);
@@ -144,7 +148,7 @@ LocationContextManager::getStackFrame(AnalysisContext *ctx,
llvm::FoldingSetNodeID ID;
StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
void *InsertPos;
- StackFrameContext *L =
+ StackFrameContext *L =
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
if (!L) {
L = new StackFrameContext(ctx, parent, s, blk, idx);
@@ -253,7 +257,7 @@ public:
IgnoredContexts.insert(BR->getBlockDecl());
Visit(BR->getBlockDecl()->getBody());
}
-};
+};
} // end anonymous namespace
typedef BumpVector<const VarDecl*> DeclVec;
@@ -263,16 +267,16 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
llvm::BumpPtrAllocator &A) {
if (Vec)
return (DeclVec*) Vec;
-
+
BumpVectorContext BC(A);
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
new (BV) DeclVec(BC, 10);
-
+
// Find the referenced variables.
FindBlockDeclRefExprsVals F(*BV, BC);
F.Visit(BD->getBody());
-
- Vec = BV;
+
+ Vec = BV;
return BV;
}
@@ -281,7 +285,7 @@ std::pair<AnalysisContext::referenced_decls_iterator,
AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
if (!ReferencedBlockVars)
ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
-
+
DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
return std::make_pair(V->begin(), V->end());
}
@@ -310,12 +314,12 @@ LocationContextManager::~LocationContextManager() {
void LocationContextManager::clear() {
for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
- E = Contexts.end(); I != E; ) {
+ E = Contexts.end(); I != E; ) {
LocationContext *LC = &*I;
++I;
delete LC;
}
-
+
Contexts.clear();
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index a4a021f..f94f6b3 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -571,7 +571,7 @@ static bool CanThrow(Expr *E) {
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
// If this is a call to a no-return function, this stops the block here.
bool NoReturn = false;
- if (C->getCallee()->getType().getNoReturnAttr()) {
+ if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) {
NoReturn = true;
}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 46acc8a..c38aae3 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -75,7 +75,7 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
char c = *I;
if (c >= '0' && c <= '9') {
hasDigits = true;
- accumulator += (accumulator * 10) + (c - '0');
+ accumulator = (accumulator * 10) + (c - '0');
continue;
}
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index f7ec873..2b7fcd0 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Parse/ParseDiagnostic.h"
@@ -124,10 +125,20 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) {
return 0;
}
-bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) {
- if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->SFINAE && Info->Class == CLASS_ERROR;
- return false;
+Diagnostic::SFINAEResponse
+Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) {
+ if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) {
+ if (!Info->SFINAE)
+ return SFINAE_Report;
+
+ if (Info->Class == CLASS_ERROR)
+ return SFINAE_SubstitutionFailure;
+
+ // Suppress notes, warnings, and extensions;
+ return SFINAE_Suppress;
+ }
+
+ return SFINAE_Report;
}
/// getDiagClass - Return the class field of the diagnostic.
@@ -222,6 +233,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
+ DelayedDiagID = 0;
+
// Set all mappings to 'unset'.
DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0);
DiagMappingsStack.push_back(BlankDiags);
@@ -289,6 +302,23 @@ const char *Diagnostic::getDescription(unsigned DiagID) const {
return CustomDiagInfo->getDescription(DiagID);
}
+void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1,
+ llvm::StringRef Arg2) {
+ if (DelayedDiagID)
+ return;
+
+ DelayedDiagID = DiagID;
+ DelayedDiagArg1 = Arg1.str();
+ DelayedDiagArg2 = Arg2.str();
+}
+
+void Diagnostic::ReportDelayed() {
+ Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
+ DelayedDiagID = 0;
+ DelayedDiagArg1.clear();
+ DelayedDiagArg2.clear();
+}
+
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
@@ -532,6 +562,35 @@ bool Diagnostic::ProcessDiag() {
return true;
}
+bool DiagnosticBuilder::Emit() {
+ // If DiagObj is null, then its soul was stolen by the copy ctor
+ // or the user called Emit().
+ if (DiagObj == 0) return false;
+
+ // When emitting diagnostics, we set the final argument count into
+ // the Diagnostic object.
+ DiagObj->NumDiagArgs = NumArgs;
+ DiagObj->NumDiagRanges = NumRanges;
+ DiagObj->NumFixItHints = NumFixItHints;
+
+ // Process the diagnostic, sending the accumulated information to the
+ // DiagnosticClient.
+ bool Emitted = DiagObj->ProcessDiag();
+
+ // Clear out the current diagnostic object.
+ unsigned DiagID = DiagObj->CurDiagID;
+ DiagObj->Clear();
+
+ // If there was a delayed diagnostic, emit it now.
+ if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID)
+ DiagObj->ReportDelayed();
+
+ // This diagnostic is dead.
+ DiagObj = 0;
+
+ return Emitted;
+}
+
DiagnosticClient::~DiagnosticClient() {}
@@ -937,9 +996,9 @@ StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level,
for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I)
Ranges.push_back(Info.getRange(I));
- FixIts.reserve(Info.getNumCodeModificationHints());
- for (unsigned I = 0, N = Info.getNumCodeModificationHints(); I != N; ++I)
- FixIts.push_back(Info.getCodeModificationHint(I));
+ FixIts.reserve(Info.getNumFixItHints());
+ for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I)
+ FixIts.push_back(Info.getFixItHint(I));
}
StoredDiagnostic::~StoredDiagnostic() { }
@@ -1172,7 +1231,7 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
return Diag;
}
- CodeModificationHint Hint;
+ FixItHint Hint;
Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
Hint.InsertionLoc = InsertionLoc;
Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
@@ -1188,3 +1247,13 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM,
/// DiagnosticClient should be included in the number of diagnostics
/// reported by Diagnostic.
bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; }
+
+PartialDiagnostic::StorageAllocator::StorageAllocator() {
+ for (unsigned I = 0; I != NumCached; ++I)
+ FreeList[I] = Cached + I;
+ NumFreeListEntries = NumCached;
+}
+
+PartialDiagnostic::StorageAllocator::~StorageAllocator() {
+ assert(NumFreeListEntries == NumCached && "A partial is on the lamb");
+}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 6def967..27cb9be 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -89,16 +89,26 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart());
for (unsigned i = 0, e = Entry->getSize(); i != e; ++i)
Ptr[i] = FillStr[i % FillStr.size()];
- Diag.Report(diag::err_cannot_open_file)
- << Entry->getName() << ErrorStr;
+
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_cannot_open_file,
+ Entry->getName(), ErrorStr);
+ else
+ Diag.Report(diag::err_cannot_open_file)
+ << Entry->getName() << ErrorStr;
+
Buffer.setInt(true);
} else if (FileInfo.st_size != Entry->getSize() ||
- FileInfo.st_mtime != Entry->getModificationTime() ||
- FileInfo.st_ino != Entry->getInode()) {
+ FileInfo.st_mtime != Entry->getModificationTime()) {
// Check that the file's size, modification time, and inode are
// the same as in the file entry (which may have come from a
// stat cache).
- Diag.Report(diag::err_file_modified) << Entry->getName();
+ if (Diag.isDiagnosticInFlight())
+ Diag.SetDelayedDiagnostic(diag::err_file_modified,
+ Entry->getName());
+ else
+ Diag.Report(diag::err_file_modified) << Entry->getName();
+
Buffer.setInt(true);
}
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 8f472b3..e3d9ed3 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -292,6 +292,7 @@ protected:
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
MacroBuilder &Builder) const {
// PS3 PPU defines.
+ Builder.defineMacro("__PPC__");
Builder.defineMacro("__PPU__");
Builder.defineMacro("__CELLOS_LV2__");
Builder.defineMacro("__ELF__");
diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp
index e95a86b..b92f2e7 100644
--- a/lib/Checker/AdjustedReturnValueChecker.cpp
+++ b/lib/Checker/AdjustedReturnValueChecker.cpp
@@ -14,11 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
using namespace clang;
diff --git a/lib/Checker/AggExprVisitor.cpp b/lib/Checker/AggExprVisitor.cpp
new file mode 100644
index 0000000..343afec
--- /dev/null
+++ b/lib/Checker/AggExprVisitor.cpp
@@ -0,0 +1,55 @@
+//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AggExprVisitor class, which contains lots of boiler
+// plate code for evaluating expressions of C++ class type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+
+namespace {
+class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
+ SVal DestPtr;
+ ExplodedNode *Pred;
+ ExplodedNodeSet &DstSet;
+ GRExprEngine &Eng;
+
+public:
+ AggExprVisitor(SVal dest, ExplodedNode *N, ExplodedNodeSet &dst,
+ GRExprEngine &eng)
+ : DestPtr(dest), Pred(N), DstSet(dst), Eng(eng) {}
+
+ void VisitCastExpr(CastExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
+};
+}
+
+void AggExprVisitor::VisitCastExpr(CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ assert(0 && "Unhandled cast kind");
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_ConstructorConversion:
+ Visit(E->getSubExpr());
+ break;
+ }
+}
+
+void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ Eng.VisitCXXConstructExpr(E, DestPtr, Pred, DstSet);
+}
+
+void GRExprEngine::VisitAggExpr(const Expr *E, SVal Dest, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
+}
diff --git a/lib/Checker/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp
index 74fb06f..746b3f9 100644
--- a/lib/Checker/ArrayBoundChecker.cpp
+++ b/lib/Checker/ArrayBoundChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/AttrNonNullChecker.cpp b/lib/Checker/AttrNonNullChecker.cpp
index 83dc13e..309a74c 100644
--- a/lib/Checker/AttrNonNullChecker.cpp
+++ b/lib/Checker/AttrNonNullChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index d6c09a2..810d0fb 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -19,9 +19,8 @@
#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 7272b34..12e61af 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
@@ -1139,12 +1140,9 @@ void EdgeBuilder::addContext(const Stmt *S) {
static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N) {
-
-
EdgeBuilder EB(PD, PDB);
- const ExplodedNode* NextNode = N->pred_empty()
- ? NULL : *(N->pred_begin());
+ const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
NextNode = GetPredecessorNode(N);
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 1d6994b..06cee5b 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
#include "clang/Checker/PathSensitive/GRState.h"
using namespace clang;
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 9a76f6a..3c4a27c 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -16,8 +16,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/Checker/BugReporter/PathDiagnostic.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/DomainSpecific/CocoaConventions.h"
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index c5bd2eb..dec375e 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangChecker
AdjustedReturnValueChecker.cpp
+ AggExprVisitor.cpp
ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
BasicConstraintManager.cpp
@@ -11,16 +12,16 @@ add_clang_library(clangChecker
BugReporter.cpp
BugReporterVisitors.cpp
BuiltinFunctionChecker.cpp
- CFRefCount.cpp
CallAndMessageChecker.cpp
CallInliner.cpp
CastToStructChecker.cpp
+ CFRefCount.cpp
CheckDeadStores.cpp
+ Checker.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
- Checker.cpp
CocoaConventions.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
@@ -38,11 +39,11 @@ add_clang_library(clangChecker
MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
+ NoReturnFunctionChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
- NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
ObjCUnusedIVarsChecker.cpp
+ OSAtomicChecker.cpp
PathDiagnostic.cpp
PointerArithChecker.cpp
PointerSubChecker.cpp
@@ -52,18 +53,18 @@ add_clang_library(clangChecker
ReturnPointerRangeChecker.cpp
ReturnStackAddressChecker.cpp
ReturnUndefChecker.cpp
- SVals.cpp
- SValuator.cpp
SimpleConstraintManager.cpp
SimpleSValuator.cpp
Store.cpp
+ SVals.cpp
+ SValuator.cpp
SymbolManager.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
- UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
+ UndefResultChecker.cpp
UnixAPIChecker.cpp
- VLASizeChecker.cpp
ValueManager.cpp
+ VLASizeChecker.cpp
)
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index 32cf753..dd1856c9 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/AST/ParentMap.h"
-#include "GRExprEngineInternalChecks.h"
using namespace clang;
diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index bef5bc2..2c16f89 100644
--- a/lib/Checker/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index 923baf5..efbce61 100644
--- a/lib/Checker/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -36,7 +36,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
IdentifierInfo *II_random;
enum { num_setids = 6 };
IdentifierInfo *II_setid[num_setids];
-
+
const bool CheckRand;
public:
@@ -214,8 +214,8 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
llvm::SmallVector<SourceRange, 2> ranges;
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
os << "Variable '" << drCond->getDecl()->getNameAsCString()
<< "' with floating point type '" << drCond->getType().getAsString()
@@ -315,7 +315,7 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
if(!FPT)
return;
-
+
// Verify that the funcion takes a single argument.
if (FPT->getNumArgs() != 1)
return;
@@ -328,17 +328,16 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
// Verify that the argument is a 'char*'.
if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
return;
-
+
// Issue a waring.
SourceRange R = CE->getCallee()->getSourceRange();
BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
"Security",
"Call to function 'mktemp' is insecure as it always "
- "creates or uses insecure temporary file",
+ "creates or uses insecure temporary file. Use 'mkstemp' instead",
CE->getLocStart(), &R, 1);
}
-
//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
@@ -386,20 +385,18 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Issue a warning.
- std::string buf1;
- llvm::raw_string_ostream os1(buf1);
+ llvm::SmallString<256> buf1;
+ llvm::raw_svector_ostream os1(buf1);
os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
- std::string buf2;
- llvm::raw_string_ostream os2(buf2);
+ llvm::SmallString<256> buf2;
+ llvm::raw_svector_ostream os2(buf2);
os2 << "Function '" << FD->getNameAsString()
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
SourceRange R = CE->getCallee()->getSourceRange();
-
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),
- CE->getLocStart(), &R, 1);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -425,8 +422,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
"Security",
"The 'random' function produces a sequence of values that "
"an adversary may be able to predict. Use 'arc4random' "
- "instead",
- CE->getLocStart(), &R, 1);
+ "instead", CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
@@ -474,22 +470,20 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
return;
// Issue a warning.
- std::string buf1;
- llvm::raw_string_ostream os1(buf1);
+ llvm::SmallString<256> buf1;
+ llvm::raw_svector_ostream os1(buf1);
os1 << "Return value is not checked in call to '" << FD->getNameAsString()
<< "'";
- std::string buf2;
- llvm::raw_string_ostream os2(buf2);
+ llvm::SmallString<256> buf2;
+ llvm::raw_svector_ostream os2(buf2);
os2 << "The return value from the call to '" << FD->getNameAsString()
<< "' is not checked. If an error occurs in '"
<< FD->getNameAsString()
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
-
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),
- CE->getLocStart(), &R, 1);
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp
index 0cbc408..af74c79 100644
--- a/lib/Checker/DereferenceChecker.cpp
+++ b/lib/Checker/DereferenceChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "clang/Checker/PathSensitive/Checker.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
using namespace clang;
@@ -29,9 +29,9 @@ public:
DereferenceChecker() : BT_null(0), BT_undef(0) {}
static void *getTag() { static int tag = 0; return &tag; }
void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
-
+
std::pair<ExplodedNode * const*, ExplodedNode * const*>
- getImplicitNodes() const {
+ getImplicitNodes() const {
return std::make_pair(ImplicitNullDerefNodes.data(),
ImplicitNullDerefNodes.data() +
ImplicitNullDerefNodes.size());
@@ -59,7 +59,7 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_undef)
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
-
+
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
@@ -68,31 +68,32 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
}
return;
}
-
+
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
-
- // Check for null dereferences.
+
+ // Check for null dereferences.
if (!isa<Loc>(location))
return;
-
+
const GRState *state = C.getState();
const GRState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->Assume(location);
-
+
// The explicit NULL case.
if (nullState) {
- if (!notNullState) {
+ if (!notNullState) {
// Generate an error node.
ExplodedNode *N = C.GenerateSink(nullState);
if (!N)
return;
-
+
// We know that 'location' cannot be non-null. This is what
- // we call an "explicit" null dereference.
+ // we call an "explicit" null dereference.
if (!BT_null)
BT_null = new BuiltinBug("Dereference of null pointer");
-
+
llvm::SmallString<100> buf;
+ llvm::SmallVector<SourceRange, 2> Ranges;
switch (S->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
@@ -101,10 +102,26 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
llvm::raw_svector_ostream os(buf);
- os << "Dereference of null pointer loaded from variable '"
- << VD->getName() << '\'';
+ os << "Dereference of null pointer (loaded from variable '"
+ << VD->getName() << "')";
+ Ranges.push_back(DR->getSourceRange());
}
}
+ break;
+ }
+ case Stmt::MemberExprClass: {
+ const MemberExpr *M = cast<MemberExpr>(S);
+ if (M->isArrow())
+ if (DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ llvm::raw_svector_ostream os(buf);
+ os << "Field access results in a dereference of a null pointer "
+ "(loaded from variable '" << VD->getName() << "')";
+ Ranges.push_back(M->getBase()->getSourceRange());
+ }
+ }
+ break;
}
default:
break;
@@ -117,19 +134,23 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
-
+
+ for (llvm::SmallVectorImpl<SourceRange>::iterator
+ I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
+ report->addRange(*I);
+
C.EmitReport(report);
return;
}
else {
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
- // dereference.
+ // dereference.
if (ExplodedNode *N = C.GenerateSink(nullState))
ImplicitNullDerefNodes.push_back(N);
}
}
-
+
// From this point forward, we know that the location is not null.
C.addTransition(notNullState);
}
diff --git a/lib/Checker/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp
index e1346e1..e09a871 100644
--- a/lib/Checker/DivZeroChecker.cpp
+++ b/lib/Checker/DivZeroChecker.cpp
@@ -12,8 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp
index 671cf89..cc71f85 100644
--- a/lib/Checker/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -10,9 +10,10 @@
// This file defined the Environment and EnvironmentManager classes.
//
//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
diff --git a/lib/Checker/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp
index 04c17d6..4fce45b 100644
--- a/lib/Checker/FixedAddressChecker.cpp
+++ b/lib/Checker/FixedAddressChecker.cpp
@@ -13,8 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/GRBlockCounter.cpp b/lib/Checker/GRBlockCounter.cpp
index 3fa3e1e..cd26060 100644
--- a/lib/Checker/GRBlockCounter.cpp
+++ b/lib/Checker/GRBlockCounter.cpp
@@ -18,7 +18,34 @@
using namespace clang;
-typedef llvm::ImmutableMap<unsigned,unsigned> CountMap;
+namespace {
+
+class CountKey {
+ const StackFrameContext *CallSite;
+ unsigned BlockID;
+
+public:
+ CountKey(const StackFrameContext *CS, unsigned ID)
+ : CallSite(CS), BlockID(ID) {}
+
+ bool operator==(const CountKey &RHS) const {
+ return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
+ }
+
+ bool operator<(const CountKey &RHS) const {
+ return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID)
+ : (CallSite < RHS.CallSite);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(CallSite);
+ ID.AddInteger(BlockID);
+ }
+};
+
+}
+
+typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
static inline CountMap GetMap(void* D) {
return CountMap(static_cast<CountMap::TreeTy*>(D));
@@ -28,9 +55,10 @@ static inline CountMap::Factory& GetFactory(void* F) {
return *static_cast<CountMap::Factory*>(F);
}
-unsigned GRBlockCounter::getNumVisited(unsigned BlockID) const {
+unsigned GRBlockCounter::getNumVisited(const StackFrameContext *CallSite,
+ unsigned BlockID) const {
CountMap M = GetMap(Data);
- CountMap::data_type* T = M.lookup(BlockID);
+ CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
return T ? *T : 0;
}
@@ -43,9 +71,12 @@ GRBlockCounter::Factory::~Factory() {
}
GRBlockCounter
-GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC, unsigned BlockID) {
- return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data), BlockID,
- BC.getNumVisited(BlockID)+1).getRoot());
+GRBlockCounter::Factory::IncrementCount(GRBlockCounter BC,
+ const StackFrameContext *CallSite,
+ unsigned BlockID) {
+ return GRBlockCounter(GetFactory(F).Add(GetMap(BC.Data),
+ CountKey(CallSite, BlockID),
+ BC.getNumVisited(CallSite, BlockID)+1).getRoot());
}
GRBlockCounter
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index a9347d0..e4ef6b0 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -126,9 +126,9 @@ void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) {
SubEngine.ProcessStmt(E, Builder);
}
-bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred,
GRBlockCounter BC) {
- return SubEngine.ProcessBlockEntrance(Blk, State, BC);
+ return SubEngine.ProcessBlockEntrance(Blk, Pred, BC);
}
void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator,
@@ -256,7 +256,7 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
// FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
- if (ProcessBlockEntrance(Blk, Pred->State, WList->getBlockCounter()))
+ if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter()))
GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred);
}
@@ -265,7 +265,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L,
// Increment the block counter.
GRBlockCounter Counter = WList->getBlockCounter();
- Counter = BCounterFactory.IncrementCount(Counter, L.getBlock()->getBlockID());
+ Counter = BCounterFactory.IncrementCount(Counter,
+ Pred->getLocationContext()->getCurrentStackFrame(),
+ L.getBlock()->getBlockID());
WList->setBlockCounter(Counter);
// Process the entrance of the block.
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 3ace552..bab8922 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -13,6 +13,8 @@
//
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Checker/PathSensitive/Checker.h"
@@ -582,7 +584,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
switch (S->getStmtClass()) {
// C++ stuff we don't support yet.
- case Stmt::CXXMemberCallExprClass:
case Stmt::CXXNamedCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass:
@@ -671,6 +672,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXMemberCallExprClass: {
+ CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
+ VisitCXXMemberCallExpr(MCE, Pred, Dst);
+ break;
+ }
+
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
@@ -895,6 +902,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
}
+ case Stmt::ObjCIsaExprClass:
+ // FIXME: Do something more intelligent with 'x->isa = ...'.
+ // For now, just ignore the assignment.
+ return;
+
case Stmt::ObjCPropertyRefExprClass:
case Stmt::ObjCImplicitSetterGetterRefExprClass:
// FIXME: Property assignments are lvalues, but not really "locations".
@@ -944,10 +956,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
// Block entrance. (Update counters).
//===----------------------------------------------------------------------===//
-bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const GRState*,
+bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred,
GRBlockCounter BC) {
- return BC.getNumVisited(B->getBlockID()) < 3;
+ return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
+ B->getBlockID()) < 3;
}
//===----------------------------------------------------------------------===//
@@ -1328,6 +1341,22 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
if (ReturnedExpr) {
SVal RetVal = state->getSVal(ReturnedExpr);
state = state->BindExpr(CE, RetVal);
+ // Clear the return expr GDM.
+ state = state->remove<ReturnExpr>();
+ }
+
+ // Bind the constructed object value to CXXConstructExpr.
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
+ const CXXThisRegion *ThisR = getCXXThisRegion(CCE->getConstructor(),LocCtx);
+ // We might not have 'this' region in the binding if we didn't inline
+ // the ctor call.
+ SVal ThisV = state->getSVal(ThisR);
+ loc::MemRegionVal *V = dyn_cast<loc::MemRegionVal>(&ThisV);
+ if (V) {
+ SVal ObjVal = state->getSVal(V->getRegion());
+ assert(isa<nonloc::LazyCompoundVal>(ObjVal));
+ state = state->BindExpr(CCE, ObjVal);
+ }
}
B.GenerateNode(state);
@@ -2282,6 +2311,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
case CastExpr::CK_AnyPointerToObjCPointerCast:
case CastExpr::CK_AnyPointerToBlockPointerCast:
case CastExpr::CK_DerivedToBase:
+ case CastExpr::CK_UncheckedDerivedToBase:
// Delegate to SValuator to process.
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
ExplodedNode* N = *I;
@@ -2338,8 +2368,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet Tmp;
if (InitEx) {
- if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) {
- VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD,
+ QualType InitTy = InitEx->getType();
+ if (getContext().getLangOptions().CPlusPlus && InitTy->isRecordType()) {
+ // Delegate expressions of C++ record type evaluation to AggExprVisitor.
+ VisitAggExpr(InitEx, GetState(Pred)->getLValue(VD,
Pred->getLocationContext()), Pred, Dst);
return;
} else if (VD->getType()->isReferenceType())
@@ -2908,7 +2940,8 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
ExplodedNodeSet Src;
if (Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state.
+ // Record the returned expression in the state. It will be used in
+ // ProcessCallExit to bind the return value to the call expr.
{
static int Tag = 0;
SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
@@ -3137,6 +3170,10 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ if (E->isElidable()) {
+ VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
+ return;
+ }
const CXXConstructorDecl *CD = E->getConstructor();
assert(CD);
@@ -3190,10 +3227,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
Pred->getLocationContext(),
E, Builder->getBlock(), Builder->getIndex());
- Type *T = CD->getParent()->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T,0));
- const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT,
- SFC);
+ const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
CallEnter Loc(E, CD, Pred->getLocationContext());
for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
@@ -3206,6 +3240,91 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
Dst.Add(N);
}
}
+
+void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the method type.
+ const FunctionProtoType *FnType =
+ MCE->getCallee()->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Method type not available");
+
+ // Evaluate explicit arguments with a worklist.
+ CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
+ AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AB);
+ WorkList.push_back(CallExprWLItem(AB, Pred));
+ ExplodedNodeSet ArgsEvaluated;
+
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ ArgsEvaluated.insert(Item.N);
+ continue;
+ }
+
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AB;
+ bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
+
+ if (VisitAsLvalue)
+ VisitLValue(*Item.I, Item.N, Tmp);
+ else
+ Visit(*Item.I, Item.N, Tmp);
+
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
+ }
+ // Evaluate the implicit object argument.
+ ExplodedNodeSet AllArgsEvaluated;
+ const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
+ if (!ME)
+ return;
+ Expr *ObjArgExpr = ME->getBase();
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ if (ME->isArrow())
+ Visit(ObjArgExpr, *I, AllArgsEvaluated);
+ else
+ VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
+ }
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+ assert(MD && "not a CXXMethodDecl?");
+
+ if (!MD->isThisDeclarationADefinition())
+ // FIXME: conservative method call evaluation.
+ return;
+
+ const StackFrameContext *SFC = AMgr.getStackFrame(MD,
+ Pred->getLocationContext(),
+ MCE,
+ Builder->getBlock(),
+ Builder->getIndex());
+ const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
+ CallEnter Loc(MCE, MD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
+ E = AllArgsEvaluated.end(); I != E; ++I) {
+ // Set up 'this' region.
+ const GRState *state = GetState(*I);
+ state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
+ ExplodedNode *N = Builder->generateNode(Loc, state, *I);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
+ const StackFrameContext *SFC) {
+ Type *T = D->getParent()->getTypeForDecl();
+ QualType PT = getContext().getPointerType(QualType(T,0));
+ return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
+}
+
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp
index 2defbcd..f68e10b 100644
--- a/lib/Checker/GRState.cpp
+++ b/lib/Checker/GRState.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/CFG.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
-#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -227,6 +227,18 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
return getPersistentState(NewSt);
}
+const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) {
+ GRState::GenericDataMap OldM = state->getGDM();
+ GRState::GenericDataMap NewM = GDMFactory.Remove(OldM, Key);
+
+ if (NewM == OldM)
+ return state;
+
+ GRState NewState = *state;
+ NewState.GDM = NewM;
+ return getPersistentState(NewState);
+}
+
//===----------------------------------------------------------------------===//
// Utility.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp
index 9621e85..bcd96e7 100644
--- a/lib/Checker/MacOSXAPIChecker.cpp
+++ b/lib/Checker/MacOSXAPIChecker.cpp
@@ -17,7 +17,7 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp
index a08afc4..a22df30 100644
--- a/lib/Checker/MallocChecker.cpp
+++ b/lib/Checker/MallocChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRState.h"
#include "clang/Checker/PathSensitive/GRStateTrait.h"
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9a26988..9f12ab6 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -13,10 +13,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/StmtVisitor.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index e428e2e..9130bfa 100644
--- a/lib/Checker/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -16,7 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/Checkers/LocalCheckers.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
#include "clang/Checker/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
diff --git a/lib/Checker/NoReturnFunctionChecker.cpp b/lib/Checker/NoReturnFunctionChecker.cpp
index 1455d87..12527e0 100644
--- a/lib/Checker/NoReturnFunctionChecker.cpp
+++ b/lib/Checker/NoReturnFunctionChecker.cpp
@@ -13,17 +13,17 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/Checker.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
namespace {
-class NoReturnFunctionChecker : public Checker {
+class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
public:
static void *getTag() { static int tag = 0; return &tag; }
- virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
};
}
@@ -32,48 +32,48 @@ void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) {
Eng.registerCheck(new NoReturnFunctionChecker());
}
-bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C,
- const CallExpr *CE) {
+void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
- bool BuildSinks = false;
+ bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
- if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
- BuildSinks = true;
- else if (const IdentifierInfo *II = FD->getIdentifier()) {
- // HACK: Some functions are not marked noreturn, and don't return.
- // Here are a few hardwired ones. If this takes too long, we can
- // potentially cache these results.
- BuildSinks
- = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
+ if (!BuildSinks) {
+ SVal L = state->getSVal(Callee);
+ const FunctionDecl *FD = L.getAsFunctionDecl();
+ if (!FD)
+ return;
+
+ if (FD->getAttr<AnalyzerNoReturnAttr>())
+ BuildSinks = true;
+ else if (const IdentifierInfo *II = FD->getIdentifier()) {
+ // HACK: Some functions are not marked noreturn, and don't return.
+ // Here are a few hardwired ones. If this takes too long, we can
+ // potentially cache these results.
+ BuildSinks
+ = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
+ .Case("exit", true)
+ .Case("panic", true)
+ .Case("error", true)
+ .Case("Assert", true)
+ // FIXME: This is just a wrapper around throwing an exception.
+ // Eventually inter-procedural analysis should handle this easily.
+ .Case("ziperr", true)
+ .Case("assfail", true)
+ .Case("db_error", true)
+ .Case("__assert", true)
+ .Case("__assert_rtn", true)
+ .Case("__assert_fail", true)
+ .Case("dtrace_assfail", true)
+ .Case("yy_fatal_error", true)
+ .Case("_XCAssertionFailureHandler", true)
+ .Case("_DTAssertionFailureHandler", true)
+ .Case("_TSAssertionFailureHandler", true)
+ .Default(false);
+ }
}
-
- if (!BuildSinks)
- return false;
- C.GenerateSink(CE);
- return true;
+ if (BuildSinks)
+ C.GenerateSink(CE);
}
diff --git a/lib/Checker/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp
index 97500d9..963923c 100644
--- a/lib/Checker/PathDiagnostic.cpp
+++ b/lib/Checker/PathDiagnostic.cpp
@@ -108,8 +108,8 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
P->addRange(Info.getRange(i));
- for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
- P->addCodeModificationHint(Info.getCodeModificationHint(i));
+ for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
+ P->addFixItHint(Info.getFixItHint(i));
D->push_front(P);
HandlePathDiagnostic(D);
diff --git a/lib/Checker/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp
index 3d62d0c..ed60c42 100644
--- a/lib/Checker/PointerArithChecker.cpp
+++ b/lib/Checker/PointerArithChecker.cpp
@@ -12,8 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp
index acc848a..bc0fd24 100644
--- a/lib/Checker/PointerSubChecker.cpp
+++ b/lib/Checker/PointerSubChecker.cpp
@@ -13,8 +13,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index c2b702a..c97da33 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -536,15 +536,15 @@ public:
// First visit the cluster.
static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end());
- // Next, visit the region.
- static_cast<DERIVED*>(this)->VisitRegion(baseR);
+ // Next, visit the base region.
+ static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
}
}
public:
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {}
- void VisitRegion(const MemRegion *baseR) {}
+ void VisitBaseRegion(const MemRegion *baseR) {}
};
}
@@ -580,7 +580,7 @@ public:
Ex(ex), Count(count), IS(is) {}
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
- void VisitRegion(const MemRegion *baseR);
+ void VisitBaseRegion(const MemRegion *baseR);
private:
void VisitBinding(SVal V);
@@ -627,7 +627,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
}
}
-void InvalidateRegionsWorker::VisitRegion(const MemRegion *baseR) {
+void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
if (IS) {
// Symbolic region? Mark that symbol touched by the invalidation.
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
@@ -787,9 +787,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
return ValMgr.makeIntVal(CAT->getSize(), false);
}
- // Clients can use ordinary variables as if they were arrays. These
- // essentially are arrays of size 1.
- return ValMgr.makeIntVal(1, false);
+ // Clients can reinterpret ordinary variables as arrays, possibly of
+ // another type. The width is rounded down to ensure that an access is
+ // entirely within bounds.
+ CharUnits VarSize = getContext().getTypeSizeInChars(T);
+ CharUnits EleSize = getContext().getTypeSizeInChars(EleTy);
+ return ValMgr.makeIntVal(VarSize / EleSize, false);
}
}
@@ -963,7 +966,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return V;
return getDefaultBinding(B, R);
@@ -1044,7 +1047,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
#endif
- if (RTy->isStructureType())
+ if (RTy->isStructureType() || RTy->isClassType())
return RetrieveStruct(store, R);
// FIXME: Handle unions.
@@ -1144,7 +1147,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
const ElementRegion* R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1175,7 +1178,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
}
// Check if the immediate super region has a direct binding.
- if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (const Optional<SVal> &V = getDirectBinding(B, superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1203,7 +1206,7 @@ SVal RegionStoreManager::RetrieveField(Store store,
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
QualType Ty = R->getValueType(getContext());
@@ -1278,13 +1281,13 @@ SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
const MemRegion *superR = R->getSuperRegion();
// Check if the super region has a default binding.
- if (Optional<SVal> V = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &V = getDefaultBinding(B, superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1300,7 +1303,7 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
// Check if the region has a binding.
RegionBindings B = GetRegionBindings(store);
- if (Optional<SVal> V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = getDirectBinding(B, R))
return *V;
// Lazily derive a value for the VarRegion.
@@ -1313,8 +1316,23 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
return ValMgr.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
- if (VD->isFileVarDecl())
+ if (VD->isFileVarDecl()) {
+ // Is 'VD' declared constant? If so, retrieve the constant value.
+ QualType CT = Ctx.getCanonicalType(T);
+ if (CT.isConstQualified()) {
+ const Expr *Init = VD->getInit();
+ // Do the null check first, as we want to call 'IgnoreParenCasts'.
+ if (Init)
+ if (const IntegerLiteral *IL =
+ dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
+ const nonloc::ConcreteInt &V = ValMgr.makeIntVal(IL);
+ return ValMgr.getSValuator().EvalCast(V, Init->getType(),
+ IL->getType());
+ }
+ }
+
return ValMgr.getRegionValueSymbolVal(R);
+ }
if (T->isIntegerType())
return ValMgr.makeIntVal(0, T);
@@ -1337,8 +1355,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
- assert(T->isStructureType());
- assert(T->getAsStructureType()->getDecl()->isDefinition());
+ assert(T->isStructureType() || T->isClassType());
return ValMgr.makeLazyCompoundVal(store, R);
}
@@ -1692,8 +1709,8 @@ public:
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
- void VisitRegion(const MemRegion *baseR);
+ void VisitBindingKey(BindingKey K);
bool UpdatePostponed();
void VisitBinding(SVal V);
};
@@ -1730,11 +1747,8 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
BindingKey *I, BindingKey *E) {
- for ( ; I != E; ++I) {
- const MemRegion *R = I->getRegion();
- if (R != baseR)
- VisitRegion(R);
- }
+ for ( ; I != E; ++I)
+ VisitBindingKey(*I);
}
void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
@@ -1762,34 +1776,36 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
SymReaper.markLive(*SI);
}
-void RemoveDeadBindingsWorker::VisitRegion(const MemRegion *R) {
+void RemoveDeadBindingsWorker::VisitBindingKey(BindingKey K) {
+ const MemRegion *R = K.getRegion();
+
// Mark this region "live" by adding it to the worklist. This will cause
// use to visit all regions in the cluster (if we haven't visited them
// already).
- AddToWorkList(R);
-
- // Mark the symbol for any live SymbolicRegion as "live". This means we
- // should continue to track that symbol.
- if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
- SymReaper.markLive(SymR->getSymbol());
+ if (AddToWorkList(R)) {
+ // Mark the symbol for any live SymbolicRegion as "live". This means we
+ // should continue to track that symbol.
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+ SymReaper.markLive(SymR->getSymbol());
+
+ // For BlockDataRegions, enqueue the VarRegions for variables marked
+ // with __block (passed-by-reference).
+ // via BlockDeclRefExprs.
+ if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
+ RI != RE; ++RI) {
+ if ((*RI)->getDecl()->getAttr<BlocksAttr>())
+ AddToWorkList(*RI);
+ }
- // For BlockDataRegions, enqueue the VarRegions for variables marked
- // with __block (passed-by-reference).
- // via BlockDeclRefExprs.
- if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
- for (BlockDataRegion::referenced_vars_iterator
- RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
- RI != RE; ++RI) {
- if ((*RI)->getDecl()->getAttr<BlocksAttr>())
- AddToWorkList(*RI);
+ // No possible data bindings on a BlockDataRegion.
+ return;
}
-
- // No possible data bindings on a BlockDataRegion.
- return;
}
- // Get the data binding for R (if any).
- if (Optional<SVal> V = RM.getBinding(B, R))
+ // Visit the data binding for K.
+ if (const SVal *V = RM.Lookup(B, K))
VisitBinding(*V);
}
diff --git a/lib/Checker/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp
index 949ded5..14edf56 100644
--- a/lib/Checker/ReturnPointerRangeChecker.cpp
+++ b/lib/Checker/ReturnPointerRangeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/ReturnStackAddressChecker.cpp b/lib/Checker/ReturnStackAddressChecker.cpp
index 9cbabba..35b1cde 100644
--- a/lib/Checker/ReturnStackAddressChecker.cpp
+++ b/lib/Checker/ReturnStackAddressChecker.cpp
@@ -14,8 +14,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/Checker/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp
index ee25988..52a0b30 100644
--- a/lib/Checker/ReturnUndefChecker.cpp
+++ b/lib/Checker/ReturnUndefChecker.cpp
@@ -14,10 +14,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
using namespace clang;
diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp
index 65a46e3..f3a803c 100644
--- a/lib/Checker/SymbolManager.cpp
+++ b/lib/Checker/SymbolManager.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp
index e047b18..9088345 100644
--- a/lib/Checker/UndefBranchChecker.cpp
+++ b/lib/Checker/UndefBranchChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/Checker.h"
using namespace clang;
diff --git a/lib/Checker/UndefCapturedBlockVarChecker.cpp b/lib/Checker/UndefCapturedBlockVarChecker.cpp
index a8d7284..b1010c9 100644
--- a/lib/Checker/UndefCapturedBlockVarChecker.cpp
+++ b/lib/Checker/UndefCapturedBlockVarChecker.cpp
@@ -14,7 +14,7 @@
#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/Checker/UndefResultChecker.cpp b/lib/Checker/UndefResultChecker.cpp
index fb2283a..8b07aed 100644
--- a/lib/Checker/UndefResultChecker.cpp
+++ b/lib/Checker/UndefResultChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/Checker/UndefinedArraySubscriptChecker.cpp b/lib/Checker/UndefinedArraySubscriptChecker.cpp
index a2792ad..148629e 100644
--- a/lib/Checker/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Checker/UndefinedArraySubscriptChecker.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
using namespace clang;
diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp
index 7c33c1d..6cef60e 100644
--- a/lib/Checker/UndefinedAssignmentChecker.cpp
+++ b/lib/Checker/UndefinedAssignmentChecker.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
@@ -53,27 +53,43 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
if (!N)
return;
+ const char *str = "Assigned value is garbage or undefined";
+
if (!BT)
- BT = new BuiltinBug("Assigned value is garbage or undefined");
+ BT = new BuiltinBug(str);
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ const Expr *ex = 0;
- if (AssignE) {
- const Expr *ex = 0;
+ while (AssignE) {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) {
+ if (B->isCompoundAssignmentOp()) {
+ const GRState *state = C.getState();
+ if (state->getSVal(B->getLHS()).isUndef()) {
+ str = "The left expression of the compound assignment is an "
+ "uninitialized value. The computed value will also be garbage";
+ ex = B->getLHS();
+ break;
+ }
+ }
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE))
ex = B->getRHS();
- else if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) {
+ break;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) {
const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
ex = VD->getInit();
}
- if (ex) {
- R->addRange(ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
- }
+
+ break;
}
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N);
+ if (ex) {
+ R->addRange(ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+ }
C.EmitReport(R);
-}
+}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index 7ff817a..d75e5d2 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -12,11 +12,10 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
-#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "llvm/ADT/StringSwitch.h"
-#include "GRExprEngineInternalChecks.h"
#include <fcntl.h>
using namespace clang;
diff --git a/lib/Checker/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp
index 51ad1e2..cea9d19 100644
--- a/lib/Checker/VLASizeChecker.cpp
+++ b/lib/Checker/VLASizeChecker.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
+#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
-#include "clang/Checker/BugReporter/BugReporter.h"
using namespace clang;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index c10a401..5097341 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -17,6 +17,7 @@
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Target/TargetData.h"
#include <algorithm>
@@ -192,7 +193,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
CallArgList Args;
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args,
- CC_Default, false);
+ FunctionType::ExtInfo());
if (CGM.ReturnTypeUsesSret(FnInfo))
flags |= BLOCK_USE_STRET;
}
@@ -472,8 +473,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(),
- FuncTy->getNoReturnAttr());
+ CGM.getTypes().getFunctionInfo(ResultType, Args,
+ FuncTy->getExtInfo());
// Cast the function pointer to the right type.
const llvm::Type *BlockFTy =
@@ -678,8 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType;
- CallingConv CC = BlockFunctionType->getCallConv();
- bool NoReturn = BlockFunctionType->getNoReturnAttr();
+ FunctionType::ExtInfo EInfo = getFunctionExtInfo(*BlockFunctionType);
bool IsVariadic;
if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) {
@@ -718,7 +718,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
Args.push_back(std::make_pair(*i, (*i)->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn);
+ CGM.getTypes().getFunctionInfo(ResultType, Args, EInfo);
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
@@ -843,7 +843,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -924,7 +924,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1008,7 +1008,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1071,7 +1071,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI =
- CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index e91319f..efee0e3 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -17,7 +17,6 @@
#include "CodeGenTypes.h"
#include "clang/AST/Type.h"
#include "llvm/Module.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 419ed73..a9b0b64 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -81,10 +81,6 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF,
Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)),
CGF.EmitScalarExpr(E->getArg(1)) };
Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2);
-
- if (Id == Intrinsic::atomic_load_nand)
- Result = CGF.Builder.CreateNot(Result);
-
return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1]));
}
@@ -550,12 +546,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_fetch_and_xor_8:
case Builtin::BI__sync_fetch_and_xor_16:
return EmitBinaryAtomic(*this, Intrinsic::atomic_load_xor, E);
- case Builtin::BI__sync_fetch_and_nand_1:
- case Builtin::BI__sync_fetch_and_nand_2:
- case Builtin::BI__sync_fetch_and_nand_4:
- case Builtin::BI__sync_fetch_and_nand_8:
- case Builtin::BI__sync_fetch_and_nand_16:
- return EmitBinaryAtomic(*this, Intrinsic::atomic_load_nand, E);
// Clang extensions: not overloaded yet.
case Builtin::BI__sync_fetch_and_min:
@@ -602,13 +592,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__sync_xor_and_fetch_16:
return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_xor, E,
llvm::Instruction::Xor);
- case Builtin::BI__sync_nand_and_fetch_1:
- case Builtin::BI__sync_nand_and_fetch_2:
- case Builtin::BI__sync_nand_and_fetch_4:
- case Builtin::BI__sync_nand_and_fetch_8:
- case Builtin::BI__sync_nand_and_fetch_16:
- return EmitBinaryAtomicPost(*this, Intrinsic::atomic_load_nand, E,
- llvm::Instruction::And);
case Builtin::BI__sync_val_compare_and_swap_1:
case Builtin::BI__sync_val_compare_and_swap_2:
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index b88001c..93a182f 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -297,311 +297,6 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name,
getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer());
}
-llvm::Constant *
-CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const ThunkAdjustment &ThisAdjustment) {
- return GenerateCovariantThunk(Fn, GD, Extern,
- CovariantThunkAdjustment(ThisAdjustment,
- ThunkAdjustment()));
-}
-
-llvm::Value *
-CodeGenFunction::DynamicTypeAdjust(llvm::Value *V,
- const ThunkAdjustment &Adjustment) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-
- const llvm::Type *OrigTy = V->getType();
- if (Adjustment.NonVirtual) {
- // Do the non-virtual adjustment
- V = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual);
- V = Builder.CreateBitCast(V, OrigTy);
- }
-
- if (!Adjustment.Virtual)
- return V;
-
- assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 &&
- "vtable entry unaligned");
-
- // Do the virtual this adjustment
- const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
- const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo();
-
- llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy);
- V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo());
- V = Builder.CreateLoad(V, "vtable");
-
- llvm::Value *VTablePtr = V;
- uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8);
- V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
- V = Builder.CreateLoad(V);
- V = Builder.CreateGEP(ThisVal, V);
-
- return Builder.CreateBitCast(V, OrigTy);
-}
-
-llvm::Constant *
-CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
- GlobalDecl GD, bool Extern,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getResultType();
-
- FunctionArgList Args;
- ImplicitParamDecl *ThisDecl =
- ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0,
- MD->getThisType(getContext()));
- Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType()));
- for (FunctionDecl::param_const_iterator i = MD->param_begin(),
- e = MD->param_end();
- i != e; ++i) {
- ParmVarDecl *D = *i;
- Args.push_back(std::make_pair(D, D->getType()));
- }
- IdentifierInfo *II
- = &CGM.getContext().Idents.get("__thunk_named_foo_");
- FunctionDecl *FD = FunctionDecl::Create(getContext(),
- getContext().getTranslationUnitDecl(),
- SourceLocation(), II, ResultType, 0,
- Extern
- ? FunctionDecl::Extern
- : FunctionDecl::Static,
- false, true);
- StartFunction(FD, ResultType, Fn, Args, SourceLocation());
-
- // generate body
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
-
- CallArgList CallArgs;
-
- bool ShouldAdjustReturnPointer = true;
- QualType ArgType = MD->getThisType(getContext());
- llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this");
- if (!Adjustment.ThisAdjustment.isEmpty()) {
- // Do the this adjustment.
- const llvm::Type *OrigTy = Callee->getType();
- Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment);
-
- if (!Adjustment.ReturnAdjustment.isEmpty()) {
- const CovariantThunkAdjustment &ReturnAdjustment =
- CovariantThunkAdjustment(ThunkAdjustment(),
- Adjustment.ReturnAdjustment);
-
- Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment);
-
- Callee = Builder.CreateBitCast(Callee, OrigTy);
- ShouldAdjustReturnPointer = false;
- }
- }
-
- CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType));
-
- for (FunctionDecl::param_const_iterator i = MD->param_begin(),
- e = MD->param_end();
- i != e; ++i) {
- ParmVarDecl *D = *i;
- QualType ArgType = D->getType();
-
- // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst);
- Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(),
- SourceLocation());
- CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType));
- }
-
- RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
- FPT->getCallConv(),
- FPT->getNoReturnAttr()),
- Callee, ReturnValueSlot(), CallArgs, MD);
- if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
- bool CanBeZero = !(ResultType->isReferenceType()
- // FIXME: attr nonnull can't be zero either
- /* || ResultType->hasAttr<NonNullAttr>() */ );
- // Do the return result adjustment.
- if (CanBeZero) {
- llvm::BasicBlock *NonZeroBlock = createBasicBlock();
- llvm::BasicBlock *ZeroBlock = createBasicBlock();
- llvm::BasicBlock *ContBlock = createBasicBlock();
-
- const llvm::Type *Ty = RV.getScalarVal()->getType();
- llvm::Value *Zero = llvm::Constant::getNullValue(Ty);
- Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero),
- NonZeroBlock, ZeroBlock);
- EmitBlock(NonZeroBlock);
- llvm::Value *NZ =
- DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment);
- EmitBranch(ContBlock);
- EmitBlock(ZeroBlock);
- llvm::Value *Z = RV.getScalarVal();
- EmitBlock(ContBlock);
- llvm::PHINode *RVOrZero = Builder.CreatePHI(Ty);
- RVOrZero->reserveOperandSpace(2);
- RVOrZero->addIncoming(NZ, NonZeroBlock);
- RVOrZero->addIncoming(Z, ZeroBlock);
- RV = RValue::get(RVOrZero);
- } else
- RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(),
- Adjustment.ReturnAdjustment));
- }
-
- if (!ResultType->isVoidType())
- EmitReturnOfRValue(RV, ResultType);
-
- FinishFunction();
- return Fn;
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
- const ThunkAdjustment &ThisAdjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Compute mangled name
- llvm::SmallString<256> OutName;
- if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
- getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment,
- OutName);
- else
- getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
-
- // Get function for mangled name
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
- return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl());
-}
-
-llvm::Constant *
-CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Compute mangled name
- llvm::SmallString<256> Name;
- getMangleContext().mangleCovariantThunk(MD, Adjustment, Name);
-
- // Get function for mangled name
- const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
-}
-
-void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) {
- CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD);
- if (!AdjPtr)
- return;
- CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr;
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- for (unsigned i = 0; i < Adj.size(); i++) {
- GlobalDecl OGD = Adj[i].first;
- const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl());
- QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType oret = getContext().getCanonicalType(nc_oret);
- QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
- CanQualType ret = getContext().getCanonicalType(nc_ret);
- ThunkAdjustment ReturnAdjustment;
- if (oret != ret) {
- QualType qD = nc_ret->getPointeeType();
- QualType qB = nc_oret->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- ReturnAdjustment = ComputeThunkAdjustment(D, B);
- }
- ThunkAdjustment ThisAdjustment = Adj[i].second;
- bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace();
- if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
- CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment);
- llvm::Constant *FnConst;
- if (!ReturnAdjustment.isEmpty())
- FnConst = GetAddrOfCovariantThunk(GD, CoAdj);
- else
- FnConst = GetAddrOfThunk(GD, ThisAdjustment);
- if (!isa<llvm::Function>(FnConst)) {
- llvm::Constant *SubExpr =
- cast<llvm::ConstantExpr>(FnConst)->getOperand(0);
- llvm::Function *OldFn = cast<llvm::Function>(SubExpr);
- llvm::Constant *NewFnConst;
- if (!ReturnAdjustment.isEmpty())
- NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj);
- else
- NewFnConst = GetAddrOfThunk(GD, ThisAdjustment);
- llvm::Function *NewFn = cast<llvm::Function>(NewFnConst);
- NewFn->takeName(OldFn);
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType());
- OldFn->replaceAllUsesWith(NewPtrForOldDecl);
- OldFn->eraseFromParent();
- FnConst = NewFn;
- }
- llvm::Function *Fn = cast<llvm::Function>(FnConst);
- if (Fn->isDeclaration()) {
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- Fn->setLinkage(linktype);
- if (!Features.Exceptions && !Features.ObjCNonFragileABI)
- Fn->addFnAttr(llvm::Attribute::NoUnwind);
- Fn->setAlignment(2);
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj);
- }
- }
- }
-}
-
-llvm::Constant *
-CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern,
- const ThunkAdjustment &ThisAdjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- llvm::SmallString<256> OutName;
- if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) {
- getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment,
- OutName);
- } else
- getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
-
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
- &getModule());
- CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
-llvm::Constant *
-CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
- const CovariantThunkAdjustment &Adjustment) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- llvm::SmallString<256> OutName;
- getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- if (!Extern)
- linktype = llvm::GlobalValue::InternalLinkage;
- llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
-
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
- &getModule());
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment);
- llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
- return m;
-}
-
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -618,17 +313,17 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD);
- return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+ return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- uint64_t VtableIndex =
- CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
+ uint64_t VTableIndex =
+ CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type));
- return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+ return ::BuildVirtualCall(*this, VTableIndex, This, Ty);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 072b1f6..cb1ecc1 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -67,8 +67,7 @@ const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
llvm::SmallVector<CanQualType, 16>(),
- FTNP->getCallConv(),
- FTNP->getNoReturnAttr());
+ FTNP->getExtInfo());
}
/// \param Args - contains any initial parameters besides those
@@ -81,8 +80,7 @@ static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
ArgTys.push_back(FTP->getArgType(i));
CanQualType ResTy = FTP->getResultType().getUnqualifiedType();
return CGT.getFunctionInfo(ResTy, ArgTys,
- FTP->getCallConv(),
- FTP->getNoReturnAttr());
+ FTP->getExtInfo());
}
const CGFunctionInfo &
@@ -175,8 +173,10 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
}
return getFunctionInfo(GetReturnType(MD->getResultType()),
ArgTys,
- getCallingConventionForDecl(MD),
- /*NoReturn*/ false);
+ FunctionType::ExtInfo(
+ /*NoReturn*/ false,
+ /*RegParm*/ 0,
+ getCallingConventionForDecl(MD)));
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@@ -194,43 +194,40 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- CallingConv CC,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
llvm::SmallVector<CanQualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->second));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn);
+ return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- CallingConv CC,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
// FIXME: Kill copy.
llvm::SmallVector<CanQualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->second));
- return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn);
+ return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
- CallingConv CallConv,
- bool NoReturn) {
+ const FunctionType::ExtInfo &Info) {
#ifndef NDEBUG
for (llvm::SmallVectorImpl<CanQualType>::const_iterator
I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
assert(I->isCanonicalAsParam());
#endif
- unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
+ unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC());
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy,
+ CGFunctionInfo::Profile(ID, Info, ResTy,
ArgTys.begin(), ArgTys.end());
void *InsertPos = 0;
@@ -239,7 +236,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
return *FI;
// Construct the function info.
- FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
+ FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information.
@@ -250,11 +247,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
bool _NoReturn,
+ unsigned _RegParm,
CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
- NoReturn(_NoReturn)
+ NoReturn(_NoReturn), RegParm(_RegParm)
{
NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs];
@@ -610,11 +608,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// FIXME: we need to honour command line settings also...
// FIXME: RegParm should be reduced in case of nested functions and/or global
// register variable.
- signed RegParm = 0;
- if (TargetDecl)
- if (const RegparmAttr *RegParmAttr
- = TargetDecl->getAttr<RegparmAttr>())
- RegParm = RegParmAttr->getNumParams();
+ signed RegParm = FI.getRegParm();
unsigned PointerWidth = getContext().Target.getPointerWidth(0);
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
@@ -623,8 +617,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const ABIArgInfo &AI = it->info;
unsigned Attributes = 0;
- if (ParamType.isRestrictQualified())
- Attributes |= llvm::Attribute::NoAlias;
+ // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we
+ // have the corresponding parameter variable. It doesn't make
+ // sense to do it here because parameters are so fucked up.
switch (AI.getKind()) {
case ABIArgInfo::Coerce:
@@ -749,6 +744,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
V = CreateMemTemp(Ty);
Builder.CreateStore(AI, V);
} else {
+ if (Arg->getType().isRestrictQualified())
+ AI->addAttr(llvm::Attribute::NoAlias);
+
if (!getContext().typesAreCompatible(Ty, Arg->getType())) {
// This must be a promotion, for something like
// "void a(x) short x; {..."
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 3d81165..31c8aac 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -76,12 +76,16 @@ namespace CodeGen {
unsigned NumArgs;
ArgInfo *Args;
+ /// How many arguments to pass inreg.
+ unsigned RegParm;
+
public:
typedef const ArgInfo *const_arg_iterator;
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention,
bool NoReturn,
+ unsigned RegParm,
CanQualType ResTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys);
~CGFunctionInfo() { delete[] Args; }
@@ -108,6 +112,8 @@ namespace CodeGen {
EffectiveCallingConvention = Value;
}
+ unsigned getRegParm() const { return RegParm; }
+
CanQualType getReturnType() const { return Args[0].type; }
ABIArgInfo &getReturnInfo() { return Args[0].info; }
@@ -116,19 +122,20 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
+ ID.AddInteger(RegParm);
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
}
template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
- unsigned CallingConvention,
- bool NoReturn,
+ const FunctionType::ExtInfo &Info,
CanQualType ResTy,
Iterator begin,
Iterator end) {
- ID.AddInteger(CallingConvention);
- ID.AddBoolean(NoReturn);
+ ID.AddInteger(Info.getCC());
+ ID.AddBoolean(Info.getNoReturn());
+ ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);
for (; begin != end; ++begin) {
CanQualType T = *begin; // force iterator to be over canonical types
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 525e858..177e862 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -69,42 +69,6 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class,
return llvm::ConstantInt::get(PtrDiffTy, Offset);
}
-// FIXME: This probably belongs in CGVtable, but it relies on
-// the static function ComputeNonVirtualBaseClassOffset, so we should make that
-// a CodeGenModule member function as well.
-ThunkAdjustment
-CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!const_cast<CXXRecordDecl *>(ClassDecl)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
- assert(false && "Class must be derived from the passed in base class!");
- return ThunkAdjustment();
- }
-
- unsigned Start = 0;
- uint64_t VirtualOffset = 0;
-
- const CXXBasePath &Path = Paths.front();
- const CXXRecordDecl *VBase = 0;
- for (unsigned i = 0, e = Path.size(); i != e; ++i) {
- const CXXBasePathElement& Element = Path[i];
- if (Element.Base->isVirtual()) {
- Start = i+1;
- QualType VBaseType = Element.Base->getType();
- VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
- }
- }
- if (VBase)
- VirtualOffset =
- getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
-
- uint64_t Offset =
- ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start);
- return ThunkAdjustment(Offset, VirtualOffset);
-}
-
/// Gets the address of a virtual base class within a complete object.
/// This should only be used for (1) non-virtual bases or (2) virtual bases
/// when the type is known to be complete (e.g. in complete destructors).
@@ -139,7 +103,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This,
V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo());
return V;
-}
+}
llvm::Value *
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
@@ -308,6 +272,53 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return Value;
}
+/// EmitCopyCtorCall - Emit a call to a copy constructor.
+static void
+EmitCopyCtorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType,
+ llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) {
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType);
+
+ CallArgList CallArgs;
+
+ // Push the this ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(ThisPtr),
+ CopyCtor->getThisType(CGF.getContext())));
+
+ // Push the VTT parameter if necessary.
+ if (VTT) {
+ QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy);
+ CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
+ }
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ CopyCtor->getParamDecl(0)->getType()));
+
+
+ {
+ CodeGenFunction::CXXTemporariesCleanupScope Scope(CGF);
+
+ // If the copy constructor has default arguments, emit them.
+ for (unsigned I = 1, E = CopyCtor->getNumParams(); I < E; ++I) {
+ const ParmVarDecl *Param = CopyCtor->getParamDecl(I);
+ const Expr *DefaultArgExpr = Param->getDefaultArg();
+
+ assert(DefaultArgExpr && "Ctor parameter must have default arg!");
+
+ QualType ArgType = Param->getType();
+ CallArgs.push_back(std::make_pair(CGF.EmitCallArg(DefaultArgExpr,
+ ArgType),
+ ArgType));
+ }
+
+ const FunctionProtoType *FPT =
+ CopyCtor->getType()->getAs<FunctionProtoType>();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
+ Callee, ReturnValueSlot(), CallArgs, CopyCtor);
+ }
+}
+
/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
/// array of objects from SrcValue to DestValue. Copying can be either a bitwise
/// copy or via a copy constructor call.
@@ -354,22 +365,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
if (BitwiseCopy)
EmitAggregateCopy(Dest, Src, Ty);
else if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
+ BaseClassDecl->getCopyConstructor(getContext(), 0))
+ EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src);
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT
- = BaseCopyCtor->getType()->getAs<FunctionProtoType>();
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
- }
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -471,7 +469,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
/// GetVTTParameter - Return the VTT parameter that should be passed to a
/// base constructor/destructor with virtual bases.
static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
- if (!CGVtableInfo::needsVTTParameter(GD)) {
+ if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
}
@@ -486,21 +484,21 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
// If the record matches the base, this is the complete ctor/dtor
// variant calling the base variant in a class with virtual bases.
if (RD == Base) {
- assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) &&
+ assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
SubVTTIndex = 0;
} else {
- SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+ SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base);
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
- if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
// A VTT parameter was passed to the constructor, use it.
VTT = CGF.LoadCXXVTT();
VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
} else {
// We're the complete constructor, so get the VTT by name.
- VTT = CGF.CGM.getVtableInfo().getVTT(RD);
+ VTT = CGF.CGM.getVTables().getVTT(RD);
VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
}
@@ -531,29 +529,13 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
return;
}
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(getContext(), 0)) {
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
- CallArgList CallArgs;
- // Push the this (Dest) ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Dest),
- BaseCopyCtor->getThisType(getContext())));
-
- // Push the VTT parameter, if necessary.
- if (llvm::Value *VTT =
- GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
- }
+ CXXConstructorDecl *BaseCopyCtor =
+ BaseClassDecl->getCopyConstructor(getContext(), 0);
+ if (!BaseCopyCtor)
+ return;
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- BaseCopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT =
- BaseCopyCtor->getType()->getAs<FunctionProtoType>();
- EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
- }
+ llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType));
+ EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src);
}
/// EmitClassCopyAssignment - This routine generates code to copy assign a class
@@ -690,7 +672,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) {
}
}
- InitializeVtablePtrs(ClassDecl);
+ InitializeVTablePointers(ClassDecl);
}
/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator.
@@ -1010,7 +992,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
MemberInitializers.push_back(Member);
}
- InitializeVtablePtrs(ClassDecl);
+ InitializeVTablePointers(ClassDecl);
for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) {
assert(LiveTemporaries.empty() &&
@@ -1060,7 +1042,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// Otherwise, we're in the base variant, so we need to ensure the
// vtable ptrs are right before emitting the body.
} else {
- InitializeVtablePtrs(Dtor->getParent());
+ InitializeVTablePointers(Dtor->getParent());
}
// Emit the body of the statement.
@@ -1286,14 +1268,12 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
// before the construction of the next array element, if any.
// Keep track of the current number of live temporaries.
- unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+ {
+ CXXTemporariesCleanupScope Scope(*this);
- EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+ }
- // Pop temporaries.
- while (LiveTemporaries.size() > OldNumLiveTemporaries)
- PopCXXTemporary();
-
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
@@ -1399,7 +1379,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy;
const CGFunctionInfo &FI
- = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
+ = CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo());
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
@@ -1474,7 +1454,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP));
- if (CGVtableInfo::needsVTTParameter(CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CurGD)) {
assert(I != E && "cannot skip vtt parameter, already done with args");
assert(I->second == VoidPP && "skipping parameter not of vtt type");
++I;
@@ -1541,7 +1521,7 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
int64_t VBaseOffsetOffset =
- CGM.getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
+ CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl);
llvm::Value *VBaseOffsetPtr =
Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr");
@@ -1556,69 +1536,126 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
-void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->isDynamicClass())
- return;
+void
+CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // Compute the address point.
+ llvm::Value *VTableAddressPoint;
+
+ // Check if we need to use a vtable from the VTT.
+ if (CodeGenVTables::needsVTTParameter(CurGD) &&
+ (RD->getNumVBases() || BaseIsMorallyVirtual)) {
+ // Get the secondary vpointer index.
+ uint64_t VirtualPointerIndex =
+ CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base);
+
+ /// Load the VTT.
+ llvm::Value *VTT = LoadCXXVTT();
+ if (VirtualPointerIndex)
+ VTT = Builder.CreateConstInBoundsGEP1_64(VTT, VirtualPointerIndex);
- llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
- CGVtableInfo::AddrSubMap_t& AddressPoints =
- *(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl];
- llvm::Value *ThisPtr = LoadCXXThis();
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
+ // And load the address point from the VTT.
+ VTableAddressPoint = Builder.CreateLoad(VTT);
+ } else {
+ uint64_t AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ VTableAddressPoint =
+ Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint);
+ }
- // Store address points for virtual bases
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, Offset);
+ // Compute where to store the address point.
+ llvm::Value *VTableField;
+
+ if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) {
+ // We need to use the virtual base offset offset because the virtual base
+ // might have a different offset in the most derived class.
+ VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD,
+ /*NullCheckValue=*/false);
+ } else {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+
+ VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy);
+ VTableField =
+ Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8);
}
- // Store address points for non-virtual bases and current class
- InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
+ // Finally, store the address point.
+ const llvm::Type *AddressPointPtrTy =
+ VTableAddressPoint->getType()->getPointerTo();
+ VTableField = Builder.CreateBitCast(VTableField, AddressPointPtrTy);
+ Builder.CreateStore(VTableAddressPoint, VTableField);
}
-void CodeGenFunction::InitializeVtablePtrsRecursive(
- const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CGVtableInfo::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset) {
- if (!ClassDecl->isDynamicClass())
- return;
+void
+CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ bool BaseIsNonVirtualPrimaryBase,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy& VBases) {
+ // If this base is a non-virtual primary base the address point has already
+ // been set.
+ if (!BaseIsNonVirtualPrimaryBase) {
+ // Initialize the vtable pointer for this base.
+ InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass);
+ }
+
+ const CXXRecordDecl *RD = Base.getBase();
- // Store address points for non-virtual bases
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
- if (Base.isVirtual())
+ // Traverse bases.
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore classes without a vtable.
+ if (!BaseDecl->isDynamicClass())
continue;
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
- uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
- InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
- ThisPtr, NewOffset);
+
+ uint64_t BaseOffset;
+ bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ bool BaseDeclIsNonVirtualPrimaryBase;
+
+ if (I->isVirtual()) {
+ // Check if we've visited this virtual base before.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(VTableClass);
+
+ BaseOffset = Layout.getVBaseClassOffset(BaseDecl);
+ BaseDeclIsMorallyVirtual = true;
+ BaseDeclIsNonVirtualPrimaryBase = false;
+ } else {
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+
+ BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+ BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl;
+ }
+
+ InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
+ BaseDeclIsMorallyVirtual,
+ BaseDeclIsNonVirtualPrimaryBase,
+ VTable, VTableClass, VBases);
}
+}
- // Compute the address point
- assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
- "Missing address point for class");
- uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
- llvm::Value *VtableAddressPoint =
- Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
-
- // Compute the address to store the address point
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
- VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
- const llvm::Type *AddressPointPtrTy =
- VtableAddressPoint->getType()->getPointerTo();
- VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
+void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
+ // Ignore classes without a vtable.
+ if (!RD->isDynamicClass())
+ return;
+
+ // Get the VTable.
+ llvm::Constant *VTable = CGM.getVTables().GetAddrOfVTable(RD);
- // Store address point
- Builder.CreateStore(VtableAddressPoint, VtableField);
+ // Initialize the vtable pointers for this class and all of its bases.
+ VisitedVirtualBasesSetTy VBases;
+ InitializeVTablePointers(BaseSubobject(RD, 0),
+ /*BaseIsMorallyVirtual=*/false,
+ /*BaseIsNonVirtualPrimaryBase=*/false,
+ VTable, RD, VBases);
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index ad97d08..58acd3c 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -88,17 +88,35 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
/// getOrCreateFile - Get the file debug info descriptor for the input location.
llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
- if (!Loc.isValid())
+ if (!Loc.isValid())
// If Location is not valid then use main input file.
return DebugFactory.CreateFile(TheCU.getFilename(), TheCU.getDirectory(),
TheCU);
SourceManager &SM = CGM.getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+
+ // Cache the results.
+ const char *fname = PLoc.getFilename();
+ llvm::DenseMap<const char *, llvm::WeakVH>::iterator it =
+ DIFileCache.find(fname);
+
+ if (it != DIFileCache.end()) {
+ // Verify that the information still exists.
+ if (&*it->second)
+ return llvm::DIFile(cast<llvm::MDNode>(it->second));
+ }
+
+ // FIXME: We shouldn't even need to call 'makeAbsolute()' in the cases
+ // where we can consult the FileEntry.
llvm::sys::Path AbsFileName(PLoc.getFilename());
AbsFileName.makeAbsolute();
- return DebugFactory.CreateFile(AbsFileName.getLast(),
- AbsFileName.getDirname(), TheCU);
+ llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(),
+ AbsFileName.getDirname(), TheCU);
+
+ DIFileCache[fname] = F.getNode();
+ return F;
+
}
/// CreateCompileUnit - Create new compile unit.
void CGDebugInfo::CreateCompileUnit() {
@@ -112,6 +130,10 @@ void CGDebugInfo::CreateCompileUnit() {
llvm::sys::Path AbsFileName(MainFileName);
AbsFileName.makeAbsolute();
+ // The main file name provided via the "-main-file-name" option contains just
+ // the file name itself with no path information. This file name may have had
+ // a relative path, so we look into the actual file entry for the main
+ // file to determine the real absolute path for the file.
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
MainFileDir = MainFile->getDir()->getName();
@@ -604,7 +626,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
// It doesn't make sense to give a virtual destructor a vtable index,
// since a single destructor has two entries in the vtable.
if (!isa<CXXDestructorDecl>(Method))
- VIndex = CGM.getVtableInfo().getMethodVtableIndex(Method);
+ VIndex = CGM.getVTables().getMethodVtableIndex(Method);
ContainingType = RecordTy;
}
@@ -662,7 +684,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
if (BI->isVirtual()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
- BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, Base);
+ BaseOffset = 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base);
BFlags = llvm::DIType::FlagVirtual;
} else
BaseOffset = RL.getBaseClassOffset(Base);
@@ -692,10 +714,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) {
ASTContext &Context = CGM.getContext();
/* Function type */
- llvm::SmallVector<llvm::DIDescriptor, 16> STys;
- STys.push_back(getOrCreateType(Context.IntTy, Unit));
- llvm::DIArray SElements =
- DebugFactory.GetOrCreateArray(STys.data(), STys.size());
+ llvm::DIDescriptor STy = getOrCreateType(Context.IntTy, Unit);
+ llvm::DIArray SElements = DebugFactory.GetOrCreateArray(&STy, 1);
llvm::DIType SubTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_subroutine_type,
Unit, "", Unit,
@@ -1048,11 +1068,9 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty,
uint64_t NumElems = Ty->getNumElements();
if (NumElems > 0)
--NumElems;
- llvm::SmallVector<llvm::DIDescriptor, 8> Subscripts;
- Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, NumElems));
- llvm::DIArray SubscriptArray =
- DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size());
+ llvm::DIDescriptor Subscript = DebugFactory.GetOrCreateSubrange(0, NumElems);
+ llvm::DIArray SubscriptArray = DebugFactory.GetOrCreateArray(&Subscript, 1);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
@@ -1208,7 +1226,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
Ty = UnwrapTypeForDebugInfo(Ty);
// Check for existing entry.
- std::map<void *, llvm::WeakVH>::iterator it =
+ llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
// Verify that the debug info still exists.
@@ -1371,13 +1389,10 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
llvm::DIFile Unit = getOrCreateFile(CurLoc);
PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
- llvm::DIDescriptor DR(RegionStack.back());
- llvm::DIScope DS = llvm::DIScope(DR.getNode());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL =
- DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(),
- DS, DO);
- Builder.SetCurrentDebugLocation(DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Builder.SetCurrentDebugLocation(llvm::NewDebugLoc::get(PLoc.getLine(),
+ PLoc.getColumn(),
+ Scope));
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
@@ -1580,11 +1595,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
llvm::Instruction *Call =
DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
- llvm::DIScope DS(RegionStack.back());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL = DebugFactory.CreateLocation(Line, Column, DS, DO);
-
- Call->setMetadata("dbg", DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Call->setDebugLoc(llvm::NewDebugLoc::get(Line, Column, Scope));
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1646,13 +1658,9 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
-
- llvm::DIScope DS(RegionStack.back());
- llvm::DILocation DO(NULL);
- llvm::DILocation DL =
- DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO);
- Call->setMetadata("dbg", DL.getNode());
+ llvm::MDNode *Scope = RegionStack.back();
+ Call->setDebugLoc(llvm::NewDebugLoc::get(Line, PLoc.getColumn(), Scope));
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 47a4620..8397245 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -21,7 +21,6 @@
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/Allocator.h"
-#include <map>
#include "CGBuilder.h"
@@ -52,8 +51,7 @@ class CGDebugInfo {
unsigned FwdDeclCount;
/// TypeCache - Cache of previously constructed Types.
- // FIXME: Eliminate this map. Be careful of iterator invalidation.
- std::map<void *, llvm::WeakVH> TypeCache;
+ llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
@@ -65,6 +63,7 @@ class CGDebugInfo {
/// constructed on demand. For example, C++ destructors, C++ operators etc..
llvm::BumpPtrAllocator DebugInfoNames;
+ llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index dc9ecd6..87ec159 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGCall.h"
+#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -1468,7 +1469,9 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
const FieldDecl* Field,
unsigned CVRQualifiers) {
- CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field);
// FIXME: CodeGenTypes should expose a method to get the appropriate type for
// FieldTy (the appropriate type is ABI-dependent).
@@ -1496,7 +1499,9 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
if (Field->isBitField())
return EmitLValueForBitfield(BaseValue, Field, CVRQualifiers);
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ unsigned idx = RL.getLLVMFieldNo(Field);
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
// Match union field type.
@@ -1531,7 +1536,9 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue,
if (!FieldType->isReferenceType())
return EmitLValueForField(BaseValue, Field, CVRQualifiers);
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
+ unsigned idx = RL.getLLVMFieldNo(Field);
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx, "tmp");
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
@@ -1637,6 +1644,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CastExpr::CK_AnyPointerToObjCPointerCast:
return EmitLValue(E->getSubExpr());
+ case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
@@ -1872,7 +1880,6 @@ LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) {
LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
// Can only get l-value for message expression returning aggregate type
RValue RV = EmitAnyExprToTemp(E);
- // FIXME: can this be volatile?
return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType()));
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 4847ca3..e2e2cd0 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -333,8 +333,7 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
llvm::Value *FuncPtr;
if (MD->isVirtual()) {
- int64_t Index =
- CGF.CGM.getVtableInfo().getMethodVtableIndex(MD);
+ int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD);
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
@@ -500,10 +499,6 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) {
void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
llvm::Value *Val = DestPtr;
- if (!Val) {
- // Create a temporary variable.
- Val = CGF.CreateMemTemp(E->getType(), "tmp");
- }
CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 0328621..d9585c9 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -44,9 +44,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
QualType ResultType = FPT->getResultType();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
- FPT->getCallConv(),
- FPT->getNoReturnAttr()), Callee,
- ReturnValue, Args, MD);
+ FPT->getExtInfo()),
+ Callee, ReturnValue, Args, MD);
}
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
@@ -411,7 +410,8 @@ static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
return CalculateCookiePadding(Ctx, E->getAllocatedType());
}
-static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
+static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
+ CodeGenFunction &CGF,
const CXXNewExpr *E,
llvm::Value *& NumElements) {
QualType Type = E->getAllocatedType();
@@ -432,6 +432,15 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
NumElements =
llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
+ while (const ArrayType *AType = Context.getAsArrayType(Type)) {
+ const llvm::ArrayType *llvmAType =
+ cast<llvm::ArrayType>(CGF.ConvertType(Type));
+ NumElements =
+ CGF.Builder.CreateMul(NumElements,
+ llvm::ConstantInt::get(
+ SizeTy, llvmAType->getNumElements()));
+ Type = AType->getElementType();
+ }
return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity());
}
@@ -444,6 +453,16 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
CGF.Builder.CreateMul(NumElements,
llvm::ConstantInt::get(SizeTy,
TypeSize.getQuantity()));
+
+ while (const ArrayType *AType = Context.getAsArrayType(Type)) {
+ const llvm::ArrayType *llvmAType =
+ cast<llvm::ArrayType>(CGF.ConvertType(Type));
+ NumElements =
+ CGF.Builder.CreateMul(NumElements,
+ llvm::ConstantInt::get(
+ SizeTy, llvmAType->getNumElements()));
+ Type = AType->getElementType();
+ }
// And add the cookie padding if necessary.
if (!CookiePadding.isZero())
@@ -504,7 +523,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
QualType SizeTy = getContext().getSizeType();
llvm::Value *NumElements = 0;
- llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements);
+ llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(),
+ *this, E, NumElements);
NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
@@ -590,10 +610,20 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
CookiePadding.getQuantity());
}
- NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
-
- EmitNewInitializer(*this, E, NewPtr, NumElements);
-
+ if (AllocType->isArrayType()) {
+ while (const ArrayType *AType = getContext().getAsArrayType(AllocType))
+ AllocType = AType->getElementType();
+ NewPtr =
+ Builder.CreateBitCast(NewPtr,
+ ConvertType(getContext().getPointerType(AllocType)));
+ EmitNewInitializer(*this, E, NewPtr, NumElements);
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+ }
+ else {
+ NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
+ EmitNewInitializer(*this, E, NewPtr, NumElements);
+ }
+
if (NullCheckResult) {
Builder.CreateBr(NewEnd);
NewNotNull = Builder.GetInsertBlock();
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 5915340..0a0c914 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -522,13 +522,21 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
// scalar.
OpInfo.Ty = E->getComputationResultType();
OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
-
+
LValue LHSLV = CGF.EmitLValue(E->getLHS());
-
-
// We know the LHS is a complex lvalue.
- OpInfo.LHS=EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
- OpInfo.LHS=EmitComplexToComplexCast(OpInfo.LHS, LHSTy, OpInfo.Ty);
+ ComplexPairTy LHSComplexPair;
+ if (LHSLV.isPropertyRef())
+ LHSComplexPair =
+ CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal();
+ else if (LHSLV.isKVCRef())
+ LHSComplexPair =
+ CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal();
+ else
+ LHSComplexPair = EmitLoadOfComplex(LHSLV.getAddress(),
+ LHSLV.isVolatileQualified());
+
+ OpInfo.LHS=EmitComplexToComplexCast(LHSComplexPair, LHSTy, OpInfo.Ty);
// Expand the binary operator.
ComplexPairTy Result = (this->*Func)(OpInfo);
@@ -537,12 +545,22 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
Result = EmitComplexToComplexCast(Result, OpInfo.Ty, LHSTy);
// Store the result value into the LHS lvalue.
- EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
+ if (LHSLV.isPropertyRef())
+ CGF.EmitObjCPropertySet(LHSLV.getPropertyRefExpr(),
+ RValue::getComplex(Result));
+ else if (LHSLV.isKVCRef())
+ CGF.EmitObjCPropertySet(LHSLV.getKVCRefExpr(), RValue::getComplex(Result));
+ else
+ EmitStoreOfComplex(Result, LHSLV.getAddress(), LHSLV.isVolatileQualified());
// And now return the LHS
IgnoreReal = ignreal;
IgnoreImag = ignimag;
IgnoreRealAssign = ignreal;
IgnoreImagAssign = ignimag;
+ if (LHSLV.isPropertyRef())
+ return CGF.EmitObjCPropertyGet(LHSLV.getPropertyRefExpr()).getComplexVal();
+ else if (LHSLV.isKVCRef())
+ return CGF.EmitObjCPropertyGet(LHSLV.getKVCRefExpr()).getComplexVal();
return EmitLoadOfComplex(LHSLV.getAddress(), LHSLV.isVolatileQualified());
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index f0d82a8..172a77d 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -14,6 +14,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
@@ -417,7 +418,7 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD);
// Itanium C++ ABI 2.3:
// For a non-virtual function, this field is a simple function pointer.
@@ -1011,7 +1012,9 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
E = RD->field_end(); I != E; ++I) {
const FieldDecl *FD = *I;
- unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ const CGRecordLayout &RL =
+ getTypes().getCGRecordLayout(FD->getParent());
+ unsigned FieldNo = RL.getLLVMFieldNo(FD);
Elements[FieldNo] = EmitNullConstant(FD->getType());
}
@@ -1047,7 +1050,9 @@ CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) {
const llvm::StructType *ClassLTy =
cast<llvm::StructType>(getTypes().ConvertType(ClassType));
- unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
+ const CGRecordLayout &RL =
+ getTypes().getCGRecordLayout(FD->getParent());
+ unsigned FieldNo = RL.getLLVMFieldNo(FD);
uint64_t Offset =
getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 7e26971..42bf68e 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -769,6 +769,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
const Expr *E = CE->getSubExpr();
+
+ if (CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase)
+ return false;
if (isa<CXXThisExpr>(E)) {
// We always assume that 'this' is never null.
@@ -826,6 +829,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
NullCheckValue);
}
+ case CastExpr::CK_UncheckedDerivedToBase:
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -1337,6 +1341,11 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFSub(Ops.LHS, Ops.RHS, "sub");
+
+ // Signed integer overflow is undefined behavior.
+ if (Ops.Ty->isSignedIntegerType())
+ return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub");
+
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 3ff77f0..9eaf57c 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -191,7 +191,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
- CC_Default, false),
+ FunctionType::ExtInfo()),
GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
@@ -201,7 +201,12 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
EmitReturnOfRValue(RV, PD->getType());
} else {
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
- if (hasAggregateLLVMType(Ivar->getType())) {
+ if (Ivar->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(),
+ LV.isVolatileQualified());
+ StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
+ }
+ else if (hasAggregateLLVMType(Ivar->getType())) {
EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType());
} else {
CodeGenTypes &Types = CGM.getTypes();
@@ -280,7 +285,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- CC_Default, false), SetPropertyFn,
+ FunctionType::ExtInfo()),
+ SetPropertyFn,
ReturnValueSlot(), Args);
} else {
// FIXME: Find a clean way to avoid AST node creation.
@@ -459,12 +465,13 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
static const unsigned NumItems = 16;
// Get selector
- llvm::SmallVector<IdentifierInfo*, 3> II;
- II.push_back(&CGM.getContext().Idents.get("countByEnumeratingWithState"));
- II.push_back(&CGM.getContext().Idents.get("objects"));
- II.push_back(&CGM.getContext().Idents.get("count"));
- Selector FastEnumSel = CGM.getContext().Selectors.getSelector(II.size(),
- &II[0]);
+ IdentifierInfo *II[] = {
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
+ };
+ Selector FastEnumSel =
+ CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]);
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
@@ -555,7 +562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
- CC_Default, false),
+ FunctionType::ExtInfo()),
EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 119819b..d445200 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -465,7 +465,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -573,7 +573,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -1694,7 +1694,7 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
Params.push_back(ASTIdTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()), false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 475280b..883ed98 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -13,6 +13,7 @@
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
@@ -306,7 +307,8 @@ public:
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -325,7 +327,8 @@ public:
Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -337,7 +340,8 @@ public:
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
const llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
- CC_Default, false), false);
+ FunctionType::ExtInfo()),
+ false);
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -1559,7 +1563,7 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
const llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@@ -3131,8 +3135,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
if (RD) {
+ const CGRecordLayout &RL =
+ CGM.getTypes().getCGRecordLayout(Field->getParent());
if (Field->isBitField()) {
- CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
+ const CGRecordLayout::BitFieldInfo &Info = RL.getBitFieldInfo(Field);
const llvm::Type *Ty =
CGM.getTypes().ConvertTypeForMemRecursive(Field->getType());
@@ -3141,7 +3147,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
FieldOffset = Info.FieldNo * TypeSize;
} else
FieldOffset =
- Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field));
+ Layout->getElementOffset(RL.getLLVMFieldNo(Field));
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
@@ -5094,7 +5100,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
// FIXME. This is too much work to get the ABI-specific result type needed to
// find the message name.
const CGFunctionInfo &FnInfo
- = Types.getFunctionInfo(ResultType, CallArgList(), CC_Default, false);
+ = Types.getFunctionInfo(ResultType, CallArgList(),
+ FunctionType::ExtInfo());
llvm::Constant *Fn = 0;
std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) {
@@ -5169,7 +5176,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
ObjCTypes.MessageRefCPtrTy));
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
- CC_Default, false);
+ FunctionType::ExtInfo());
llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee);
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index ff5d40b..b781940 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -16,7 +16,6 @@
#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
#define CLANG_CODEGEN_OBCJRUNTIME_H
#include "clang/Basic/IdentifierTable.h" // Selector
-#include "llvm/ADT/SmallVector.h"
#include "clang/AST/DeclObjC.h"
#include <string>
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 4907223..1caec97 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -148,7 +148,7 @@ public:
};
/// BuildTypeInfo - Build the RTTI type info struct for the given type.
- llvm::Constant *BuildTypeInfo(QualType Ty);
+ llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
};
}
@@ -327,83 +327,20 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) {
if (ContainsIncompleteClassType(Ty))
return llvm::GlobalValue::InternalLinkage;
- switch (Ty->getTypeClass()) {
- default:
- // FIXME: We need to add code to handle all types.
- assert(false && "Unhandled type!");
- break;
-
- case Type::Pointer: {
- const PointerType *PointerTy = cast<PointerType>(Ty);
-
- // If the pointee type has internal linkage, then the pointer type needs to
- // have it as well.
- if (getTypeInfoLinkage(PointerTy->getPointeeType()) ==
- llvm::GlobalVariable::InternalLinkage)
- return llvm::GlobalVariable::InternalLinkage;
-
- return llvm::GlobalVariable::WeakODRLinkage;
- }
-
- case Type::Enum: {
- const EnumType *EnumTy = cast<EnumType>(Ty);
- const EnumDecl *ED = EnumTy->getDecl();
-
- // If we're in an anonymous namespace, then we always want internal linkage.
- if (ED->isInAnonymousNamespace() || !ED->hasLinkage())
- return llvm::GlobalVariable::InternalLinkage;
-
- return llvm::GlobalValue::WeakODRLinkage;
- }
-
- case Type::Record: {
- const RecordType *RecordTy = cast<RecordType>(Ty);
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
-
- // If we're in an anonymous namespace, then we always want internal linkage.
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
- return llvm::GlobalVariable::InternalLinkage;
-
- // If this class does not have a vtable, we want weak linkage.
- if (!RD->isDynamicClass())
- return llvm::GlobalValue::WeakODRLinkage;
-
- return CodeGenModule::getVtableLinkage(RD);
- }
-
- case Type::Vector:
- case Type::ExtVector:
- case Type::Builtin:
- return llvm::GlobalValue::WeakODRLinkage;
-
- case Type::FunctionProto: {
- const FunctionProtoType *FPT = cast<FunctionProtoType>(Ty);
+ switch (Ty->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return llvm::GlobalValue::InternalLinkage;
- // Check the return type.
- if (getTypeInfoLinkage(FPT->getResultType()) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
-
- // Check the parameter types.
- for (unsigned i = 0; i != FPT->getNumArgs(); ++i) {
- if (getTypeInfoLinkage(FPT->getArgType(i)) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
+ case ExternalLinkage:
+ if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (RD->isDynamicClass())
+ return CodeGenModule::getVtableLinkage(RD);
}
-
- return llvm::GlobalValue::WeakODRLinkage;
- }
-
- case Type::ConstantArray:
- case Type::IncompleteArray: {
- const ArrayType *AT = cast<ArrayType>(Ty);
-
- // Check the element type.
- if (getTypeInfoLinkage(AT->getElementType()) ==
- llvm::GlobalValue::InternalLinkage)
- return llvm::GlobalValue::InternalLinkage;
- }
+ return llvm::GlobalValue::WeakODRLinkage;
}
return llvm::GlobalValue::WeakODRLinkage;
@@ -444,6 +381,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
switch (Ty->getTypeClass()) {
default: assert(0 && "Unhandled type!");
+ case Type::Builtin:
// GCC treats vector types as fundamental types.
case Type::Vector:
case Type::ExtVector:
@@ -511,7 +449,7 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) {
Fields.push_back(Vtable);
}
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
+llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);
@@ -525,7 +463,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy);
// Check if there is already an external RTTI descriptor for this type.
- if (ShouldUseExternalRTTIDescriptor(Ty))
+ if (!Force && ShouldUseExternalRTTIDescriptor(Ty))
return GetAddrOfExternalRTTIDescriptor(Ty);
llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty);
@@ -538,11 +476,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty) {
switch (Ty->getTypeClass()) {
default: assert(false && "Unhandled type class!");
- case Type::Builtin:
- assert(false && "Builtin type info must be in the standard library!");
- break;
// GCC treats vector types as fundamental types.
+ case Type::Builtin:
case Type::Vector:
case Type::ExtVector:
// Itanium C++ ABI 2.9.5p4:
@@ -760,7 +696,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// subobject. For a virtual base, this is the offset in the virtual table of
// the virtual base offset for the virtual base referenced (negative).
if (Base->isVirtual())
- OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ OffsetFlags = CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl);
else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8;
@@ -854,3 +790,61 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) {
return RTTIBuilder(*this).BuildTypeInfo(Ty);
}
+
+// Try to find the magic class __cxxabiv1::__fundamental_type_info. If
+// exists and has a destructor, we will emit the typeinfo for the fundamental
+// types. This is the same behaviour as GCC.
+static CXXRecordDecl *FindMagicClass(ASTContext &AC) {
+ const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1");
+ DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII);
+ TranslationUnitDecl *TUD = AC.getTranslationUnitDecl();
+ DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN);
+ if (NamespaceLookup.first == NamespaceLookup.second)
+ return NULL;
+ const NamespaceDecl *Namespace =
+ dyn_cast<NamespaceDecl>(*NamespaceLookup.first);
+ if (!Namespace)
+ return NULL;
+
+ const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info");
+ DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII);
+ DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN);
+ if (ClassLookup.first == ClassLookup.second)
+ return NULL;
+ CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(*ClassLookup.first);
+
+ if (Class->hasDefinition() && Class->isDynamicClass() &&
+ Class->getDestructor(AC))
+ return Class;
+
+ return NULL;
+}
+
+void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
+ QualType PointerType = Context.getPointerType(Type);
+ QualType PointerTypeConst = Context.getPointerType(Type.withConst());
+ RTTIBuilder(*this).BuildTypeInfo(Type, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
+ RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
+}
+
+void CodeGenModule::EmitFundamentalRTTIDescriptors() {
+ CXXRecordDecl *RD = FindMagicClass(getContext());
+ if (!RD)
+ return;
+
+ getVTables().GenerateClassData(getVtableLinkage(RD), RD);
+
+ QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty,
+ Context.Char16Ty, Context.UnsignedLongLongTy,
+ Context.LongLongTy, Context.WCharTy,
+ Context.UnsignedShortTy, Context.ShortTy,
+ Context.UnsignedLongTy, Context.LongTy,
+ Context.UnsignedIntTy, Context.IntTy,
+ Context.UnsignedCharTy, Context.FloatTy,
+ Context.LongDoubleTy, Context.DoubleTy,
+ Context.CharTy, Context.BoolTy,
+ Context.SignedCharTy };
+ for (unsigned i = 0; i < sizeof(FundamentalTypes)/sizeof(QualType); ++i)
+ EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
+}
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
new file mode 100644
index 0000000..d0d8f98
--- /dev/null
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -0,0 +1,95 @@
+//===--- CGRecordLayout.h - LLVM Record Layout Information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGRECORDLAYOUT_H
+#define CLANG_CODEGEN_CGRECORDLAYOUT_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+namespace llvm {
+ class Type;
+}
+
+namespace clang {
+namespace CodeGen {
+
+/// CGRecordLayout - This class handles struct and union layout info while
+/// lowering AST types to LLVM types.
+///
+/// These layout objects are only created on demand as IR generation requires.
+class CGRecordLayout {
+ friend class CodeGenTypes;
+
+ CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT
+ void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
+
+public:
+ struct BitFieldInfo {
+ BitFieldInfo(unsigned FieldNo,
+ unsigned Start,
+ unsigned Size)
+ : FieldNo(FieldNo), Start(Start), Size(Size) {}
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
+ };
+
+private:
+ /// The LLVMType corresponding to this record layout.
+ const llvm::Type *LLVMType;
+
+ /// Map from (non-bit-field) struct field to the corresponding llvm struct
+ /// type field no. This info is populated by record builder.
+ llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
+
+ /// Map from (bit-field) struct field to the corresponding llvm struct type
+ /// field no. This info is populated by record builder.
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields;
+
+ /// Whether one of the fields in this record layout is a pointer to data
+ /// member, or a struct that contains pointer to data member.
+ bool ContainsPointerToDataMember : 1;
+
+public:
+ CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
+ : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) {}
+
+ /// \brief Return the LLVM type associated with this record.
+ const llvm::Type *getLLVMType() const {
+ return LLVMType;
+ }
+
+ /// \brief Check whether this struct contains pointers to data members.
+ bool containsPointerToDataMember() const {
+ return ContainsPointerToDataMember;
+ }
+
+ /// \brief Return the BitFieldInfo that corresponds to the field FD.
+ unsigned getLLVMFieldNo(const FieldDecl *FD) const {
+ assert(!FD->isBitField() && "Invalid call for bit-field decl!");
+ assert(FieldInfo.count(FD) && "Invalid field for record!");
+ return FieldInfo.lookup(FD);
+ }
+
+ /// \brief Return llvm::StructType element number that corresponds to the
+ /// field FD.
+ const BitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
+ assert(FD->isBitField() && "Invalid call for non bit-field decl!");
+ llvm::DenseMap<const FieldDecl *, BitFieldInfo>::const_iterator
+ it = BitFields.find(FD);
+ assert(it != BitFields.end() && "Unable to find bitfield info");
+ return it->second;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index baafd68..daebabd 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -1,4 +1,4 @@
-//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===//
+//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,25 +7,131 @@
//
//===----------------------------------------------------------------------===//
//
-// This is a helper class used to build CGRecordLayout objects and LLVM types.
+// Builder implementation for CGRecordLayout objects.
//
//===----------------------------------------------------------------------===//
-#include "CGRecordLayoutBuilder.h"
-
+#include "CGRecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "CodeGenTypes.h"
+#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"
-
-
using namespace clang;
using namespace CodeGen;
+namespace clang {
+namespace CodeGen {
+
+class CGRecordLayoutBuilder {
+public:
+ /// FieldTypes - Holds the LLVM types that the struct is created from.
+ std::vector<const llvm::Type *> FieldTypes;
+
+ /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
+ typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
+ llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
+
+ /// LLVMBitFieldInfo - Holds location and size information about a bit field.
+ struct LLVMBitFieldInfo {
+ LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start,
+ unsigned Size)
+ : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { }
+
+ const FieldDecl *FD;
+
+ unsigned FieldNo;
+ unsigned Start;
+ unsigned Size;
+ };
+ llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+
+ /// ContainsPointerToDataMember - Whether one of the fields in this record
+ /// layout is a pointer to data member, or a struct that contains pointer to
+ /// data member.
+ bool ContainsPointerToDataMember;
+
+ /// Packed - Whether the resulting LLVM struct will be packed or not.
+ bool Packed;
+
+private:
+ CodeGenTypes &Types;
+
+ /// Alignment - Contains the alignment of the RecordDecl.
+ //
+ // FIXME: This is not needed and should be removed.
+ unsigned Alignment;
+
+ /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
+ /// LLVM types.
+ unsigned AlignmentAsLLVMStruct;
+
+ /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
+ /// this will have the number of bits still available in the field.
+ char BitsAvailableInLastField;
+
+ /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
+ uint64_t NextFieldOffsetInBytes;
+
+ /// LayoutUnion - Will layout a union RecordDecl.
+ void LayoutUnion(const RecordDecl *D);
+
+ /// LayoutField - try to layout all fields in the record decl.
+ /// Returns false if the operation failed because the struct is not packed.
+ bool LayoutFields(const RecordDecl *D);
+
+ /// LayoutBases - layout the bases and vtable pointer of a record decl.
+ void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
+
+ /// LayoutField - layout a single field. Returns false if the operation failed
+ /// because the current struct is not packed.
+ bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// LayoutBitField - layout a single bit field.
+ void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
+
+ /// AppendField - Appends a field with the given offset and type.
+ void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
+
+ /// AppendPadding - Appends enough padding bytes so that the total struct
+ /// size matches the alignment of the passed in type.
+ void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
+
+ /// AppendPadding - Appends enough padding bytes so that the total
+ /// struct size is a multiple of the field alignment.
+ void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
+
+ /// AppendBytes - Append a given number of bytes to the record.
+ void AppendBytes(uint64_t NumBytes);
+
+ /// AppendTailPadding - Append enough tail padding so that the type will have
+ /// the passed size.
+ void AppendTailPadding(uint64_t RecordSize);
+
+ unsigned getTypeAlignment(const llvm::Type *Ty) const;
+ uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
+
+ /// CheckForPointerToDataMember - Check if the given type contains a pointer
+ /// to data member.
+ void CheckForPointerToDataMember(QualType T);
+
+public:
+ CGRecordLayoutBuilder(CodeGenTypes &Types)
+ : ContainsPointerToDataMember(false), Packed(false), Types(Types),
+ Alignment(0), AlignmentAsLLVMStruct(1),
+ BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
+
+ /// Layout - Will layout a RecordDecl.
+ void Layout(const RecordDecl *D);
+};
+
+}
+}
+
void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
Packed = D->hasAttr<PackedAttr>();
@@ -110,7 +216,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// Check if we have a pointer to data member in this field.
CheckForPointerToDataMember(D->getType());
-
+
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
uint64_t FieldOffsetInBytes = FieldOffset / 8;
@@ -166,7 +272,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
unsigned Align = 0;
bool HasOnlyZeroSizedBitFields = true;
-
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
@@ -182,12 +288,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
continue;
// Add the bit field info.
- Types.addBitFieldInfo(*Field, 0, 0, FieldSize);
- } else
- Types.addFieldInfo(*Field, 0);
+ LLVMBitFields.push_back(LLVMBitFieldInfo(*Field, 0, 0, FieldSize));
+ } else {
+ LLVMFields.push_back(LLVMFieldInfo(*Field, 0));
+ }
HasOnlyZeroSizedBitFields = false;
-
+
const llvm::Type *FieldTy =
Types.ConvertTypeForMemRecursive(Field->getType());
unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
@@ -218,7 +325,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
"0-align record did not have all zero-sized bit-fields!");
Align = 1;
}
-
+
// Append tail padding.
if (Layout.getSize() / 8 > Size)
AppendPadding(Layout.getSize() / 8, Align);
@@ -228,9 +335,9 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) {
// Check if we need to add a vtable pointer.
if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
- const llvm::Type *Int8PtrTy =
+ const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(Types.getLLVMContext());
-
+
assert(NextFieldOffsetInBytes == 0 &&
"Vtable pointer must come first!");
AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
@@ -245,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
LayoutBases(RD, Layout);
-
+
unsigned FieldNo = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
@@ -269,14 +376,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
uint64_t RecordSizeInBytes = RecordSize / 8;
assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
- uint64_t AlignedNextFieldOffset =
+ uint64_t AlignedNextFieldOffset =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);
if (AlignedNextFieldOffset == RecordSizeInBytes) {
// We don't need any padding.
return;
}
-
+
unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
AppendBytes(NumPadBytes);
}
@@ -359,46 +466,49 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
}
} else if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
+
// FIXME: It would be better if there was a way to explicitly compute the
// record layout instead of converting to a type.
Types.ConvertTagDeclType(RD);
-
+
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
-
+
if (Layout.containsPointerToDataMember())
ContainsPointerToDataMember = true;
- }
+ }
}
-CGRecordLayout *
-CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
- const RecordDecl *D) {
- CGRecordLayoutBuilder Builder(Types);
+CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
+ CGRecordLayoutBuilder Builder(*this);
Builder.Layout(D);
- const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(),
+ const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),
Builder.FieldTypes,
Builder.Packed);
- assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 ==
- Types.getTargetData().getTypeAllocSize(Ty) &&
+ assert(getContext().getASTRecordLayout(D).getSize() / 8 ==
+ getTargetData().getTypeAllocSize(Ty) &&
"Type size mismatch!");
+ CGRecordLayout *RL =
+ new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
+
// Add all the field numbers.
for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) {
const FieldDecl *FD = Builder.LLVMFields[i].first;
unsigned FieldNo = Builder.LLVMFields[i].second;
- Types.addFieldInfo(FD, FieldNo);
+ RL->FieldInfo.insert(std::make_pair(FD, FieldNo));
}
// Add bitfield info.
for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) {
- const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i];
+ const CGRecordLayoutBuilder::LLVMBitFieldInfo &Info =
+ Builder.LLVMBitFields[i];
- Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
+ CGRecordLayout::BitFieldInfo BFI(Info.FieldNo, Info.Start, Info.Size);
+ RL->BitFields.insert(std::make_pair(Info.FD, BFI));
}
- return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
+ return RL;
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h
deleted file mode 100644
index eb60ed7..0000000
--- a/lib/CodeGen/CGRecordLayoutBuilder.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This is a helper class used to build CGRecordLayout objects and LLVM types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
-#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/System/DataTypes.h"
-#include <vector>
-
-namespace llvm {
- class Type;
-}
-
-namespace clang {
- class ASTRecordLayout;
- class CXXRecordDecl;
- class FieldDecl;
- class RecordDecl;
- class QualType;
-
-namespace CodeGen {
- class CGRecordLayout;
- class CodeGenTypes;
-
-class CGRecordLayoutBuilder {
- CodeGenTypes &Types;
-
- /// Packed - Whether the resulting LLVM struct will be packed or not.
- bool Packed;
-
- /// ContainsPointerToDataMember - Whether one of the fields in this record
- /// layout is a pointer to data member, or a struct that contains pointer to
- /// data member.
- bool ContainsPointerToDataMember;
-
- /// Alignment - Contains the alignment of the RecordDecl.
- unsigned Alignment;
-
- /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
- /// LLVM types.
- unsigned AlignmentAsLLVMStruct;
-
- /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
- /// this will have the number of bits still available in the field.
- char BitsAvailableInLastField;
-
- /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
- uint64_t NextFieldOffsetInBytes;
-
- /// FieldTypes - Holds the LLVM types that the struct is created from.
- std::vector<const llvm::Type *> FieldTypes;
-
- /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
- typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
- llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
-
- /// LLVMBitFieldInfo - Holds location and size information about a bit field.
- struct LLVMBitFieldInfo {
- LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start,
- unsigned Size)
- : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { }
-
- const FieldDecl *FD;
-
- unsigned FieldNo;
- unsigned Start;
- unsigned Size;
- };
- llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
-
- CGRecordLayoutBuilder(CodeGenTypes &Types)
- : Types(Types), Packed(false), ContainsPointerToDataMember(false)
- , Alignment(0), AlignmentAsLLVMStruct(1)
- , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
-
- /// Layout - Will layout a RecordDecl.
- void Layout(const RecordDecl *D);
-
- /// LayoutUnion - Will layout a union RecordDecl.
- void LayoutUnion(const RecordDecl *D);
-
- /// LayoutField - try to layout all fields in the record decl.
- /// Returns false if the operation failed because the struct is not packed.
- bool LayoutFields(const RecordDecl *D);
-
- /// LayoutBases - layout the bases and vtable pointer of a record decl.
- void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
-
- /// LayoutField - layout a single field. Returns false if the operation failed
- /// because the current struct is not packed.
- bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// LayoutBitField - layout a single bit field.
- void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// AppendField - Appends a field with the given offset and type.
- void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
-
- /// AppendPadding - Appends enough padding bytes so that the total struct
- /// size matches the alignment of the passed in type.
- void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
-
- /// AppendPadding - Appends enough padding bytes so that the total
- /// struct size is a multiple of the field alignment.
- void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
-
- /// AppendBytes - Append a given number of bytes to the record.
- void AppendBytes(uint64_t NumBytes);
-
- /// AppendTailPadding - Append enough tail padding so that the type will have
- /// the passed size.
- void AppendTailPadding(uint64_t RecordSize);
-
- unsigned getTypeAlignment(const llvm::Type *Ty) const;
- uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
-
- /// CheckForPointerToDataMember - Check if the given type contains a pointer
- /// to data member.
- void CheckForPointerToDataMember(QualType T);
-
-public:
- /// ComputeLayout - Return the right record layout for a given record decl.
- static CGRecordLayout *ComputeLayout(CodeGenTypes &Types,
- const RecordDecl *D);
-};
-
-} // end namespace CodeGen
-} // end namespace clang
-
-
-#endif
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a889e55..ae2f791 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -607,7 +607,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (FnRetTy->isReferenceType()) {
// If this function returns a reference, take the address of the expression
// rather than the value.
- Builder.CreateStore(EmitLValue(RV).getAddress(), ReturnValue);
+ RValue Result = EmitReferenceBindingToExpr(RV, false);
+ Builder.CreateStore(Result.getScalarVal(), ReturnValue);
} else if (!hasAggregateLLVMType(RV->getType())) {
Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
} else if (RV->getType()->isAnyComplexType()) {
diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp
index bed8439..6d38ab9 100644
--- a/lib/CodeGen/CGTemporaries.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -127,15 +127,14 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
size_t CleanupStackDepth = CleanupEntries.size();
(void) CleanupStackDepth;
- unsigned OldNumLiveTemporaries = LiveTemporaries.size();
-
- RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
- /*IgnoreResult=*/false, IsInitializer);
-
- // Pop temporaries.
- while (LiveTemporaries.size() > OldNumLiveTemporaries)
- PopCXXTemporary();
+ RValue RV;
+
+ {
+ CXXTemporariesCleanupScope Scope(*this);
+ RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile,
+ /*IgnoreResult=*/false, IsInitializer);
+ }
assert(CleanupEntries.size() == CleanupStackDepth &&
"Cleanup size mismatch!");
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index 96c104b..91d9f76 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -19,283 +19,355 @@ using namespace CodeGen;
#define D1(x)
namespace {
+
+/// VTT builder - Class for building VTT layout information.
class VTTBuilder {
- /// Inits - The list of values built for the VTT.
- std::vector<llvm::Constant *> &Inits;
- /// Class - The most derived class that this vtable is being built for.
- const CXXRecordDecl *Class;
- CodeGenModule &CGM; // Per-module state.
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
- /// BLayout - Layout for the most derived class that this vtable is being
- /// built for.
- const ASTRecordLayout &BLayout;
- CGVtableInfo::AddrMap_t &AddressPoints;
- // vtbl - A pointer to the vtable for Class.
- llvm::Constant *ClassVtbl;
- llvm::LLVMContext &VMContext;
-
- /// SeenVBasesInSecondary - The seen virtual bases when building the
- /// secondary virtual pointers.
- llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary;
+
+ CodeGenModule &CGM;
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ typedef llvm::SmallVector<llvm::Constant *, 64> VTTComponentsVectorTy;
- bool GenerateDefinition;
+ /// VTTComponents - The VTT components.
+ VTTComponentsVectorTy VTTComponents;
+
+ /// MostDerivedClassLayout - the AST record layout of the most derived class.
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
- llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
- llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
- CtorVtableAddressPoints;
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
+
+ /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived
+ /// class.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of
+ /// all subobjects of the most derived class.
+ llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices;
+
+ /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for
+ /// the VTT.
+ bool GenerateDefinition;
- llvm::Constant *getCtorVtable(const BaseSubobject &Base,
- bool BaseIsVirtual) {
- if (!GenerateDefinition)
- return 0;
-
- llvm::Constant *&CtorVtable = CtorVtables[Base];
- if (!CtorVtable) {
- // Build the vtable.
- CGVtableInfo::CtorVtableInfo Info
- = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseIsVirtual);
-
- CtorVtable = Info.Vtable;
-
- // Add the address points for this base.
- for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
- Info.AddressPoints.begin(), E = Info.AddressPoints.end();
- I != E; ++I) {
- uint64_t &AddressPoint =
- CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
-
- // Check if we already have the address points for this base.
- if (AddressPoint)
- break;
-
- // Otherwise, insert it.
- AddressPoint = I->second;
- }
- }
-
- return CtorVtable;
+ /// GetAddrOfVTable - Returns the address of the vtable for the base class in
+ /// the given vtable class.
+ ///
+ /// \param AddressPoints - If the returned vtable is a construction vtable,
+ /// this will hold the address points for it.
+ llvm::Constant *GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
+ AddressPointsMapTy& AddressPoints);
+
+ /// AddVTablePointer - Add a vtable pointer to the VTT currently being built.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints);
+
+ /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base
+ /// subobject.
+ void LayoutSecondaryVTTs(BaseSubobject Base);
+
+ /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
+ /// for the given base subobject.
+ ///
+ /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
+ /// for the given base subobject.
+ ///
+ /// \param AddressPoints - If the vtable is a construction vtable, this has
+ /// the address points for it.
+ void LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ llvm::Constant *VTable,
+ const AddressPointsMapTy& AddressPoints);
+
+ /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the
+ /// given record decl.
+ void LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases);
+
+ /// LayoutVTT - Will lay out the VTT for the given subobject, including any
+ /// secondary VTTs, secondary virtual pointers and virtual VTTs.
+ void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual);
+
+public:
+ VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition);
+
+ // getVTTComponents - Returns a reference to the VTT components.
+ const VTTComponentsVectorTy &getVTTComponents() const {
+ return VTTComponents;
}
+ /// getSubVTTIndicies - Returns a reference to the sub-VTT indices.
+ const llvm::DenseMap<const CXXRecordDecl *, uint64_t> &
+ getSubVTTIndicies() const {
+ return SubVTTIndicies;
+ }
- /// BuildVtablePtr - Build up a referene to the given secondary vtable
- llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
- const CXXRecordDecl *VtableClass,
- const CXXRecordDecl *RD,
- uint64_t Offset) {
- if (!GenerateDefinition)
- return 0;
-
- uint64_t AddressPoint;
-
- if (VtableClass != Class) {
- // We have a ctor vtable, look for the address point in the ctor vtable
- // address points.
- AddressPoint =
- CtorVtableAddressPoints[std::make_pair(VtableClass,
- BaseSubobject(RD, Offset))];
- } else {
- AddressPoint =
- (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)];
- }
+ /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary
+ /// virtual pointer indices.
+ const llvm::DenseMap<BaseSubobject, uint64_t> &
+ getSecondaryVirtualPointerIndices() const {
+ return SecondaryVirtualPointerIndices;
+ }
- // FIXME: We can never have 0 address point. Do this for now so gepping
- // retains the same structure. Later we'll just assert.
- if (AddressPoint == 0)
- AddressPoint = 1;
- D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
- RD->getNameAsCString(), VtblClass->getNameAsCString(),
- Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
-
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0),
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint)
- };
+};
+
+VTTBuilder::VTTBuilder(CodeGenModule &CGM,
+ const CXXRecordDecl *MostDerivedClass,
+ bool GenerateDefinition)
+ : CGM(CGM), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)),
+ GenerateDefinition(GenerateDefinition) {
- llvm::Constant *Init =
- llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2);
+ // Lay out this VTT.
+ LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false);
+}
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+llvm::Constant *
+VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual,
+ AddressPointsMapTy& AddressPoints) {
+ if (!GenerateDefinition)
+ return 0;
+
+ if (Base.getBase() == MostDerivedClass) {
+ assert(Base.getBaseOffset() == 0 &&
+ "Most derived class vtable must have a zero offset!");
+ // This is a regular vtable.
+ return CGM.getVTables().GetAddrOfVTable(MostDerivedClass);
}
+
+ return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass,
+ Base, BaseIsVirtual,
+ AddressPoints);
+}
- /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
- /// current offset in bits to the object we're working on.
- void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl,
- const CXXRecordDecl *VtblClass, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- if (RD->getNumVBases() == 0 && ! MorallyVirtual)
- return;
-
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
- // We only want to visit each virtual base once.
- if (i->isVirtual() && SeenVBasesInSecondary.count(Base))
- continue;
-
- // Itanium C++ ABI 2.6.2:
- // Secondary virtual pointers are present for all bases with either
- // virtual bases or virtual function declarations overridden along a
- // virtual path.
- //
- // If the base class is not dynamic, we don't want to add it, nor any
- // of its base classes.
- if (!Base->isDynamicClass())
- continue;
+void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints) {
+ // Store the vtable pointer index if we're generating the primary VTT.
+ if (VTableClass == MostDerivedClass) {
+ assert(!SecondaryVirtualPointerIndices.count(Base) &&
+ "A virtual pointer index already exists for this base subobject!");
+ SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
+ }
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
- bool NonVirtualPrimaryBase;
- NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
- bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
- uint64_t BaseOffset;
- if (!i->isVirtual()) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- } else
- BaseOffset = BLayout.getVBaseClassOffset(Base);
- llvm::Constant *subvtbl = vtbl;
- const CXXRecordDecl *subVtblClass = VtblClass;
- if ((Base->getNumVBases() || BaseMorallyVirtual)
- && !NonVirtualPrimaryBase) {
- llvm::Constant *init;
- if (BaseMorallyVirtual || VtblClass == Class)
- init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset);
- else {
- init = getCtorVtable(BaseSubobject(Base, BaseOffset), i->isVirtual());
-
- subvtbl = init;
- subVtblClass = Base;
-
- init = BuildVtablePtr(init, Class, Base, BaseOffset);
- }
-
- Inits.push_back(init);
- }
-
- if (i->isVirtual())
- SeenVBasesInSecondary.insert(Base);
-
- Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual);
- }
+ if (!GenerateDefinition) {
+ VTTComponents.push_back(0);
+ return;
}
- /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
- /// currnet object we're working on.
- void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool BaseIsVirtual,
- bool MorallyVirtual) {
- // Itanium C++ ABI 2.6.2:
- // An array of virtual table addresses, called the VTT, is declared for
- // each class type that has indirect or direct virtual base classes.
- if (RD->getNumVBases() == 0)
- return;
+ uint64_t AddressPoint;
+ if (VTableClass != MostDerivedClass) {
+ // The vtable is a construction vtable, look in the construction vtable
+ // address points.
+ AddressPoint = AddressPoints.lookup(Base);
+ } else {
+ // Just get the address point for the regular vtable.
+ AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass);
+ }
- // Remember the sub-VTT index.
- SubVTTIndicies[RD] = Inits.size();
+ if (!AddressPoint) AddressPoint = 0;
+ assert(AddressPoint != 0 && "Did not find an address point!");
+
+ llvm::Value *Idxs[] = {
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0),
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()),
+ AddressPoint)
+ };
+
+ llvm::Constant *Init =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Idxs, 2);
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+
+ VTTComponents.push_back(Init);
+}
- llvm::Constant *Vtable;
- const CXXRecordDecl *VtableClass;
+void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
- // First comes the primary virtual table pointer...
- if (MorallyVirtual) {
- Vtable = ClassVtbl;
- VtableClass = Class;
- } else {
- Vtable = getCtorVtable(BaseSubobject(RD, Offset),
- /*IsVirtual=*/BaseIsVirtual);
- VtableClass = RD;
- }
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
- llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
- Inits.push_back(Init);
-
- // then the secondary VTTs....
- SecondaryVTTs(RD, Offset, MorallyVirtual);
+ // Don't layout virtual bases.
+ if (I->isVirtual())
+ continue;
- // Make sure to clear the set of seen virtual bases.
- SeenVBasesInSecondary.clear();
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- // and last the secondary vtable pointers.
- Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual);
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = Base.getBaseOffset() +
+ Layout.getBaseClassOffset(BaseDecl);
+
+ // Layout the VTT for this base.
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
}
+}
+
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ const AddressPointsMapTy& AddressPoints,
+ VisitedVirtualBasesSetTy &VBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // We're not interested in bases that don't have virtual bases, and not
+ // morally virtual bases.
+ if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
+ return;
- /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
- /// built from each direct non-virtual proper base that requires a VTT in
- /// declaration order.
- void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual())
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers are present for all bases with either
+ // virtual bases or virtual function declarations overridden along a
+ // virtual path.
+ //
+ // If the base class is not dynamic, we don't want to add it, nor any
+ // of its base classes.
+ if (!BaseDecl->isDynamicClass())
+ continue;
+
+ bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
+ bool BaseDeclIsNonVirtualPrimaryBase = false;
+ uint64_t BaseOffset;
+ if (I->isVirtual()) {
+ // Ignore virtual bases that we've already visited.
+ if (!VBases.insert(BaseDecl))
continue;
+
+ BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ BaseDeclIsMorallyVirtual = true;
+ } else {
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/false, MorallyVirtual);
+ BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl);
+
+ if (!Layout.getPrimaryBaseWasVirtual() &&
+ Layout.getPrimaryBase() == BaseDecl)
+ BaseDeclIsNonVirtualPrimaryBase = true;
}
- }
- /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
- /// graph preorder.
- void VirtualVTTs(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual() && !SeenVBase.count(Base)) {
- SeenVBase.insert(Base);
- uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/true, false);
- }
- VirtualVTTs(Base);
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers: for each base class X which (a) has virtual
+ // bases or is reachable along a virtual path from D, and (b) is not a
+ // non-virtual primary base, the address of the virtual table for X-in-D
+ // or an appropriate construction virtual table.
+ if (!BaseDeclIsNonVirtualPrimaryBase &&
+ (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
+ // Add the vtable pointer.
+ AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass,
+ AddressPoints);
}
+
+ // And lay out the secondary virtual pointers for the base class.
+ LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
+ BaseDeclIsMorallyVirtual, VTable,
+ VTableClass, AddressPoints, VBases);
}
+}
-public:
- VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm, bool GenerateDefinition)
- : Inits(inits), Class(c), CGM(cgm),
- BLayout(cgm.getContext().getASTRecordLayout(c)),
- AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
- VMContext(cgm.getModule().getContext()),
- GenerateDefinition(GenerateDefinition) {
-
- // First comes the primary virtual table pointer for the complete class...
- ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0;
+void
+VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
+ llvm::Constant *VTable,
+ const AddressPointsMapTy& AddressPoints) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
+ VTable, Base.getBase(), AddressPoints, VBases);
+}
- llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0);
- Inits.push_back(Init);
+void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
+ VisitedVirtualBasesSetTy &VBases) {
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- // then the secondary VTTs...
- SecondaryVTTs(Class);
+ // Check if this is a virtual base.
+ if (I->isVirtual()) {
+ // Check if we've seen this base before.
+ if (!VBases.insert(BaseDecl))
+ continue;
+
+ uint64_t BaseOffset =
+ MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+
+ LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
+ }
+
+ // We only need to layout virtual VTTs for this base if it actually has
+ // virtual bases.
+ if (BaseDecl->getNumVBases())
+ LayoutVirtualVTTs(BaseDecl, VBases);
+ }
+}
- // Make sure to clear the set of seen virtual bases.
- SeenVBasesInSecondary.clear();
+void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
+ const CXXRecordDecl *RD = Base.getBase();
- // then the secondary vtable pointers...
- Secondary(Class, ClassVtbl, Class);
+ // Itanium C++ ABI 2.6.2:
+ // An array of virtual table addresses, called the VTT, is declared for
+ // each class type that has indirect or direct virtual base classes.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
- // and last, the virtual VTTs.
- VirtualVTTs(Class);
+ if (!IsPrimaryVTT) {
+ // Remember the sub-VTT index.
+ SubVTTIndicies[RD] = VTTComponents.size();
}
+
+ AddressPointsMapTy AddressPoints;
+ llvm::Constant *VTable = GetAddrOfVTable(Base, BaseIsVirtual, AddressPoints);
+
+ // Add the primary vtable pointer.
+ AddVTablePointer(Base, VTable, RD, AddressPoints);
+
+ // Add the secondary VTTs.
+ LayoutSecondaryVTTs(Base);
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
- return SubVTTIndicies;
+ // Add the secondary virtual pointers.
+ LayoutSecondaryVirtualPointers(Base, VTable, AddressPoints);
+
+ // If this is the primary VTT, we want to lay out virtual VTTs as well.
+ if (IsPrimaryVTT) {
+ VisitedVirtualBasesSetTy VBases;
+ LayoutVirtualVTTs(Base.getBase(), VBases);
}
-};
+}
+
}
llvm::GlobalVariable *
-CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition,
- const CXXRecordDecl *RD) {
+CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
+ const CXXRecordDecl *RD) {
// Only classes that have virtual bases need a VTT.
if (RD->getNumVBases() == 0)
return 0;
@@ -311,13 +383,15 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+ VTTBuilder Builder(CGM, RD, GenerateDefinition);
+
+ const llvm::ArrayType *Type =
+ llvm::ArrayType::get(Int8PtrTy, Builder.getVTTComponents().size());
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
llvm::Constant *Init = 0;
if (GenerateDefinition)
- Init = llvm::ConstantArray::get(Type, inits);
+ Init = llvm::ConstantArray::get(Type, Builder.getVTTComponents().data(),
+ Builder.getVTTComponents().size());
llvm::GlobalVariable *OldGV = GV;
GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
@@ -336,26 +410,12 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
return GV;
}
-CGVtableInfo::CtorVtableInfo
-CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
- const BaseSubobject &Base, bool BaseIsVirtual) {
- CtorVtableInfo Info;
-
- Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
- /*GenerateDefinition=*/true,
- RD, Base.getBase(), Base.getBaseOffset(),
- BaseIsVirtual, Info.AddressPoints);
- return Info;
-}
-
-llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+llvm::GlobalVariable *CodeGenVTables::getVTT(const CXXRecordDecl *RD) {
return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
/*GenerateDefinition=*/false, RD);
-
}
-
-bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
+bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
// We don't have any virtual bases, just return early.
@@ -373,19 +433,17 @@ bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
return false;
}
-uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *Base) {
+uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
ClassPairTy ClassPair(RD, Base);
- SubVTTIndiciesTy::iterator I =
- SubVTTIndicies.find(ClassPair);
+ SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair);
if (I != SubVTTIndicies.end())
return I->second;
- std::vector<llvm::Constant *> inits;
- VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+ VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I =
Builder.getSubVTTIndicies().begin(),
E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
// Insert all indices.
@@ -399,3 +457,31 @@ uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
return I->second;
}
+
+uint64_t
+CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
+ BaseSubobject Base) {
+ SecondaryVirtualPointerIndicesMapTy::iterator I =
+ SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
+
+ if (I != SecondaryVirtualPointerIndices.end())
+ return I->second;
+
+ VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
+
+ // Insert all secondary vpointer indices.
+ for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
+ Builder.getSecondaryVirtualPointerIndices().begin(),
+ E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) {
+ std::pair<const CXXRecordDecl *, BaseSubobject> Pair =
+ std::make_pair(RD, I->first);
+
+ SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second));
+ }
+
+ I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
+ assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!");
+
+ return I->second;
+}
+
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index df30f47..2d1c734 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -138,7 +138,7 @@ private:
/// AddOverriders - Add the final overriders for this base subobject to the
/// map of final overriders.
- void AddOverriders(BaseSubobject Base,uint64_t OffsetInLayoutClass,
+ void AddOverriders(BaseSubobject Base, uint64_t OffsetInLayoutClass,
SubobjectOffsetsMapTy &Offsets);
/// PropagateOverrider - Propagate the NewMD overrider to all the functions
@@ -636,6 +636,10 @@ public:
reinterpret_cast<uintptr_t>(MD));
}
+ static VtableComponent getFromOpaqueInteger(uint64_t I) {
+ return VtableComponent(I);
+ }
+
/// getKind - Get the kind of this vtable component.
Kind getKind() const {
return (Kind)(Value & 0x7);
@@ -725,6 +729,9 @@ private:
return static_cast<uintptr_t>(Value & ~7ULL);
}
+ explicit VtableComponent(uint64_t Value)
+ : Value(Value) { }
+
/// The kind is stored in the lower 3 bits of the value. For offsets, we
/// make use of the facts that classes can't be larger than 2^55 bytes,
/// so we store the offset in the lower part of the 61 bytes that remain.
@@ -1091,9 +1098,15 @@ public:
typedef llvm::SmallSetVector<const CXXRecordDecl *, 8>
PrimaryBasesSetVectorTy;
+ typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
+ VBaseOffsetOffsetsMapTy;
+
+ typedef llvm::DenseMap<BaseSubobject, uint64_t>
+ AddressPointsMapTy;
+
private:
- /// VtableInfo - Global vtable information.
- CGVtableInfo &VtableInfo;
+ /// VTables - Global vtable information.
+ CodeGenVTables &VTables;
/// MostDerivedClass - The most derived class for which we're building this
/// vtable.
@@ -1122,9 +1135,6 @@ private:
/// bases in this vtable.
llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
- typedef llvm::DenseMap<const CXXRecordDecl *, int64_t>
- VBaseOffsetOffsetsMapTy;
-
/// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for
/// the most derived class.
VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
@@ -1133,29 +1143,8 @@ private:
llvm::SmallVector<VtableComponent, 64> Components;
/// AddressPoints - Address points for the vtable being built.
- CGVtableInfo::AddressPointsMapTy AddressPoints;
-
- /// ReturnAdjustment - A return adjustment.
- struct ReturnAdjustment {
- /// NonVirtual - The non-virtual adjustment from the derived object to its
- /// nearest virtual base.
- int64_t NonVirtual;
-
- /// VBaseOffsetOffset - The offset (in bytes), relative to the address point
- /// of the virtual base class offset.
- int64_t VBaseOffsetOffset;
-
- ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
-
- bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
+ AddressPointsMapTy AddressPoints;
- friend bool operator==(const ReturnAdjustment &LHS,
- const ReturnAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
- }
- };
-
/// MethodInfo - Contains information about a method in a vtable.
/// (Used for computing 'this' pointer adjustment thunks.
struct MethodInfo {
@@ -1185,62 +1174,21 @@ private:
/// currently building.
MethodInfoMapTy MethodInfoMap;
- /// ThisAdjustment - A 'this' pointer adjustment thunk.
- struct ThisAdjustment {
- /// NonVirtual - The non-virtual adjustment from the derived object to its
- /// nearest virtual base.
- int64_t NonVirtual;
-
- /// VCallOffsetOffset - The offset (in bytes), relative to the address point,
- /// of the virtual call offset.
- int64_t VCallOffsetOffset;
-
- ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
-
- bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
-
- friend bool operator==(const ThisAdjustment &LHS,
- const ThisAdjustment &RHS) {
- return LHS.NonVirtual == RHS.NonVirtual &&
- LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
- }
- };
-
- /// ThunkInfo - The 'this' pointer adjustment as well as an optional return
- /// adjustment for a thunk.
- struct ThunkInfo {
- /// This - The 'this' pointer adjustment.
- ThisAdjustment This;
-
- /// Return - The return adjustment.
- ReturnAdjustment Return;
-
- ThunkInfo() { }
-
- ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
- : This(This), Return(Return) { }
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy;
- friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
- return LHS.This == RHS.This && LHS.Return == RHS.Return;
- }
+ /// VTableThunks - The thunks by vtable index in the vtable currently being
+ /// built.
+ VtableThunksMapTy VTableThunks;
- bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
- };
-
- typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy;
+ typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
- /// Thunks - The thunks by vtable index in the vtable currently being built.
- ThunksInfoMapTy Thunks;
-
- typedef llvm::DenseMap<const CXXMethodDecl *,
- llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy;
-
- /// MethodThunks - A map that contains all the thunks needed for all methods
- /// in the vtable currently being built.
- MethodThunksMapTy MethodThunks;
+ /// Thunks - A map that contains all the thunks needed for all methods in the
+ /// most derived class for which the vtable is currently being built.
+ ThunksMapTy Thunks;
/// AddThunk - Add a thunk for the given method.
- void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk);
+ void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk);
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
/// part of the vtable we're currently building.
@@ -1341,10 +1289,10 @@ private:
}
public:
- VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass,
+ VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass,
uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass)
- : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass),
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
MostDerivedClassOffset(MostDerivedClassOffset),
MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
@@ -1353,15 +1301,57 @@ public:
LayoutVtable();
}
+ ThunksMapTy::const_iterator thunks_begin() const {
+ return Thunks.begin();
+ }
+
+ ThunksMapTy::const_iterator thunks_end() const {
+ return Thunks.end();
+ }
+
+ const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
+ return VBaseOffsetOffsets;
+ }
+
+ /// getNumVTableComponents - Return the number of components in the vtable
+ /// currently built.
+ uint64_t getNumVTableComponents() const {
+ return Components.size();
+ }
+
+ const uint64_t *vtable_components_data_begin() const {
+ return reinterpret_cast<const uint64_t *>(Components.begin());
+ }
+
+ const uint64_t *vtable_components_data_end() const {
+ return reinterpret_cast<const uint64_t *>(Components.end());
+ }
+
+ AddressPointsMapTy::const_iterator address_points_begin() const {
+ return AddressPoints.begin();
+ }
+
+ AddressPointsMapTy::const_iterator address_points_end() const {
+ return AddressPoints.end();
+ }
+
+ VtableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ return VTableThunks.begin();
+ }
+
+ VtableThunksMapTy::const_iterator vtable_thunks_end() const {
+ return VTableThunks.end();
+ }
+
/// dumpLayout - Dump the vtable layout.
void dumpLayout(llvm::raw_ostream&);
};
-void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) {
- if (isBuildingConstructorVtable())
- return;
+void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ assert(!isBuildingConstructorVtable() &&
+ "Can't add thunks for construction vtable");
- llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+ llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
// Check if we have this thunk already.
if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
@@ -1410,6 +1400,17 @@ void VtableBuilder::ComputeThisAdjustments() {
Overriders.getOverrider(BaseSubobject(MD->getParent(),
MethodInfo.BaseOffset), MD);
+ // Check if we need an adjustment at all.
+ if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
+ // When a return thunk is needed by a derived class that overrides a
+ // virtual base, gcc uses a virtual 'this' adjustment as well.
+ // While the thunk itself might be needed by vtables in subclasses or
+ // in construction vtables, there doesn't seem to be a reason for using
+ // the thunk in this vtable. Still, we do so to match gcc.
+ if (VTableThunks.lookup(VtableIndex).Return.isEmpty())
+ continue;
+ }
+
ThisAdjustment ThisAdjustment =
ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
@@ -1417,22 +1418,48 @@ void VtableBuilder::ComputeThisAdjustments() {
continue;
// Add it.
- Thunks[VtableIndex].This = ThisAdjustment;
+ VTableThunks[VtableIndex].This = ThisAdjustment;
if (isa<CXXDestructorDecl>(MD)) {
// Add an adjustment for the deleting destructor as well.
- Thunks[VtableIndex + 1].This = ThisAdjustment;
+ VTableThunks[VtableIndex + 1].This = ThisAdjustment;
}
-
- AddThunk(Overrider.Method, Thunks[VtableIndex]);
}
/// Clear the method info map.
MethodInfoMap.clear();
+
+ if (isBuildingConstructorVtable()) {
+ // We don't need to store thunk information for construction vtables.
+ return;
+ }
+
+ for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(),
+ E = VTableThunks.end(); I != E; ++I) {
+ const VtableComponent &Component = Components[I->first];
+ const ThunkInfo &Thunk = I->second;
+ const CXXMethodDecl *MD;
+
+ switch (Component.getKind()) {
+ default:
+ llvm_unreachable("Unexpected vtable component kind!");
+ case VtableComponent::CK_FunctionPointer:
+ MD = Component.getFunctionDecl();
+ break;
+ case VtableComponent::CK_CompleteDtorPointer:
+ MD = Component.getDestructorDecl();
+ break;
+ case VtableComponent::CK_DeletingDtorPointer:
+ // We've already added the thunk when we saw the complete dtor pointer.
+ continue;
+ }
+
+ if (MD->getParent() == MostDerivedClass)
+ AddThunk(MD, Thunk);
+ }
}
-VtableBuilder::ReturnAdjustment
-VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1444,8 +1471,8 @@ VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
VBaseOffsetOffsets.lookup(Offset.VirtualBase);
} else {
Adjustment.VBaseOffsetOffset =
- VtableInfo.getVirtualBaseOffsetOffset(Offset.DerivedClass,
- Offset.VirtualBase);
+ VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
+ Offset.VirtualBase);
}
// FIXME: Once the assert in getVirtualBaseOffsetOffset is back again,
@@ -1512,14 +1539,10 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
return BaseOffset();
}
-VtableBuilder::ThisAdjustment
+ThisAdjustment
VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
uint64_t BaseOffsetInLayoutClass,
FinalOverriders::OverriderInfo Overrider) {
- // Check if we need an adjustment at all.
- if (BaseOffsetInLayoutClass == Overrider.Offset)
- return ThisAdjustment();
-
// Ignore adjustments for pure virtual member functions.
if (Overrider.Method->isPure())
return ThisAdjustment();
@@ -1576,7 +1599,7 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
- Thunks[Components.size()].Return = ReturnAdjustment;
+ VTableThunks[Components.size()].Return = ReturnAdjustment;
// Add the function.
Components.push_back(VtableComponent::MakeFunction(MD));
@@ -1776,6 +1799,25 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass,
MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
MethodInfoMap.erase(OverriddenMD);
+
+ // If the overridden method exists in a virtual base class or a direct
+ // or indirect base class of a virtual base class, we need to emit a
+ // thunk if we ever have a class hierarchy where the base class is not
+ // a primary base in the complete object.
+ if (!isBuildingConstructorVtable() && OverriddenMD != MD) {
+ // Compute the this adjustment.
+ ThisAdjustment ThisAdjustment =
+ ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
+ Overrider);
+
+ if (ThisAdjustment.VCallOffsetOffset &&
+ Overrider.Method->getParent() == MostDerivedClass) {
+ // This is a virtual thunk for the most derived class, add it.
+ AddThunk(Overrider.Method,
+ ThunkInfo(ThisAdjustment, ReturnAdjustment()));
+ }
+ }
+
continue;
}
}
@@ -1866,20 +1908,32 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base,
// Compute 'this' pointer adjustments.
ComputeThisAdjustments();
- // Record the address point.
- AddressPoints.insert(std::make_pair(BaseSubobject(Base.getBase(),
- OffsetInLayoutClass),
- AddressPoint));
-
- // Record the address points for all primary bases.
- for (PrimaryBasesSetVectorTy::const_iterator I = PrimaryBases.begin(),
- E = PrimaryBases.end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = *I;
+ // Add all address points.
+ const CXXRecordDecl *RD = Base.getBase();
+ while (true) {
+ AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
+ AddressPoint));
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- // We know that all the primary bases have the same offset as the base
- // subobject.
- BaseSubobject PrimaryBase(BaseDecl, OffsetInLayoutClass);
- AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint));
+ if (!PrimaryBase)
+ break;
+
+ if (Layout.getPrimaryBaseWasVirtual()) {
+ // Check if this virtual primary base is a primary base in the layout
+ // class. If it's not, we don't want to add it.
+ const ASTRecordLayout &LayoutClassLayout =
+ Context.getASTRecordLayout(LayoutClass);
+
+ if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) !=
+ OffsetInLayoutClass) {
+ // We don't want to add this class (or any of its primary bases).
+ break;
+ }
+ }
+
+ RD = PrimaryBase;
}
bool BaseIsMorallyVirtual = BaseIsVirtual;
@@ -2062,8 +2116,8 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
// Since an address point can be shared by multiple subobjects, we use an
// STL multimap.
std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
- for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
- AddressPoints.begin(), E = AddressPoints.end(); I != E; ++I) {
+ for (AddressPointsMapTy::const_iterator I = AddressPoints.begin(),
+ E = AddressPoints.end(); I != E; ++I) {
const BaseSubobject& Base = I->first;
uint64_t Index = I->second;
@@ -2106,7 +2160,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (MD->isPure())
Out << " [pure]";
- ThunkInfo Thunk = Thunks.lookup(I);
+ ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this function pointer has a return adjustment, dump it.
if (!Thunk.Return.isEmpty()) {
@@ -2154,7 +2208,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
if (DD->isPure())
Out << " [pure]";
- ThunkInfo Thunk = Thunks.lookup(I);
+ ThunkInfo Thunk = VTableThunks.lookup(I);
if (!Thunk.isEmpty()) {
// If this destructor has a 'this' pointer adjustment, dump it.
if (!Thunk.This.isEmpty()) {
@@ -2253,13 +2307,12 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << "\n";
}
- if (!MethodThunks.empty()) {
-
+ if (!Thunks.empty()) {
// We store the method names in a map to get a stable order.
std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
- for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(),
- E = MethodThunks.end(); I != E; ++I) {
+ for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
+ I != E; ++I) {
const CXXMethodDecl *MD = I->first;
std::string MethodName =
PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual,
@@ -2273,7 +2326,9 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
I != E; ++I) {
const std::string &MethodName = I->first;
const CXXMethodDecl *MD = I->second;
- const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD];
+
+ ThunkInfoVectorTy ThunksVector = Thunks[MD];
+ std::sort(ThunksVector.begin(), ThunksVector.end());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2283,1099 +2338,42 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
Out << llvm::format("%4d | ", I);
+ // If this function pointer has a return pointer adjustment, dump it.
+ if (!Thunk.Return.isEmpty()) {
+ Out << "return adjustment: " << Thunk.This.NonVirtual;
+ Out << " non-virtual";
+ if (Thunk.Return.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ Out << " vbase offset offset";
+ }
+
+ if (!Thunk.This.isEmpty())
+ Out << "\n ";
+ }
+
// If this function pointer has a 'this' pointer adjustment, dump it.
if (!Thunk.This.isEmpty()) {
- Out << "this: ";
- Out << Thunk.This.NonVirtual << " nv";
+ Out << "this adjustment: ";
+ Out << Thunk.This.NonVirtual << " non-virtual";
if (Thunk.This.VCallOffsetOffset) {
Out << ", " << Thunk.This.VCallOffsetOffset;
- Out << " v";
+ Out << " vcall offset offset";
}
}
Out << '\n';
}
- }
- }
-}
-
-}
-
-namespace {
-class OldVtableBuilder {
-public:
- /// Index_t - Vtable index type.
- typedef uint64_t Index_t;
- typedef std::vector<std::pair<GlobalDecl,
- std::pair<GlobalDecl, ThunkAdjustment> > >
- SavedAdjustmentsVectorTy;
-private:
-
- // VtableComponents - The components of the vtable being built.
- typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy;
- VtableComponentsVectorTy VtableComponents;
-
- const bool BuildVtable;
-
- llvm::Type *Ptr8Ty;
-
- /// MostDerivedClass - The most derived class that this vtable is being
- /// built for.
- const CXXRecordDecl *MostDerivedClass;
-
- /// LayoutClass - The most derived class used for virtual base layout
- /// information.
- const CXXRecordDecl *LayoutClass;
- /// LayoutOffset - The offset for Class in LayoutClass.
- uint64_t LayoutOffset;
- /// BLayout - Layout for the most derived class that this vtable is being
- /// built for.
- const ASTRecordLayout &BLayout;
- llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary;
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
- llvm::Constant *rtti;
- llvm::LLVMContext &VMContext;
- CodeGenModule &CGM; // Per-module state.
-
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
- llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
- llvm::DenseMap<GlobalDecl, Index_t> VCallOffsetForVCall;
- // This is the offset to the nearest virtual base
- llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset;
- llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
-
- /// PureVirtualFunction - Points to __cxa_pure_virtual.
- llvm::Constant *PureVirtualFn;
-
- /// VtableMethods - A data structure for keeping track of methods in a vtable.
- /// Can add methods, override methods and iterate in vtable order.
- class VtableMethods {
- // MethodToIndexMap - Maps from a global decl to the index it has in the
- // Methods vector.
- llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap;
-
- /// Methods - The methods, in vtable order.
- typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy;
- MethodsVectorTy Methods;
- MethodsVectorTy OrigMethods;
-
- public:
- /// AddMethod - Add a method to the vtable methods.
- void AddMethod(GlobalDecl GD) {
- assert(!MethodToIndexMap.count(GD) &&
- "Method has already been added!");
-
- MethodToIndexMap[GD] = Methods.size();
- Methods.push_back(GD);
- OrigMethods.push_back(GD);
- }
-
- /// OverrideMethod - Replace a method with another.
- void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) {
- llvm::DenseMap<GlobalDecl, uint64_t>::iterator i
- = MethodToIndexMap.find(OverriddenGD);
- assert(i != MethodToIndexMap.end() && "Did not find entry!");
-
- // Get the index of the old decl.
- uint64_t Index = i->second;
-
- // Replace the old decl with the new decl.
- Methods[Index] = GD;
-
- // And add the new.
- MethodToIndexMap[GD] = Index;
- }
-
- /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if
- /// the index couldn't be found.
- bool getIndex(GlobalDecl GD, uint64_t &Index) const {
- llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i
- = MethodToIndexMap.find(GD);
-
- if (i == MethodToIndexMap.end())
- return false;
-
- Index = i->second;
- return true;
- }
-
- GlobalDecl getOrigMethod(uint64_t Index) const {
- return OrigMethods[Index];
- }
-
- MethodsVectorTy::size_type size() const {
- return Methods.size();
- }
-
- void clear() {
- MethodToIndexMap.clear();
- Methods.clear();
- OrigMethods.clear();
- }
-
- GlobalDecl operator[](uint64_t Index) const {
- return Methods[Index];
- }
- };
-
- /// Methods - The vtable methods we're currently building.
- VtableMethods Methods;
-
- /// ThisAdjustments - For a given index in the vtable, contains the 'this'
- /// pointer adjustment needed for a method.
- typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy;
- ThisAdjustmentsMapTy ThisAdjustments;
-
- SavedAdjustmentsVectorTy SavedAdjustments;
-
- /// BaseReturnTypes - Contains the base return types of methods who have been
- /// overridden with methods whose return types require adjustment. Used for
- /// generating covariant thunk information.
- typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy;
- BaseReturnTypesMapTy BaseReturnTypes;
-
- std::vector<Index_t> VCalls;
-
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- // subAddressPoints - Used to hold the AddressPoints (offsets) into the built
- // vtable for use in computing the initializers for the VTT.
- llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints;
-
- /// AddressPoints - Address points for this vtable.
- CGVtableInfo::AddressPointsMapTy& AddressPoints;
-
- typedef CXXRecordDecl::method_iterator method_iter;
- const uint32_t LLVMPointerWidth;
- Index_t extra;
- typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
- static llvm::DenseMap<CtorVtable_t, int64_t>&
- AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
- const CXXRecordDecl *c) {
- CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l];
- if (oref == 0)
- oref = new CGVtableInfo::AddrMap_t;
-
- llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
- if (ref == 0)
- ref = new llvm::DenseMap<CtorVtable_t, int64_t>;
- return *ref;
- }
-
- bool DclIsSame(const FunctionDecl *New, const FunctionDecl *Old) {
- FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
- FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
-
- // C++ [temp.fct]p2:
- // A function template can be overloaded with other function templates
- // and with normal (non-template) functions.
- if ((OldTemplate == 0) != (NewTemplate == 0))
- return false;
-
- // Is the function New an overload of the function Old?
- QualType OldQType = CGM.getContext().getCanonicalType(Old->getType());
- QualType NewQType = CGM.getContext().getCanonicalType(New->getType());
-
- // Compare the signatures (C++ 1.3.10) of the two functions to
- // determine whether they are overloads. If we find any mismatch
- // in the signature, they are overloads.
-
- // If either of these functions is a K&R-style function (no
- // prototype), then we consider them to have matching signatures.
- if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) ||
- isa<FunctionNoProtoType>(NewQType.getTypePtr()))
- return true;
-
- FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
- FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
-
- // The signature of a function includes the types of its
- // parameters (C++ 1.3.10), which includes the presence or absence
- // of the ellipsis; see C++ DR 357).
- if (OldQType != NewQType &&
- (OldType->getNumArgs() != NewType->getNumArgs() ||
- OldType->isVariadic() != NewType->isVariadic() ||
- !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(),
- NewType->arg_type_begin())))
- return false;
-
-#if 0
- // C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
- // signature, its return type and its template parameter list. The names
- // of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
- // signature.
- //
- // We check the return type and template parameter lists for function
- // templates first; the remaining checks follow.
- if (NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- TPL_TemplateMatch) ||
- OldType->getResultType() != NewType->getResultType()))
- return false;
-#endif
-
- // If the function is a class member, its signature includes the
- // cv-qualifiers (if any) on the function itself.
- //
- // As part of this, also check whether one of the member functions
- // is static, in which case they are not overloads (C++
- // 13.1p2). While not part of the definition of the signature,
- // this check is important to determine whether these functions
- // can be overloaded.
- const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
- !OldMethod->isStatic() && !NewMethod->isStatic() &&
- OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers())
- return false;
-
- // The signatures match; this is not an overload.
- return true;
- }
-
- typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl*>
- ForwardUnique_t;
- ForwardUnique_t ForwardUnique;
- llvm::DenseMap<const CXXMethodDecl*, const CXXMethodDecl*> UniqueOverrider;
-
- void BuildUniqueOverrider(const CXXMethodDecl *U, const CXXMethodDecl *MD) {
- const CXXMethodDecl *PrevU = UniqueOverrider[MD];
- assert(U && "no unique overrider");
- if (PrevU == U)
- return;
- if (PrevU != U && PrevU != 0) {
- // If already set, note the two sets as the same
- if (0)
- printf("%s::%s same as %s::%s\n",
- PrevU->getParent()->getNameAsString().c_str(),
- PrevU->getNameAsString().c_str(),
- U->getParent()->getNameAsString().c_str(),
- U->getNameAsString().c_str());
- ForwardUnique[PrevU] = U;
- return;
- }
-
- // Not set, set it now
- if (0)
- printf("marking %s::%s %p override as %s::%s\n",
- MD->getParent()->getNameAsString().c_str(),
- MD->getNameAsString().c_str(),
- (void*)MD,
- U->getParent()->getNameAsString().c_str(),
- U->getNameAsString().c_str());
- UniqueOverrider[MD] = U;
-
- for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
- me = MD->end_overridden_methods(); mi != me; ++mi) {
- BuildUniqueOverrider(U, *mi);
- }
- }
-
- void BuildUniqueOverriders(const CXXRecordDecl *RD) {
- if (0) printf("walking %s\n", RD->getNameAsCString());
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
- if (!MD->isVirtual())
- continue;
-
- if (UniqueOverrider[MD] == 0) {
- // Only set this, if it hasn't been set yet.
- BuildUniqueOverrider(MD, MD);
- if (0)
- printf("top set is %s::%s %p\n",
- MD->getParent()->getNameAsString().c_str(),
- MD->getNameAsString().c_str(),
- (void*)MD);
- ForwardUnique[MD] = MD;
- }
- }
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- BuildUniqueOverriders(Base);
- }
- }
-
- static int DclCmp(const void *p1, const void *p2) {
- const CXXMethodDecl *MD1 = *(const CXXMethodDecl *const *)p1;
- const CXXMethodDecl *MD2 = *(const CXXMethodDecl *const *)p2;
-
- return (DeclarationName::compare(MD1->getDeclName(), MD2->getDeclName()));
- }
-
- void MergeForwarding() {
- typedef llvm::SmallVector<const CXXMethodDecl *, 100> A_t;
- A_t A;
- for (ForwardUnique_t::iterator I = ForwardUnique.begin(),
- E = ForwardUnique.end(); I != E; ++I) {
- if (I->first == I->second)
- // Only add the roots of all trees
- A.push_back(I->first);
- }
- llvm::array_pod_sort(A.begin(), A.end(), DclCmp);
- for (A_t::iterator I = A.begin(),
- E = A.end(); I != E; ++I) {
- A_t::iterator J = I;
- while (++J != E && DclCmp(I, J) == 0)
- if (DclIsSame(*I, *J)) {
- if (0) printf("connecting %s\n", (*I)->getNameAsString().c_str());
- ForwardUnique[*J] = *I;
- }
- }
- }
-
- const CXXMethodDecl *getUnique(const CXXMethodDecl *MD) {
- const CXXMethodDecl *U = UniqueOverrider[MD];
- assert(U && "unique overrider not found");
- while (ForwardUnique.count(U)) {
- const CXXMethodDecl *NU = ForwardUnique[U];
- if (NU == U) break;
- U = NU;
- }
- return U;
- }
-
- GlobalDecl getUnique(GlobalDecl GD) {
- const CXXMethodDecl *Unique = getUnique(cast<CXXMethodDecl>(GD.getDecl()));
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Unique))
- return GlobalDecl(CD, GD.getCtorType());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Unique))
- return GlobalDecl(DD, GD.getDtorType());
-
- return Unique;
- }
-
- /// getPureVirtualFn - Return the __cxa_pure_virtual function.
- llvm::Constant* getPureVirtualFn() {
- if (!PureVirtualFn) {
- const llvm::FunctionType *Ty =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- /*isVarArg=*/false);
- PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"));
- }
-
- return PureVirtualFn;
- }
-
-public:
- OldVtableBuilder(const CXXRecordDecl *MostDerivedClass,
- const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm,
- bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints)
- : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l),
- LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)),
- rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm),
- PureVirtualFn(0),
- subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)),
- AddressPoints(AddressPoints),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0))
- {
- Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
- if (BuildVtable) {
- QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass);
- rtti = CGM.GetAddrOfRTTIDescriptor(ClassType);
- }
- BuildUniqueOverriders(MostDerivedClass);
- MergeForwarding();
- }
-
- // getVtableComponents - Returns a reference to the vtable components.
- const VtableComponentsVectorTy &getVtableComponents() const {
- return VtableComponents;
- }
-
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex()
- { return VBIndex; }
-
- SavedAdjustmentsVectorTy &getSavedAdjustments()
- { return SavedAdjustments; }
-
- llvm::Constant *wrap(Index_t i) {
- llvm::Constant *m;
- m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
- return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
- }
-
- llvm::Constant *wrap(llvm::Constant *m) {
- return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
- }
-
-//#define D1(x)
-#define D1(X) do { if (getenv("CLANG_VTABLE_DEBUG")) { X; } } while (0)
-
- void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
- bool updateVBIndex, Index_t current_vbindex) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- Index_t next_vbindex = current_vbindex;
- if (i->isVirtual() && !SeenVBase.count(Base)) {
- SeenVBase.insert(Base);
- if (updateVBIndex) {
- next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8)
- - 3*LLVMPointerWidth/8);
- VBIndex[Base] = next_vbindex;
- }
- int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
- VCalls.push_back((0?700:0) + BaseOffset);
- D1(printf(" vbase for %s at %d delta %d most derived %s\n",
- Base->getNameAsCString(),
- (int)-VCalls.size()-3, (int)BaseOffset,
- MostDerivedClass->getNameAsCString()));
- }
- // We also record offsets for non-virtual bases to closest enclosing
- // virtual base. We do this so that we don't have to search
- // for the nearst virtual base class when generating thunks.
- if (updateVBIndex && VBIndex.count(Base) == 0)
- VBIndex[Base] = next_vbindex;
- GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex);
- }
- }
-
- void StartNewTable() {
- SeenVBase.clear();
- }
-
- Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B,
- Index_t Offset = 0) {
-
- if (B == D)
- return Offset;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D);
- for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(),
- e = D->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- int64_t BaseOffset = 0;
- if (!i->isVirtual())
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- int64_t o = getNVOffset_1(Base, B, BaseOffset);
- if (o >= 0)
- return o;
- }
-
- return -1;
- }
-
- /// getNVOffset - Returns the non-virtual offset for the given (B) base of the
- /// derived class D.
- Index_t getNVOffset(QualType qB, QualType qD) {
- qD = qD->getPointeeType();
- qB = qB->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- int64_t o = getNVOffset_1(D, B);
- if (o >= 0)
- return o;
-
- assert(false && "FIXME: non-virtual base not found");
- return 0;
- }
-
- /// getVbaseOffset - Returns the index into the vtable for the virtual base
- /// offset for the given (B) virtual base of the derived class D.
- Index_t getVbaseOffset(QualType qB, QualType qD) {
- qD = qD->getPointeeType();
- qB = qB->getPointeeType();
- CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
- CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
- if (D != MostDerivedClass)
- return CGM.getVtableInfo().getVirtualBaseOffsetOffset(D, B);
- llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
- i = VBIndex.find(B);
- if (i != VBIndex.end())
- return i->second;
-
- assert(false && "FIXME: Base not found");
- return 0;
- }
-
- bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
- Index_t OverrideOffset, Index_t Offset,
- int64_t CurrentVBaseOffset);
-
- /// AppendMethods - Append the current methods to the vtable.
- void AppendMethodsToVtable();
-
- llvm::Constant *WrapAddrOf(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
-
- return wrap(CGM.GetAddrOfFunction(GD, Ty));
- }
-
- void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
- int64_t CurrentVBaseOffset) {
- for (Path_t::reverse_iterator i = Path->rbegin(),
- e = Path->rend(); i != e; ++i) {
- const CXXRecordDecl *RD = i->first;
- int64_t OverrideOffset = i->second;
- for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- const CXXMethodDecl *MD = *mi;
-
- if (!MD->isVirtual())
- continue;
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Override both the complete and the deleting destructor.
- GlobalDecl CompDtor(DD, Dtor_Complete);
- OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
-
- GlobalDecl DeletingDtor(DD, Dtor_Deleting);
- OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
- } else {
- OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset,
- CurrentVBaseOffset);
- }
- }
- }
- }
-
- void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
- int64_t CurrentVBaseOffset) {
- // If we can find a previously allocated slot for this, reuse it.
- if (OverrideMethod(GD, MorallyVirtual, Offset, Offset,
- CurrentVBaseOffset))
- return;
-
- D1(printf(" vfn for %s at %d\n",
- dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(),
- (int)Methods.size()));
-
- // We didn't find an entry in the vtable that we could use, add a new
- // entry.
- Methods.AddMethod(GD);
-
- VCallOffset[GD] = Offset/8 - CurrentVBaseOffset/8;
-
- if (MorallyVirtual) {
- GlobalDecl UGD = getUnique(GD);
- const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
-
- assert(UMD && "final overrider not found");
-
- Index_t &idx = VCall[UMD];
- // Allocate the first one, after that, we reuse the previous one.
- if (idx == 0) {
- VCallOffsetForVCall[UGD] = Offset/8;
- NonVirtualOffset[UMD] = Offset/8 - CurrentVBaseOffset/8;
- idx = VCalls.size()+1;
- VCalls.push_back(Offset/8 - CurrentVBaseOffset/8);
- D1(printf(" vcall for %s at %d with delta %d\n",
- dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(),
- (int)-VCalls.size()-3, (int)VCalls[idx-1]));
- }
- }
- }
-
- void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, int64_t CurrentVBaseOffset) {
- for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- const CXXMethodDecl *MD = *mi;
- if (!MD->isVirtual())
- continue;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // For destructors, add both the complete and the deleting destructor
- // to the vtable.
- AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
- CurrentVBaseOffset);
- AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
- CurrentVBaseOffset);
- } else
- AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
- }
+ Out << '\n';
- void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase,
- bool PrimaryBaseWasVirtual, bool MorallyVirtual,
- int64_t Offset, int64_t CurrentVBaseOffset,
- Path_t *Path) {
- Path->push_back(std::make_pair(RD, Offset));
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- if (i->isVirtual())
- continue;
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- uint64_t o = Offset + Layout.getBaseClassOffset(Base);
- StartNewTable();
- GenerateVtableForBase(Base, o, MorallyVirtual, false,
- true, Base == PrimaryBase && !PrimaryBaseWasVirtual,
- CurrentVBaseOffset, Path);
}
- Path->pop_back();
}
-
-// #define D(X) do { X; } while (0)
-#define D(X)
-
- void insertVCalls(int InsertionPoint) {
- D1(printf("============= combining vbase/vcall\n"));
- D(VCalls.insert(VCalls.begin(), 673));
- D(VCalls.push_back(672));
-
- VtableComponents.insert(VtableComponents.begin() + InsertionPoint,
- VCalls.size(), 0);
- if (BuildVtable) {
- // The vcalls come first...
- for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(),
- e = VCalls.rend();
- i != e; ++i)
- VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i);
- }
- VCalls.clear();
- VCall.clear();
- VCallOffsetForVCall.clear();
- VCallOffset.clear();
- NonVirtualOffset.clear();
- }
-
- void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
- Index_t AddressPoint) {
- D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
- LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
- AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
-
- // Now also add the address point for all our primary bases.
- while (1) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- RD = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
- // FIXME: Double check this.
- if (RD == 0)
- break;
- if (PrimaryBaseWasVirtual &&
- BLayout.getVBaseClassOffset(RD) != Offset)
- break;
- D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
- LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
- subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
- AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
- }
- }
-
-
- void FinishGenerateVtable(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout,
- const CXXRecordDecl *PrimaryBase,
- bool ForNPNVBases, bool WasPrimaryBase,
- bool PrimaryBaseWasVirtual,
- bool MorallyVirtual, int64_t Offset,
- bool ForVirtualBase, int64_t CurrentVBaseOffset,
- Path_t *Path) {
- bool alloc = false;
- if (Path == 0) {
- alloc = true;
- Path = new Path_t;
- }
-
- StartNewTable();
- extra = 0;
- Index_t AddressPoint = 0;
- int VCallInsertionPoint = 0;
- if (!ForNPNVBases || !WasPrimaryBase) {
- bool DeferVCalls = MorallyVirtual || ForVirtualBase;
- VCallInsertionPoint = VtableComponents.size();
- if (!DeferVCalls) {
- insertVCalls(VCallInsertionPoint);
- } else
- // FIXME: just for extra, or for all uses of VCalls.size post this?
- extra = -VCalls.size();
-
- // Add the offset to top.
- VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0);
-
- // Add the RTTI information.
- VtableComponents.push_back(rtti);
-
- AddressPoint = VtableComponents.size();
-
- AppendMethodsToVtable();
- }
-
- // and then the non-virtual bases.
- NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, CurrentVBaseOffset, Path);
-
- if (ForVirtualBase) {
- // FIXME: We're adding to VCalls in callers, we need to do the overrides
- // in the inner part, so that we know the complete set of vcalls during
- // the build and don't have to insert into methods. Saving out the
- // AddressPoint here, would need to be fixed, if we didn't do that. Also
- // retroactively adding vcalls for overrides later wind up in the wrong
- // place, the vcall slot has to be alloted during the walk of the base
- // when the function is first introduces.
- AddressPoint += VCalls.size();
- insertVCalls(VCallInsertionPoint);
- }
-
- if (!ForNPNVBases || !WasPrimaryBase)
- AddAddressPoints(RD, Offset, AddressPoint);
-
- if (alloc) {
- delete Path;
- }
- }
-
- void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
- bool updateVBIndex, Index_t current_vbindex,
- int64_t CurrentVBaseOffset) {
- if (!RD->isDynamicClass())
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- // vtables are composed from the chain of primaries.
- if (PrimaryBase && !PrimaryBaseWasVirtual) {
- D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
- Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, CurrentVBaseOffset);
- }
-
- D1(printf(" doing vcall entries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- // And add the virtuals for the class to the primary vtable.
- AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
-
- void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
- bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, int64_t CurrentVBaseOffset,
- bool bottom) {
- if (!RD->isDynamicClass())
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- // vtables are composed from the chain of primaries.
- if (PrimaryBase) {
- int BaseCurrentVBaseOffset = CurrentVBaseOffset;
- if (PrimaryBaseWasVirtual) {
- IndirectPrimary.insert(PrimaryBase);
- BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
- }
-
- D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset, false);
- }
-
- D1(printf(" doing vbase entries for %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
- GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex);
-
- if (RDisVirtualBase || bottom) {
- Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- CurrentVBaseOffset);
- }
- }
-
- void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
- bool MorallyVirtual = false,
- bool ForVirtualBase = false,
- bool ForNPNVBases = false,
- bool WasPrimaryBase = true,
- int CurrentVBaseOffset = 0,
- Path_t *Path = 0) {
- if (!RD->isDynamicClass())
- return;
-
- // Construction vtable don't need parts that have no virtual bases and
- // aren't morally virtual.
- if ((LayoutClass != MostDerivedClass) &&
- RD->getNumVBases() == 0 && !MorallyVirtual)
- return;
-
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
-
- extra = 0;
- D1(printf("building entries for base %s most derived %s\n",
- RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
-
- if (ForVirtualBase)
- extra = VCalls.size();
-
- if (!ForNPNVBases || !WasPrimaryBase) {
- VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0,
- ForVirtualBase, CurrentVBaseOffset, true);
-
- if (Path)
- OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
- }
-
- FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase,
- PrimaryBaseWasVirtual, MorallyVirtual, Offset,
- ForVirtualBase, CurrentVBaseOffset, Path);
- }
-
- void GenerateVtableForVBases(const CXXRecordDecl *RD,
- int64_t Offset = 0,
- Path_t *Path = 0) {
- bool alloc = false;
- if (Path == 0) {
- alloc = true;
- Path = new Path_t;
- }
- // FIXME: We also need to override using all paths to a virtual base,
- // right now, we just process the first path
- Path->push_back(std::make_pair(RD, Offset));
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual() && !IndirectPrimary.count(Base)) {
- // Mark it so we don't output it twice.
- IndirectPrimary.insert(Base);
- StartNewTable();
- VCall.clear();
- int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- int64_t CurrentVBaseOffset = BaseOffset;
- D1(printf("vtable %s virtual base %s\n",
- MostDerivedClass->getNameAsCString(), Base->getNameAsCString()));
- GenerateVtableForBase(Base, BaseOffset, true, true, false,
- true, CurrentVBaseOffset, Path);
- }
- int64_t BaseOffset;
- if (i->isVirtual())
- BaseOffset = BLayout.getVBaseClassOffset(Base);
- else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- }
-
- if (Base->getNumVBases()) {
- GenerateVtableForVBases(Base, BaseOffset, Path);
- }
- }
- Path->pop_back();
- if (alloc)
- delete Path;
- }
-};
-} // end anonymous namespace
-
-bool OldVtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
- Index_t OverrideOffset, Index_t Offset,
- int64_t CurrentVBaseOffset) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- const bool isPure = MD->isPure();
-
- // FIXME: Should OverrideOffset's be Offset?
-
- for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods(); mi != e; ++mi) {
- GlobalDecl OGD;
- GlobalDecl OGD2;
-
- const CXXMethodDecl *OMD = *mi;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
- OGD = GlobalDecl(DD, GD.getDtorType());
- else
- OGD = OMD;
-
- // Check whether this is the method being overridden in this section of
- // the vtable.
- uint64_t Index;
- if (!Methods.getIndex(OGD, Index))
- continue;
-
- OGD2 = OGD;
-
- // Get the original method, which we should be computing thunks, etc,
- // against.
- OGD = Methods.getOrigMethod(Index);
- OMD = cast<CXXMethodDecl>(OGD.getDecl());
-
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- QualType OverriddenReturnType =
- OMD->getType()->getAs<FunctionType>()->getResultType();
-
- // Check if we need a return type adjustment.
- if (!ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD,
- OMD).isEmpty()) {
- CanQualType &BaseReturnType = BaseReturnTypes[Index];
-
- // Insert the base return type.
- if (BaseReturnType.isNull())
- BaseReturnType =
- CGM.getContext().getCanonicalType(OverriddenReturnType);
- }
-
- Methods.OverrideMethod(OGD, GD);
-
- GlobalDecl UGD = getUnique(GD);
- const CXXMethodDecl *UMD = cast<CXXMethodDecl>(UGD.getDecl());
- assert(UGD.getDecl() && "unique overrider not found");
- assert(UGD == getUnique(OGD) && "unique overrider not unique");
-
- ThisAdjustments.erase(Index);
- if (MorallyVirtual || VCall.count(UMD)) {
-
- Index_t &idx = VCall[UMD];
- if (idx == 0) {
- VCallOffset[GD] = VCallOffset[OGD];
- // NonVirtualOffset[UMD] = CurrentVBaseOffset/8 - OverrideOffset/8;
- NonVirtualOffset[UMD] = VCallOffset[OGD];
- VCallOffsetForVCall[UMD] = OverrideOffset/8;
- idx = VCalls.size()+1;
- VCalls.push_back(OverrideOffset/8 - CurrentVBaseOffset/8);
- D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
- } else {
- VCallOffset[GD] = NonVirtualOffset[UMD];
- VCalls[idx-1] = -VCallOffsetForVCall[UGD] + OverrideOffset/8;
- D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
- MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
- }
- int64_t NonVirtualAdjustment = -VCallOffset[OGD];
- QualType DerivedType = MD->getThisType(CGM.getContext());
- QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
- int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
- if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
- NonVirtualAdjustment = NonVirtualAdjustment2;
- }
- int64_t VirtualAdjustment =
- -((idx + extra + 2) * LLVMPointerWidth / 8);
-
- // Optimize out virtual adjustments of 0.
- if (VCalls[idx-1] == 0)
- VirtualAdjustment = 0;
-
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
- VirtualAdjustment);
-
- if (!isPure && !ThisAdjustment.isEmpty()) {
- ThisAdjustments[Index] = ThisAdjustment;
- SavedAdjustments.push_back(
- std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
- }
- return true;
- }
-
- VCallOffset[GD] = VCallOffset[OGD2] - OverrideOffset/8;
-
- int64_t NonVirtualAdjustment = -VCallOffset[GD];
- QualType DerivedType = MD->getThisType(CGM.getContext());
- QualType BaseType = cast<const CXXMethodDecl>(OGD.getDecl())->getThisType(CGM.getContext());
- int64_t NonVirtualAdjustment2 = -(getNVOffset(BaseType, DerivedType)/8);
- if (NonVirtualAdjustment2 != NonVirtualAdjustment) {
- NonVirtualAdjustment = NonVirtualAdjustment2;
- }
-
- if (NonVirtualAdjustment) {
- ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
-
- if (!isPure) {
- ThisAdjustments[Index] = ThisAdjustment;
- SavedAdjustments.push_back(
- std::make_pair(GD, std::make_pair(OGD, ThisAdjustment)));
- }
- }
- return true;
- }
-
- return false;
}
-
-void OldVtableBuilder::AppendMethodsToVtable() {
- if (!BuildVtable) {
- VtableComponents.insert(VtableComponents.end(), Methods.size(),
- (llvm::Constant *)0);
- ThisAdjustments.clear();
- BaseReturnTypes.clear();
- Methods.clear();
- return;
- }
-
- // Reserve room in the vtable for our new methods.
- VtableComponents.reserve(VtableComponents.size() + Methods.size());
-
- for (unsigned i = 0, e = Methods.size(); i != e; ++i) {
- GlobalDecl GD = Methods[i];
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // Get the 'this' pointer adjustment.
- ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i);
-
- // Construct the return type adjustment.
- ThunkAdjustment ReturnAdjustment;
-
- QualType BaseReturnType = BaseReturnTypes.lookup(i);
- if (!BaseReturnType.isNull() && !MD->isPure()) {
- QualType DerivedType =
- MD->getType()->getAs<FunctionType>()->getResultType();
-
- int64_t NonVirtualAdjustment =
- getNVOffset(BaseReturnType, DerivedType) / 8;
-
- int64_t VirtualAdjustment =
- getVbaseOffset(BaseReturnType, DerivedType);
-
- ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment,
- VirtualAdjustment);
- }
-
- llvm::Constant *Method = 0;
- if (!ReturnAdjustment.isEmpty()) {
- // Build a covariant thunk.
- CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment);
- Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment));
- } else if (!ThisAdjustment.isEmpty()) {
- // Build a "regular" thunk.
- Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment));
- } else if (MD->isPure()) {
- // We have a pure virtual method.
- Method = getPureVirtualFn();
- } else {
- // We have a good old regular method.
- Method = WrapAddrOf(GD);
- }
-
- // Add the method to the vtable.
- VtableComponents.push_back(Method);
- }
-
- ThisAdjustments.clear();
- BaseReturnTypes.clear();
-
- Methods.clear();
}
-void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
+void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.5.2:
// The order of the virtual function pointers in a virtual table is the
@@ -3481,7 +2479,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
NumVirtualFunctionPointers[RD] = CurrentIndex;
}
-uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
NumVirtualFunctionPointers.find(RD);
if (I != NumVirtualFunctionPointers.end())
@@ -3494,7 +2492,7 @@ uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
return I->second;
}
-uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) {
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
@@ -3508,36 +2506,8 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
return I->second;
}
-CGVtableInfo::AdjustmentVectorTy*
-CGVtableInfo::getAdjustments(GlobalDecl GD) {
- SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD);
- if (I != SavedAdjustments.end())
- return &I->second;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext());
- if (!SavedAdjustmentRecords.insert(RD).second)
- return 0;
-
- AddressPointsMapTy AddressPoints;
- OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints);
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- b.GenerateVtableForBase(RD);
- b.GenerateVtableForVBases(RD);
-
- for (OldVtableBuilder::SavedAdjustmentsVectorTy::iterator
- i = b.getSavedAdjustments().begin(),
- e = b.getSavedAdjustments().end(); i != e; i++)
- SavedAdjustments[i->first].push_back(i->second);
-
- I = SavedAdjustments.find(GD);
- if (I != SavedAdjustments.end())
- return &I->second;
-
- return 0;
-}
-
-int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
VirtualBaseClassOffsetOffsetsMapTy::iterator I =
@@ -3549,7 +2519,6 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
BaseSubobject(RD, 0),
/*BaseIsVirtual=*/false,
/*OffsetInLayoutClass=*/0);
-
for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
Builder.getVBaseOffsetOffsets().begin(),
@@ -3573,128 +2542,588 @@ int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
return I->second;
}
-uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) {
- uint64_t AddressPoint =
- (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)];
-
+uint64_t
+CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) {
+ uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base));
+ assert(AddressPoint && "Address point must not be zero!");
+
return AddressPoint;
}
-llvm::GlobalVariable *
-CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition,
- const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset,
- bool IsVirtual,
- AddressPointsMapTy& AddressPoints) {
- if (GenerateDefinition) {
- if (LayoutClass == RD) {
- assert(!IsVirtual &&
- "Can only have a virtual base in construction vtables!");
- assert(!Offset &&
- "Can only have a base offset in construction vtables!");
- }
+llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Compute the mangled name.
+ llvm::SmallString<256> Name;
+ if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
+ getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This,
+ Name);
+ else
+ getMangleContext().mangleThunk(MD, Thunk, Name);
+
+ const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD);
+ return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl());
+}
+
+static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ int64_t NonVirtualAdjustment,
+ int64_t VirtualAdjustment) {
+ if (!NonVirtualAdjustment && !VirtualAdjustment)
+ return Ptr;
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+
+ llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
+
+ if (NonVirtualAdjustment) {
+ // Do the non-virtual adjustment.
+ V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
+ }
+
+ if (VirtualAdjustment) {
+ const llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ // Do the virtual adjustment.
+ llvm::Value *VTablePtrPtr =
+ CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
+
+ llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
+
+ llvm::Value *OffsetPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+
+ OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
+
+ // Load the adjustment offset from the vtable.
+ llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
- VtableBuilder Builder(*this, RD, Offset,
- /*MostDerivedClassIsVirtual=*/IsVirtual,
- LayoutClass);
+ // Adjust our pointer.
+ V = CGF.Builder.CreateInBoundsGEP(V, Offset);
+ }
+
+ // Cast back to the original type.
+ return CGF.Builder.CreateBitCast(V, Ptr->getType());
+}
+
+void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+ QualType ThisType = MD->getThisType(getContext());
- if (CGM.getLangOptions().DumpVtableLayouts)
- Builder.dumpLayout(llvm::errs());
+ FunctionArgList FunctionArgs;
+
+ // FIXME: It would be nice if more of this code could be shared with
+ // CodeGenFunction::GenerateCode.
+
+ // Create the implicit 'this' parameter declaration.
+ CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0,
+ MD->getLocation(),
+ &getContext().Idents.get("this"),
+ ThisType);
+
+ // Add the 'this' parameter.
+ FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
+
+ // Add the rest of the parameters.
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ ParmVarDecl *Param = *I;
+
+ FunctionArgs.push_back(std::make_pair(Param, Param->getType()));
}
+
+ StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation());
- llvm::SmallString<256> OutName;
- if (LayoutClass != RD)
- CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
- RD, OutName);
- else
- CGM.getMangleContext().mangleCXXVtable(RD, OutName);
- llvm::StringRef Name = OutName.str();
+ // Adjust the 'this' pointer if necessary.
+ llvm::Value *AdjustedThisPtr =
+ PerformTypeAdjustment(*this, LoadCXXThis(),
+ Thunk.This.NonVirtual,
+ Thunk.This.VCallOffsetOffset);
+
+ CallArgList CallArgs;
+
+ // Add our adjusted 'this' pointer.
+ CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType));
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 ||
- GV->isDeclaration()) {
- OldVtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition,
- AddressPoints);
+ // Add the rest of the parameters.
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end(); I != E; ++I) {
+ ParmVarDecl *Param = *I;
+ QualType ArgType = Param->getType();
+
+ // FIXME: Declaring a DeclRefExpr on the stack is kinda icky.
+ DeclRefExpr ArgExpr(Param, ArgType.getNonReferenceType(), SourceLocation());
+ CallArgs.push_back(std::make_pair(EmitCallArg(&ArgExpr, ArgType), ArgType));
+ }
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- // First comes the vtables for all the non-virtual bases...
- b.GenerateVtableForBase(RD, Offset);
+ // Get our callee.
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
- // then the vtables for all the virtual bases.
- b.GenerateVtableForVBases(RD, Offset);
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().getFunctionInfo(ResultType, CallArgs,
+ FPT->getExtInfo());
+
+ // Now emit our call.
+ RValue RV = EmitCall(FnInfo, Callee, ReturnValueSlot(), CallArgs, MD);
+
+ if (!Thunk.Return.isEmpty()) {
+ // Emit the return adjustment.
+ bool NullCheckValue = !ResultType->isReferenceType();
+
+ llvm::BasicBlock *AdjustNull = 0;
+ llvm::BasicBlock *AdjustNotNull = 0;
+ llvm::BasicBlock *AdjustEnd = 0;
+
+ llvm::Value *ReturnValue = RV.getScalarVal();
- llvm::Constant *Init = 0;
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
- llvm::ArrayType *ArrayType =
- llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size());
-
- if (GenerateDefinition)
- Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0],
- b.getVtableComponents().size());
-
- llvm::GlobalVariable *OGV = GV;
-
- GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType,
- /*isConstant=*/true, Linkage, Init, Name);
- CGM.setGlobalVisibility(GV, RD);
-
- if (OGV) {
- GV->takeName(OGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OGV->getType());
- OGV->replaceAllUsesWith(NewPtr);
- OGV->eraseFromParent();
+ if (NullCheckValue) {
+ AdjustNull = createBasicBlock("adjust.null");
+ AdjustNotNull = createBasicBlock("adjust.notnull");
+ AdjustEnd = createBasicBlock("adjust.end");
+
+ llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue);
+ Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
+ EmitBlock(AdjustNotNull);
+ }
+
+ ReturnValue = PerformTypeAdjustment(*this, ReturnValue,
+ Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ if (NullCheckValue) {
+ Builder.CreateBr(AdjustEnd);
+ EmitBlock(AdjustNull);
+ Builder.CreateBr(AdjustEnd);
+ EmitBlock(AdjustEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(ReturnValue, AdjustNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
+ AdjustNull);
+ ReturnValue = PHI;
}
+
+ RV = RValue::get(ReturnValue);
}
+
+ if (!ResultType->isVoidType())
+ EmitReturnOfRValue(RV, ResultType);
+
+ FinishFunction();
+
+ // Destroy the 'this' declaration.
+ CXXThisDecl->Destroy(getContext());
- return GV;
+ // Set the right linkage.
+ Fn->setLinkage(CGM.getFunctionLinkage(MD));
+
+ // Set the right visibility.
+ CGM.setGlobalVisibility(Fn, MD);
}
-void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
- llvm::GlobalVariable *&Vtable = Vtables[RD];
- if (Vtable) {
- assert(Vtable->getInitializer() && "Vtable doesn't have a definition!");
+void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
+{
+ llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // Strip off a bitcast if we got one back.
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ assert(CE->getOpcode() == llvm::Instruction::BitCast);
+ Entry = CE->getOperand(0);
+ }
+
+ // There's already a declaration with the same name, check if it has the same
+ // type or if we need to replace it.
+ if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() !=
+ CGM.getTypes().GetFunctionTypeForVtable(MD)) {
+ llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry);
+
+ // If the types mismatch then we have to rewrite the definition.
+ assert(OldThunkFn->isDeclaration() &&
+ "Shouldn't replace non-declaration");
+
+ // Remove the name from the old thunk function and get a new thunk.
+ OldThunkFn->setName(llvm::StringRef());
+ Entry = CGM.GetAddrOfThunk(GD, Thunk);
+
+ // If needed, replace the old thunk with a bitcast.
+ if (!OldThunkFn->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(Entry, OldThunkFn->getType());
+ OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl);
+ }
+
+ // Remove the old thunk.
+ OldThunkFn->eraseFromParent();
+ }
+
+ // Actually generate the thunk body.
+ llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+ CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk);
+}
+
+void CodeGenVTables::EmitThunks(GlobalDecl GD)
+{
+ const CXXMethodDecl *MD =
+ cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl();
+
+ // We don't need to generate thunks for the base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return;
+
+ const CXXRecordDecl *RD = MD->getParent();
+
+ // Compute VTable related info for this class.
+ ComputeVTableRelatedInformation(RD);
+
+ ThunksMapTy::const_iterator I = Thunks.find(MD);
+ if (I == Thunks.end()) {
+ // We did not find a thunk for this method.
return;
}
+
+ const ThunkInfoVectorTy &ThunkInfoVector = I->second;
+ for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
+ EmitThunk(GD, ThunkInfoVector[I]);
+}
+
+void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+ uint64_t *&LayoutData = VTableLayoutMap[RD];
- AddressPointsMapTy AddressPoints;
- Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0,
- /*IsVirtual=*/false,
- AddressPoints);
- GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+ // Check if we've computed this information before.
+ if (LayoutData)
+ return;
+
+ VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- if (!(*i)->isVirtual())
- continue;
- if(!(*i)->hasInlineBody() && !(*i)->isImplicit())
- continue;
+ // Add the VTable layout.
+ uint64_t NumVTableComponents = Builder.getNumVTableComponents();
+ LayoutData = new uint64_t[NumVTableComponents + 1];
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) {
- CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete));
- CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting));
- } else {
- CGM.BuildThunksForVirtual(GlobalDecl(*i));
+ // Store the number of components.
+ LayoutData[0] = NumVTableComponents;
+
+ // Store the components.
+ std::copy(Builder.vtable_components_data_begin(),
+ Builder.vtable_components_data_end(),
+ &LayoutData[1]);
+
+ // Add the known thunks.
+ Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+
+ // Add the thunks needed in this vtable.
+ assert(!VTableThunksMap.count(RD) &&
+ "Thunks already exists for this vtable!");
+
+ VTableThunksTy &VTableThunks = VTableThunksMap[RD];
+ VTableThunks.append(Builder.vtable_thunks_begin(),
+ Builder.vtable_thunks_end());
+
+ // Sort them.
+ std::sort(VTableThunks.begin(), VTableThunks.end());
+
+ // Add the address points.
+ for (VtableBuilder::AddressPointsMapTy::const_iterator I =
+ Builder.address_points_begin(), E = Builder.address_points_end();
+ I != E; ++I) {
+
+ uint64_t &AddressPoint = AddressPoints[std::make_pair(RD, I->first)];
+
+ // Check if we already have the address points for this base.
+ assert(!AddressPoint && "Address point already exists for this base!");
+
+ AddressPoint = I->second;
+ }
+
+ // If we don't have the vbase information for this class, insert it.
+ // getVirtualBaseOffsetOffset will compute it separately without computing
+ // the rest of the vtable related information.
+ if (!RD->getNumVBases())
+ return;
+
+ const RecordType *VBaseRT =
+ RD->vbases_begin()->getType()->getAs<RecordType>();
+ const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+
+ if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
+ return;
+
+ for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
+ Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+ // Insert all types.
+ ClassPairTy ClassPair(RD, I->first);
+
+ VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second));
+ }
+}
+
+llvm::Constant *
+CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
+ const uint64_t *Components,
+ unsigned NumComponents,
+ const VTableThunksTy &VTableThunks) {
+ llvm::SmallVector<llvm::Constant *, 64> Inits;
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+
+ const llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ QualType ClassType = CGM.getContext().getTagDeclType(RD);
+ llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType);
+
+ unsigned NextVTableThunkIndex = 0;
+
+ llvm::Constant* PureVirtualFn = 0;
+
+ for (unsigned I = 0; I != NumComponents; ++I) {
+ VtableComponent Component =
+ VtableComponent::getFromOpaqueInteger(Components[I]);
+
+ llvm::Constant *Init = 0;
+
+ switch (Component.getKind()) {
+ case VtableComponent::CK_VCallOffset:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_VBaseOffset:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_OffsetToTop:
+ Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop());
+ Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy);
+ break;
+ case VtableComponent::CK_RTTI:
+ Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy);
+ break;
+ case VtableComponent::CK_FunctionPointer:
+ case VtableComponent::CK_CompleteDtorPointer:
+ case VtableComponent::CK_DeletingDtorPointer: {
+ GlobalDecl GD;
+
+ // Get the right global decl.
+ switch (Component.getKind()) {
+ default:
+ llvm_unreachable("Unexpected vtable component kind");
+ case VtableComponent::CK_FunctionPointer:
+ GD = Component.getFunctionDecl();
+ break;
+ case VtableComponent::CK_CompleteDtorPointer:
+ GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete);
+ break;
+ case VtableComponent::CK_DeletingDtorPointer:
+ GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting);
+ break;
+ }
+
+ if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) {
+ // We have a pure virtual member function.
+ if (!PureVirtualFn) {
+ const llvm::FunctionType *Ty =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
+ /*isVarArg=*/false);
+ PureVirtualFn =
+ CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual");
+ PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
+ Int8PtrTy);
+ }
+
+ Init = PureVirtualFn;
+ } else {
+ // Check if we should use a thunk.
+ if (NextVTableThunkIndex < VTableThunks.size() &&
+ VTableThunks[NextVTableThunkIndex].first == I) {
+ const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
+
+ Init = CGM.GetAddrOfThunk(GD, Thunk);
+
+ NextVTableThunkIndex++;
+ } else {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
+
+ Init = CGM.GetAddrOfFunction(GD, Ty);
+ }
+
+ Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+ }
+ break;
+ }
+
+ case VtableComponent::CK_UnusedFunctionPointer:
+ Init = llvm::ConstantExpr::getNullValue(Int8PtrTy);
+ break;
+ };
+
+ Inits.push_back(Init);
+ }
+
+ llvm::ArrayType *ArrayType = llvm::ArrayType::get(Int8PtrTy, NumComponents);
+ return llvm::ConstantArray::get(ArrayType, Inits.data(), Inits.size());
+}
+
+/// GetGlobalVariable - Will return a global variable of the given type.
+/// If a variable with a different type already exists then a new variable
+/// with the right type will be created.
+/// FIXME: We should move this to CodeGenModule and rename it to something
+/// better and then use it in CGVTT and CGRTTI.
+static llvm::GlobalVariable *
+GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name,
+ const llvm::Type *Ty,
+ llvm::GlobalValue::LinkageTypes Linkage) {
+
+ llvm::GlobalVariable *GV = Module.getNamedGlobal(Name);
+ llvm::GlobalVariable *OldGV = 0;
+
+ if (GV) {
+ // Check if the variable has the right type.
+ if (GV->getType()->getElementType() == Ty)
+ return GV;
+
+ assert(GV->isDeclaration() && "Declaration has wrong type!");
+
+ OldGV = GV;
+ }
+
+ // Create a new variable.
+ GV = new llvm::GlobalVariable(Module, Ty, /*isConstant=*/true,
+ Linkage, 0, Name);
+
+ if (OldGV) {
+ // Replace occurrences of the old variable if needed.
+ GV->takeName(OldGV);
+
+ if (!OldGV->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtrForOldDecl);
}
+
+ OldGV->eraseFromParent();
}
+
+ return GV;
}
-llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
- llvm::GlobalVariable *Vtable = Vtables.lookup(RD);
+llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXVtable(RD, OutName);
+ llvm::StringRef Name = OutName.str();
+
+ ComputeVTableRelatedInformation(RD);
- if (!Vtable) {
- AddressPointsMapTy AddressPoints;
- Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage,
- /*GenerateDefinition=*/false, RD, RD, 0,
- /*IsVirtual=*/false, AddressPoints);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, getNumVTableComponents(RD));
+
+ return GetGlobalVariable(CGM.getModule(), Name, ArrayType,
+ llvm::GlobalValue::ExternalLinkage);
+}
+
+void
+CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
+ // Dump the vtable layout if necessary.
+ if (CGM.getLangOptions().DumpVtableLayouts) {
+ VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD);
+
+ Builder.dumpLayout(llvm::errs());
}
- return Vtable;
+ assert(VTableThunksMap.count(RD) &&
+ "No thunk status for this record decl!");
+
+ const VTableThunksTy& Thunks = VTableThunksMap[RD];
+
+ // Create and set the initializer.
+ llvm::Constant *Init =
+ CreateVTableInitializer(RD, getVTableComponentsData(RD),
+ getNumVTableComponents(RD), Thunks);
+ VTable->setInitializer(Init);
+
+ // Set the correct linkage.
+ VTable->setLinkage(Linkage);
}
-void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
+llvm::GlobalVariable *
+CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base,
+ bool BaseIsVirtual,
+ VTableAddressPointsMapTy& AddressPoints) {
+ VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(),
+ /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD);
+
+ // Dump the vtable layout if necessary.
+ if (CGM.getLangOptions().DumpVtableLayouts)
+ Builder.dumpLayout(llvm::errs());
+
+ // Add the address points.
+ AddressPoints.insert(Builder.address_points_begin(),
+ Builder.address_points_end());
+
+ // Get the mangled construction vtable name.
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8,
+ Base.getBase(), OutName);
+ llvm::StringRef Name = OutName.str();
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ llvm::ArrayType *ArrayType =
+ llvm::ArrayType::get(Int8PtrTy, Builder.getNumVTableComponents());
+
+ // Create the variable that will hold the construction vtable.
+ llvm::GlobalVariable *VTable =
+ GetGlobalVariable(CGM.getModule(), Name, ArrayType,
+ llvm::GlobalValue::InternalLinkage);
+
+ // Add the thunks.
+ VTableThunksTy VTableThunks;
+ VTableThunks.append(Builder.vtable_thunks_begin(),
+ Builder.vtable_thunks_end());
+
+ // Sort them.
+ std::sort(VTableThunks.begin(), VTableThunks.end());
+
+ // Create and set the initializer.
+ llvm::Constant *Init =
+ CreateVTableInitializer(Base.getBase(),
+ Builder.vtable_components_data_begin(),
+ Builder.getNumVTableComponents(), VTableThunks);
+ VTable->setInitializer(Init);
+
+ return VTable;
+}
+
+void
+CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD) {
+ llvm::GlobalVariable *&VTable = Vtables[RD];
+ if (VTable) {
+ assert(VTable->getInitializer() && "Vtable doesn't have a definition!");
+ return;
+ }
+
+ VTable = GetAddrOfVTable(RD);
+ EmitVTableDefinition(VTable, Linkage, RD);
+
+ GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD);
+}
+
+void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
@@ -3702,20 +3131,34 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
if (!RD->isDynamicClass())
return;
+ // Check if we need to emit thunks for this function.
+ if (MD->isVirtual())
+ EmitThunks(GD);
+
// Get the key function.
const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
+ TemplateSpecializationKind RDKind = RD->getTemplateSpecializationKind();
+ TemplateSpecializationKind MDKind = MD->getTemplateSpecializationKind();
+
if (KeyFunction) {
// We don't have the right key function.
if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
return;
+ } else {
+ // If this is an explicit instantiation of a method, we don't need a vtable.
+ // Since we have no key function, we will emit the vtable when we see
+ // a use, and just defining a function is not an use.
+ if ((RDKind == TSK_ImplicitInstantiation ||
+ RDKind == TSK_ExplicitInstantiationDeclaration) &&
+ MDKind == TSK_ExplicitInstantiationDefinition)
+ return;
}
if (Vtables.count(RD))
return;
- TemplateSpecializationKind kind = RD->getTemplateSpecializationKind();
- if (kind == TSK_ImplicitInstantiation)
+ if (RDKind == TSK_ImplicitInstantiation)
CGM.DeferredVtables.push_back(RD);
else
GenerateClassData(CGM.getVtableLinkage(RD), RD);
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 5a146ab..6073555 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -15,7 +15,6 @@
#define CLANG_CODEGEN_CGVTABLE_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/GlobalVariable.h"
#include "GlobalDecl.h"
@@ -25,41 +24,93 @@ namespace clang {
namespace CodeGen {
class CodeGenModule;
-/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks.
-class ThunkAdjustment {
-public:
- ThunkAdjustment(int64_t NonVirtual, int64_t Virtual)
- : NonVirtual(NonVirtual),
- Virtual(Virtual) { }
-
- ThunkAdjustment()
- : NonVirtual(0), Virtual(0) { }
+/// ReturnAdjustment - A return adjustment.
+struct ReturnAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
+ int64_t NonVirtual;
+
+ /// VBaseOffsetOffset - The offset (in bytes), relative to the address point
+ /// of the virtual base class offset.
+ int64_t VBaseOffsetOffset;
+
+ ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
- // isEmpty - Return whether this thunk adjustment is empty.
- bool isEmpty() const {
- return NonVirtual == 0 && Virtual == 0;
+ friend bool operator==(const ReturnAdjustment &LHS,
+ const ReturnAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
}
- /// NonVirtual - The non-virtual adjustment.
+ friend bool operator<(const ReturnAdjustment &LHS,
+ const ReturnAdjustment &RHS) {
+ if (LHS.NonVirtual < RHS.NonVirtual)
+ return true;
+
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
+ }
+};
+
+/// ThisAdjustment - A 'this' pointer adjustment.
+struct ThisAdjustment {
+ /// NonVirtual - The non-virtual adjustment from the derived object to its
+ /// nearest virtual base.
int64_t NonVirtual;
- /// Virtual - The virtual adjustment.
- int64_t Virtual;
+ /// VCallOffsetOffset - The offset (in bytes), relative to the address point,
+ /// of the virtual call offset.
+ int64_t VCallOffsetOffset;
+
+ ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { }
+
+ bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; }
+
+ friend bool operator==(const ThisAdjustment &LHS,
+ const ThisAdjustment &RHS) {
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VCallOffsetOffset == RHS.VCallOffsetOffset;
+ }
+
+ friend bool operator<(const ThisAdjustment &LHS,
+ const ThisAdjustment &RHS) {
+ if (LHS.NonVirtual < RHS.NonVirtual)
+ return true;
+
+ return LHS.NonVirtual == RHS.NonVirtual &&
+ LHS.VCallOffsetOffset < RHS.VCallOffsetOffset;
+ }
};
-/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the
-/// return pointer for covariant thunks.
-class CovariantThunkAdjustment {
-public:
- CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment,
- const ThunkAdjustment &ReturnAdjustment)
- : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { }
+/// ThunkInfo - The 'this' pointer adjustment as well as an optional return
+/// adjustment for a thunk.
+struct ThunkInfo {
+ /// This - The 'this' pointer adjustment.
+ ThisAdjustment This;
+
+ /// Return - The return adjustment.
+ ReturnAdjustment Return;
- CovariantThunkAdjustment() { }
+ ThunkInfo() { }
- ThunkAdjustment ThisAdjustment;
- ThunkAdjustment ReturnAdjustment;
-};
+ ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return)
+ : This(This), Return(Return) { }
+
+ friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ return LHS.This == RHS.This && LHS.Return == RHS.Return;
+ }
+
+ friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ if (LHS.This < RHS.This)
+ return true;
+
+ return LHS.This == RHS.This && LHS.Return < RHS.Return;
+ }
+
+ bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
+};
// BaseSubobject - Uniquely identifies a direct or indirect base class.
// Stores both the base class decl and the offset from the most derived class to
@@ -126,19 +177,7 @@ template <> struct isPodLike<clang::CodeGen::BaseSubobject> {
namespace clang {
namespace CodeGen {
-class CGVtableInfo {
-public:
- typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> >
- AdjustmentVectorTy;
-
- typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
- typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t;
- typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t;
- llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
-
- typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
-
-private:
+class CodeGenVTables {
CodeGenModule &CGM;
/// MethodVtableIndices - Contains the index (relative to the vtable address
@@ -163,31 +202,97 @@ private:
/// pointers in the vtable for a given record decl.
llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
- typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy;
- SavedAdjustmentsTy SavedAdjustments;
- llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords;
+ typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - Contains all thunks that a given method decl will need.
+ ThunksMapTy Thunks;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t *> VTableLayoutMapTy;
+
+ /// VTableLayoutMap - Stores the vtable layout for all record decls.
+ /// The layout is stored as an array of 64-bit integers, where the first
+ /// integer is the number of vtable entries in the layout, and the subsequent
+ /// integers are the vtable components.
+ VTableLayoutMapTy VTableLayoutMap;
+
+ typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
+ BaseSubobject>, uint64_t> AddressPointsMapTy;
+
+ /// Address points - Address points for all vtables.
+ AddressPointsMapTy AddressPoints;
+
+ /// VTableAddressPointsMapTy - Address points for a single vtable.
+ typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
+
+ typedef llvm::SmallVector<std::pair<uint64_t, ThunkInfo>, 1>
+ VTableThunksTy;
+
+ typedef llvm::DenseMap<const CXXRecordDecl *, VTableThunksTy>
+ VTableThunksMapTy;
+
+ /// VTableThunksMap - Contains thunks needed by vtables.
+ VTableThunksMapTy VTableThunksMap;
+
+ uint64_t getNumVTableComponents(const CXXRecordDecl *RD) const {
+ assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
+
+ return VTableLayoutMap.lookup(RD)[0];
+ }
+
+ const uint64_t *getVTableComponentsData(const CXXRecordDecl *RD) const {
+ assert(VTableLayoutMap.count(RD) && "No vtable layout for this class!");
+
+ uint64_t *Components = VTableLayoutMap.lookup(RD);
+ return &Components[1];
+ }
+
+ typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy;
+
+ /// SubVTTIndicies - Contains indices into the various sub-VTTs.
+ SubVTTIndiciesMapTy SubVTTIndicies;
+
+
+ typedef llvm::DenseMap<std::pair<const CXXRecordDecl *,
+ BaseSubobject>, uint64_t>
+ SecondaryVirtualPointerIndicesMapTy;
- typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy;
- SubVTTIndiciesTy SubVTTIndicies;
+ /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer
+ /// indices.
+ SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
/// getNumVirtualFunctionPointers - Return the number of virtual function
/// pointers in the vtable for a given record decl.
uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
-
- llvm::GlobalVariable *
- GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition, const CXXRecordDecl *LayoutClass,
- const CXXRecordDecl *RD, uint64_t Offset, bool IsVirtual,
- AddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
bool GenerateDefinition,
const CXXRecordDecl *RD);
+ /// EmitThunk - Emit a single thunk.
+ void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk);
+
+ /// EmitThunks - Emit the associated thunks for the given global decl.
+ void EmitThunks(GlobalDecl GD);
+
+ /// ComputeVTableRelatedInformation - Compute and store all vtable related
+ /// information (vtable layout, vbase offset offsets, thunks etc) for the
+ /// given record decl.
+ void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
+
+ /// CreateVTableInitializer - Create a vtable initializer for the given record
+ /// decl.
+ /// \param Components - The vtable components; this is really an array of
+ /// VTableComponents.
+ llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
+ const uint64_t *Components,
+ unsigned NumComponents,
+ const VTableThunksTy &VTableThunks);
+
public:
- CGVtableInfo(CodeGenModule &CGM)
+ CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM) { }
/// needsVTTParameter - Return whether the given global decl needs a VTT
@@ -199,6 +304,11 @@ public:
/// given record decl.
uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base);
+ /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the
+ /// virtual pointer for the given subobject is located.
+ uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
+ BaseSubobject Base);
+
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
@@ -212,35 +322,32 @@ public:
int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
- AdjustmentVectorTy *getAdjustments(GlobalDecl GD);
-
- /// getVtableAddressPoint - returns the address point of the vtable for the
- /// given record decl.
- /// FIXME: This should return a list of address points.
- uint64_t getVtableAddressPoint(const CXXRecordDecl *RD);
-
- llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD);
-
- /// CtorVtableInfo - Information about a constructor vtable.
- struct CtorVtableInfo {
- /// Vtable - The vtable itself.
- llvm::GlobalVariable *Vtable;
+ /// getAddressPoint - Get the address point of the given subobject in the
+ /// class decl.
+ uint64_t getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD);
- /// AddressPoints - The address points in this constructor vtable.
- AddressPointsMapTy AddressPoints;
-
- CtorVtableInfo() : Vtable(0) { }
- };
+ /// GetAddrOfVTable - Get the address of the vtable for the given record decl.
+ llvm::GlobalVariable *GetAddrOfVTable(const CXXRecordDecl *RD);
+
+ /// EmitVTableDefinition - Emit the definition of the given vtable.
+ void EmitVTableDefinition(llvm::GlobalVariable *VTable,
+ llvm::GlobalVariable::LinkageTypes Linkage,
+ const CXXRecordDecl *RD);
- CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD,
- const BaseSubobject &Base,
- bool BaseIsVirtual);
+ /// GenerateConstructionVTable - Generate a construction vtable for the given
+ /// base subobject.
+ llvm::GlobalVariable *
+ GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base,
+ bool BaseIsVirtual,
+ VTableAddressPointsMapTy& AddressPoints);
llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD);
- void MaybeEmitVtable(GlobalDecl GD);
+ // EmitVTableRelatedData - Will emit any thunks that the global decl might
+ // have, as well as the vtable itself if the global decl is the key function.
+ void EmitVTableRelatedData(GlobalDecl GD);
- /// GenerateClassData - Generate all the class data requires to be generated
+ /// GenerateClassData - Generate all the class data required to be generated
/// upon definition of a KeyFunction. This includes the vtable, the
/// rtti data structure and the VTT.
///
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index f455827..b863aff 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -199,8 +199,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0,
false, false, 0, 0,
- /*FIXME?*/false,
- /*FIXME?*/CC_Default);
+ /*FIXME?*/
+ FunctionType::ExtInfo());
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
@@ -211,7 +211,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// FIXME: Leaked.
// CC info is ignored, hopefully?
CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args,
- CC_Default, false);
+ FunctionType::ExtInfo());
if (RetTy->isVoidType()) {
// Void type; nothing to return.
@@ -279,7 +279,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) {
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
// Check if we need a VTT parameter as well.
- if (CGVtableInfo::needsVTTParameter(GD)) {
+ if (CodeGenVTables::needsVTTParameter(GD)) {
// FIXME: The comment about using a fake decl above applies here too.
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
CXXVTTDecl =
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index bd12c4a..f21350d 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -22,7 +22,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ValueHandle.h"
-#include <map>
#include "CodeGenModule.h"
#include "CGBlocks.h"
#include "CGBuilder.h"
@@ -254,6 +253,27 @@ public:
}
};
+ /// CXXTemporariesCleanupScope - Enters a new scope for catching live
+ /// temporaries, all of which will be popped once the scope is exited.
+ class CXXTemporariesCleanupScope {
+ CodeGenFunction &CGF;
+ size_t NumLiveTemporaries;
+
+ // DO NOT IMPLEMENT
+ CXXTemporariesCleanupScope(const CXXTemporariesCleanupScope &);
+ CXXTemporariesCleanupScope &operator=(const CXXTemporariesCleanupScope &);
+
+ public:
+ explicit CXXTemporariesCleanupScope(CodeGenFunction &CGF)
+ : CGF(CGF), NumLiveTemporaries(CGF.LiveTemporaries.size()) { }
+
+ ~CXXTemporariesCleanupScope() {
+ while (CGF.LiveTemporaries.size() > NumLiveTemporaries)
+ CGF.PopCXXTemporary();
+ }
+ };
+
+
/// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup
/// blocks that have been added.
void EmitCleanupBlocks(size_t OldCleanupStackSize);
@@ -504,30 +524,29 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
- /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an
- /// object pointer to alter the dynamic type of the pointer. Used by
- /// GenerateCovariantThunk for building thunks.
- llvm::Value *DynamicTypeAdjust(llvm::Value *V,
- const ThunkAdjustment &Adjustment);
-
- /// GenerateThunk - Generate a thunk for the given method
- llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const ThunkAdjustment &ThisAdjustment);
- llvm::Constant *
- GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD,
- bool Extern,
- const CovariantThunkAdjustment &Adjustment);
-
+ /// GenerateThunk - Generate a thunk for the given method.
+ void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk);
+
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
- void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl);
+ /// InitializeVTablePointer - Initialize the vtable pointer of the given
+ /// subobject.
+ ///
+ /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base
+ /// or a direct or indirect base of a virtual base.
+ void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass);
+
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
+ void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual,
+ bool BaseIsNonVirtualPrimaryBase,
+ llvm::Constant *VTable,
+ const CXXRecordDecl *VTableClass,
+ VisitedVirtualBasesSetTy& VBases);
+
+ void InitializeVTablePointers(const CXXRecordDecl *ClassDecl);
- void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl,
- llvm::Constant *Vtable,
- CGVtableInfo::AddrSubMap_t& AddressPoints,
- llvm::Value *ThisPtr,
- uint64_t Offset);
void SynthesizeCXXCopyConstructor(const FunctionArgList &Args);
void SynthesizeCXXCopyAssignment(const FunctionArgList &Args);
@@ -1272,6 +1291,10 @@ public:
/// getTrapBB - Create a basic block that will call the trap intrinsic. We'll
/// generate a branch around the created basic block as necessary.
llvm::BasicBlock* getTrapBB();
+
+ /// EmitCallArg - Emit a single call argument.
+ RValue EmitCallArg(const Expr *E, QualType ArgType);
+
private:
void EmitReturnOfRValue(RValue RV, QualType Ty);
@@ -1303,9 +1326,6 @@ private:
/// current cleanup scope.
void AddBranchFixup(llvm::BranchInst *BI);
- /// EmitCallArg - Emit a single call argument.
- RValue EmitCallArg(const Expr *E, QualType ArgType);
-
/// EmitCallArgs - Emit call arguments for a function.
/// The CallArgTypeInfo parameter is used for iterating over the known
/// argument types of the function being called.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index b4b5bbd..3c872c8 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -47,7 +47,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()),
- MangleCtx(C), VtableInfo(*this), Runtime(0),
+ MangleCtx(C), VTables(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
VMContext(M.getContext()) {
@@ -79,6 +79,7 @@ void CodeGenModule::createObjCRuntime() {
}
void CodeGenModule::Release() {
+ EmitFundamentalRTTIDescriptors();
EmitDeferred();
EmitCXXGlobalInitFunc();
EmitCXXGlobalDtorFunc();
@@ -495,7 +496,7 @@ void CodeGenModule::EmitDeferred() {
if (!DeferredVtables.empty()) {
const CXXRecordDecl *RD = DeferredVtables.back();
DeferredVtables.pop_back();
- getVtableInfo().GenerateClassData(getVtableLinkage(RD), RD);
+ getVTables().GenerateClassData(getVtableLinkage(RD), RD);
continue;
}
@@ -714,20 +715,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- getVtableInfo().MaybeEmitVtable(GD);
- if (MD->isVirtual() && MD->isOutOfLine() &&
- (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) {
- if (isa<CXXDestructorDecl>(D)) {
- GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()),
- GD.getDtorType());
- BuildThunksForVirtual(CanonGD);
- } else {
- BuildThunksForVirtual(MD->getCanonicalDecl());
- }
- }
- }
-
+ if (isa<CXXMethodDecl>(D))
+ getVTables().EmitVTableRelatedData(GD);
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
@@ -758,7 +748,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
if (WeakRefReferences.count(Entry)) {
const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl());
if (FD && !FD->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
+ Entry->setLinkage(llvm::Function::ExternalLinkage);
WeakRefReferences.erase(Entry);
}
@@ -873,7 +863,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
if (Entry) {
if (WeakRefReferences.count(Entry)) {
if (D && !D->hasAttr<WeakAttr>())
- Entry->setLinkage(llvm::Function::ExternalLinkage);
+ Entry->setLinkage(llvm::Function::ExternalLinkage);
WeakRefReferences.erase(Entry);
}
@@ -1255,9 +1245,9 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
if (!CI->use_empty())
CI->replaceAllUsesWith(NewCall);
- // Copy any custom metadata attached with CI.
- if (llvm::MDNode *DbgNode = CI->getMetadata("dbg"))
- NewCall->setMetadata("dbg", DbgNode);
+ // Copy debug location attached to CI.
+ if (!CI->getDebugLoc().isUnknown())
+ NewCall->setDebugLoc(CI->getDebugLoc());
CI->eraseFromParent();
}
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index febb856..3c57c0b 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -31,7 +31,6 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ValueHandle.h"
-#include <list>
namespace llvm {
class Module;
@@ -93,8 +92,8 @@ class CodeGenModule : public BlockModule {
CodeGenTypes Types;
MangleContext MangleCtx;
- /// VtableInfo - Holds information about C++ vtables.
- CGVtableInfo VtableInfo;
+ /// VTables - Holds information about C++ vtables.
+ CodeGenVTables VTables;
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
@@ -181,7 +180,7 @@ public:
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
MangleContext &getMangleContext() { return MangleCtx; }
- CGVtableInfo &getVtableInfo() { return VtableInfo; }
+ CodeGenVTables &getVTables() { return VTables; }
Diagnostic &getDiags() const { return Diags; }
const llvm::TargetData &getTargetData() const { return TheTargetData; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
@@ -225,36 +224,18 @@ public:
/// for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty);
- llvm::Constant *GetAddrOfThunk(GlobalDecl GD,
- const ThunkAdjustment &ThisAdjustment);
- llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD,
- const CovariantThunkAdjustment &ThisAdjustment);
- void BuildThunksForVirtual(GlobalDecl GD);
- void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD);
+ /// GetAddrOfThunk - Get the address of the thunk for the given global decl.
+ llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
/// GetWeakRefReference - Get a reference to the target of VD.
llvm::Constant *GetWeakRefReference(const ValueDecl *VD);
- /// BuildThunk - Build a thunk for the given method.
- llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern,
- const ThunkAdjustment &ThisAdjustment);
-
- /// BuildCoVariantThunk - Build a thunk for the given method
- llvm::Constant *
- BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
- const CovariantThunkAdjustment &Adjustment);
-
/// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
/// its base class. Returns null if the offset is 0.
llvm::Constant *
GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl);
- /// ComputeThunkAdjustment - Returns the two parts required to compute the
- /// offset for an object.
- ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
-
/// GetStringForStringLiteral - Return the appropriate bytes for a string
/// literal, properly padded to match the literal type. If only the address of
/// a constant is needed consider using GetAddrOfConstantStringLiteral.
@@ -523,6 +504,14 @@ private:
void EmitAnnotations(void);
+ /// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the
+ /// given type.
+ void EmitFundamentalRTTIDescriptor(QualType Type);
+
+ /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the
+ /// builtin types.
+ void EmitFundamentalRTTIDescriptors();
+
/// EmitDeferred - Emit any needed decls for which code generation
/// was deferred.
void EmitDeferred(void);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 4feca4d..f53dd83 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTypes.h"
+#include "CGCall.h"
+#include "CGRecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@@ -20,10 +22,6 @@
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
-
-#include "CGCall.h"
-#include "CGRecordLayoutBuilder.h"
-
using namespace clang;
using namespace CodeGen;
@@ -400,7 +398,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
/// enum.
const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
-
// TagDecl's are not necessarily unique, instead use the (clang)
// type connected to the decl.
const Type *Key =
@@ -449,7 +446,7 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
}
// Layout fields.
- CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD);
+ CGRecordLayout *Layout = ComputeRecordLayout(RD);
CGRecordLayouts[Key] = Layout;
const llvm::Type *ResultType = Layout->getLLVMType();
@@ -462,42 +459,11 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) {
return ResultHolder.get();
}
-/// getLLVMFieldNo - Return llvm::StructType element number
-/// that corresponds to the field FD.
-unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) {
- assert(!FD->isBitField() && "Don't use getLLVMFieldNo on bit fields!");
-
- llvm::DenseMap<const FieldDecl*, unsigned>::iterator I = FieldInfo.find(FD);
- assert (I != FieldInfo.end() && "Unable to find field info");
- return I->second;
-}
-
-/// addFieldInfo - Assign field number to field FD.
-void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) {
- FieldInfo[FD] = No;
-}
-
-/// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field FD.
-CodeGenTypes::BitFieldInfo CodeGenTypes::getBitFieldInfo(const FieldDecl *FD) {
- llvm::DenseMap<const FieldDecl *, BitFieldInfo>::iterator
- I = BitFields.find(FD);
- assert (I != BitFields.end() && "Unable to find bitfield info");
- return I->second;
-}
-
-/// addBitFieldInfo - Assign a start bit and a size to field FD.
-void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
- unsigned Start, unsigned Size) {
- BitFields.insert(std::make_pair(FD, BitFieldInfo(FieldNo, Start, Size)));
-}
-
/// getCGRecordLayout - Return record layout info for the given llvm::Type.
const CGRecordLayout &
-CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
+CodeGenTypes::getCGRecordLayout(const RecordDecl *TD) const {
const Type *Key = Context.getTagDeclType(TD).getTypePtr();
- llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I
- = CGRecordLayouts.find(Key);
- assert (I != CGRecordLayouts.end()
- && "Unable to find record layout information for type");
- return *I->second;
+ const CGRecordLayout *Layout = CGRecordLayouts.lookup(Key);
+ assert(Layout && "Unable to find record layout information for type");
+ return *Layout;
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index b2912ef..9b74106d 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -16,7 +16,6 @@
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallSet.h"
#include <vector>
#include "CGCall.h"
@@ -52,37 +51,9 @@ namespace clang {
typedef CanQual<Type> CanQualType;
namespace CodeGen {
+ class CGRecordLayout;
class CodeGenTypes;
- /// CGRecordLayout - This class handles struct and union layout info while
- /// lowering AST types to LLVM types.
- class CGRecordLayout {
- CGRecordLayout(); // DO NOT IMPLEMENT
-
- /// LLVMType - The LLVMType corresponding to this record layout.
- const llvm::Type *LLVMType;
-
- /// ContainsPointerToDataMember - Whether one of the fields in this record
- /// layout is a pointer to data member, or a struct that contains pointer to
- /// data member.
- bool ContainsPointerToDataMember;
-
- public:
- CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
- : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { }
-
- /// getLLVMType - Return llvm type associated with this record.
- const llvm::Type *getLLVMType() const {
- return LLVMType;
- }
-
- /// containsPointerToDataMember - Whether this struct contains pointers to
- /// data members.
- bool containsPointerToDataMember() const {
- return ContainsPointerToDataMember;
- }
- };
-
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
@@ -107,32 +78,12 @@ class CodeGenTypes {
/// CGRecordLayouts - This maps llvm struct type with corresponding
/// record layout info.
- /// FIXME : If CGRecordLayout is less than 16 bytes then use
- /// inline it in the map.
llvm::DenseMap<const Type*, CGRecordLayout *> CGRecordLayouts;
- /// FieldInfo - This maps struct field with corresponding llvm struct type
- /// field no. This info is populated by record organizer.
- llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
-
/// FunctionInfos - Hold memoized CGFunctionInfo results.
llvm::FoldingSet<CGFunctionInfo> FunctionInfos;
-public:
- struct BitFieldInfo {
- BitFieldInfo(unsigned FieldNo,
- unsigned Start,
- unsigned Size)
- : FieldNo(FieldNo), Start(Start), Size(Size) {}
-
- unsigned FieldNo;
- unsigned Start;
- unsigned Size;
- };
-
private:
- llvm::DenseMap<const FieldDecl *, BitFieldInfo> BitFields;
-
/// TypeCache - This map keeps cache of llvm::Types (through PATypeHolder)
/// and maps llvm::Types to corresponding clang::Type. llvm::PATypeHolder is
/// used instead of llvm::Type because it allows us to bypass potential
@@ -178,11 +129,7 @@ public:
/// and/or incomplete argument types, this will return the opaque type.
const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
- const CGRecordLayout &getCGRecordLayout(const TagDecl*) const;
-
- /// getLLVMFieldNo - Return llvm::StructType element number
- /// that corresponds to the field FD.
- unsigned getLLVMFieldNo(const FieldDecl *FD);
+ const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const;
/// UpdateCompletedType - When we find the full definition for a TagDecl,
/// replace the 'opaque' type we previously made for it if applicable.
@@ -202,7 +149,7 @@ public:
const CGFunctionInfo &getFunctionInfo(const CallArgList &Args,
const FunctionType *Ty) {
return getFunctionInfo(Ty->getResultType(), Args,
- Ty->getCallConv(), Ty->getNoReturnAttr());
+ Ty->getExtInfo());
}
const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty);
@@ -216,33 +163,22 @@ public:
/// specified, the "C" calling convention will be used.
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const CallArgList &Args,
- CallingConv CC,
- bool NoReturn);
+ const FunctionType::ExtInfo &Info);
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
- CallingConv CC,
- bool NoReturn);
+ const FunctionType::ExtInfo &Info);
/// Retrieves the ABI information for the given function signature.
///
/// \param ArgTys - must all actually be canonical as params
const CGFunctionInfo &getFunctionInfo(CanQualType RetTy,
const llvm::SmallVectorImpl<CanQualType> &ArgTys,
- CallingConv CC,
- bool NoReturn);
+ const FunctionType::ExtInfo &Info);
-public: // These are internal details of CGT that shouldn't be used externally.
- /// addFieldInfo - Assign field number to field FD.
- void addFieldInfo(const FieldDecl *FD, unsigned FieldNo);
-
- /// addBitFieldInfo - Assign a start bit and a size to field FD.
- void addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo,
- unsigned Start, unsigned Size);
-
- /// getBitFieldInfo - Return the BitFieldInfo that corresponds to the field
- /// FD.
- BitFieldInfo getBitFieldInfo(const FieldDecl *FD);
+ /// \brief Compute a new LLVM record layout object for the given record.
+ CGRecordLayout *ComputeRecordLayout(const RecordDecl *D);
+public: // These are internal details of CGT that shouldn't be used externally.
/// ConvertTagDeclType - Lay out a tagged decl type like struct or union or
/// enum.
const llvm::Type *ConvertTagDeclType(const TagDecl *TD);
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index f2a73f1..077db7c 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -102,7 +102,7 @@ public:
llvm::raw_svector_ostream &getStream() { return Out; }
void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
- void mangleCallOffset(const ThunkAdjustment &Adjustment);
+ void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
void mangleNumber(int64_t Number);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleName(const NamedDecl *ND);
@@ -439,23 +439,23 @@ void CXXNameMangler::mangleNumber(int64_t Number) {
Out << Number;
}
-void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
+void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number> # non-virtual base override
// <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
- if (!Adjustment.Virtual) {
+ if (!Virtual) {
Out << 'h';
- mangleNumber(Adjustment.NonVirtual);
+ mangleNumber(NonVirtual);
Out << '_';
return;
}
Out << 'v';
- mangleNumber(Adjustment.NonVirtual);
+ mangleNumber(NonVirtual);
Out << '_';
- mangleNumber(Adjustment.Virtual);
+ mangleNumber(Virtual);
Out << '_';
}
@@ -1131,15 +1131,20 @@ void CXXNameMangler::mangleType(const ComplexType *T) {
}
// GNU extension: vector types
+// <type> ::= <vector-type>
+// <vector-type> ::= Dv <positive dimension number> _ <element type>
+// ::= Dv [<dimension expression>] _ <element type>
void CXXNameMangler::mangleType(const VectorType *T) {
- Out << "U8__vector";
+ Out << "Dv" << T->getNumElements() << '_';
mangleType(T->getElementType());
}
void CXXNameMangler::mangleType(const ExtVectorType *T) {
mangleType(static_cast<const VectorType*>(T));
}
void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
- Out << "U8__vector";
+ Out << "Dv";
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
mangleType(T->getElementType());
}
@@ -1159,7 +1164,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
mangleName(TD, T->getArgs(), T->getNumArgs());
}
-void CXXNameMangler::mangleType(const TypenameType *T) {
+void CXXNameMangler::mangleType(const DependentNameType *T) {
// Typename types are always nested
Out << 'N';
mangleUnresolvedScope(T->getQualifier());
@@ -1451,8 +1456,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// It isn't clear that we ever actually want to have such a
// nested-name-specifier; why not just represent it as a typename type?
if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) {
- QTy = getASTContext().getTypenameType(NNS->getPrefix(),
- NNS->getAsIdentifier())
+ QTy = getASTContext().getDependentNameType(ETK_Typename,
+ NNS->getPrefix(),
+ NNS->getAsIdentifier())
.getTypePtr();
}
assert(QTy && "Qualifier was not type!");
@@ -1862,52 +1868,50 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
Mangler.mangle(D);
}
-/// \brief Mangles the a thunk with the offset n for the declaration D and
-/// emits that name to the given output stream.
-void MangleContext::mangleThunk(const FunctionDecl *FD,
- const ThunkAdjustment &ThisAdjustment,
+void MangleContext::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
llvm::SmallVectorImpl<char> &Res) {
- assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
-
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Use mangleCXXDtor for destructor decls!");
+
CXXNameMangler Mangler(*this, Res);
Mangler.getStream() << "_ZT";
- Mangler.mangleCallOffset(ThisAdjustment);
- Mangler.mangleFunctionEncoding(FD);
-}
-
-void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D,
- CXXDtorType Type,
- const ThunkAdjustment &ThisAdjustment,
- llvm::SmallVectorImpl<char> &Res) {
+ if (!Thunk.Return.isEmpty())
+ Mangler.getStream() << 'c';
+
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
+
+ // Mangle the return pointer adjustment if there is one.
+ if (!Thunk.Return.isEmpty())
+ Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ Mangler.mangleFunctionEncoding(MD);
+}
+
+void
+MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &Res) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
- CXXNameMangler Mangler(*this, Res, D, Type);
+
+ CXXNameMangler Mangler(*this, Res, DD, Type);
Mangler.getStream() << "_ZT";
- Mangler.mangleCallOffset(ThisAdjustment);
- Mangler.mangleFunctionEncoding(D);
-}
-/// \brief Mangles the a covariant thunk for the declaration D and emits that
-/// name to the given output stream.
-void
-MangleContext::mangleCovariantThunk(const FunctionDecl *FD,
- const CovariantThunkAdjustment& Adjustment,
- llvm::SmallVectorImpl<char> &Res) {
- assert(!isa<CXXDestructorDecl>(FD) &&
- "No such thing as a covariant thunk for a destructor!");
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
+ ThisAdjustment.VCallOffsetOffset);
- // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- // # first call-offset is 'this' adjustment
- // # second call-offset is result adjustment
- CXXNameMangler Mangler(*this, Res);
- Mangler.getStream() << "_ZTc";
- Mangler.mangleCallOffset(Adjustment.ThisAdjustment);
- Mangler.mangleCallOffset(Adjustment.ReturnAdjustment);
- Mangler.mangleFunctionEncoding(FD);
+ Mangler.mangleFunctionEncoding(DD);
}
/// mangleGuardVariable - Returns the mangled name for a guard variable
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 62656b9..91a5e97 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -28,13 +28,14 @@ namespace clang {
class ASTContext;
class CXXConstructorDecl;
class CXXDestructorDecl;
+ class CXXMethodDecl;
class FunctionDecl;
class NamedDecl;
class VarDecl;
namespace CodeGen {
- class CovariantThunkAdjustment;
- class ThunkAdjustment;
+ struct ThisAdjustment;
+ struct ThunkInfo;
/// MangleBuffer - a convenient class for storing a name which is
/// either the result of a mangling or is a constant string with
@@ -91,15 +92,12 @@ public:
bool shouldMangleDeclName(const NamedDecl *D);
void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
- void mangleThunk(const FunctionDecl *FD,
- const ThunkAdjustment &ThisAdjustment,
+ void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
llvm::SmallVectorImpl<char> &);
- void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type,
- const ThunkAdjustment &ThisAdjustment,
+ void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
llvm::SmallVectorImpl<char> &);
- void mangleCovariantThunk(const FunctionDecl *FD,
- const CovariantThunkAdjustment& Adjustment,
- llvm::SmallVectorImpl<char> &);
void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 60d8e9c..7efcd8a 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -10,8 +10,8 @@ add_clang_library(clangDriver
DriverOptions.cpp
HostInfo.cpp
Job.cpp
- OptTable.cpp
Option.cpp
+ OptTable.cpp
Phases.cpp
Tool.cpp
ToolChain.cpp
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index acfff38..921147f 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -45,7 +45,8 @@ using namespace clang;
Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
llvm::StringRef _DefaultHostTriple,
llvm::StringRef _DefaultImageName,
- bool IsProduction, Diagnostic &_Diags)
+ bool IsProduction, bool CXXIsProduction,
+ Diagnostic &_Diags)
: Opts(createDriverOptTable()), Diags(_Diags),
Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
DefaultImageName(_DefaultImageName),
@@ -66,7 +67,8 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
CCCClangArchs.insert(llvm::Triple::x86_64);
CCCClangArchs.insert(llvm::Triple::arm);
- CCCUseClangCXX = false;
+ if (!CXXIsProduction)
+ CCCUseClangCXX = false;
}
// Compute the path to the resource directory.
@@ -172,6 +174,8 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) {
HostTriple = A->getValue(*Args);
if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
Dir = A->getValue(*Args);
+ if (const Arg *A = Args->getLastArg(options::OPT_B))
+ PrefixDir = A->getValue(*Args);
Host = GetHostInfo(HostTriple);
@@ -1088,6 +1092,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
}
std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
+ // Respect a limited subset of the '-Bprefix' functionality in GCC by
+ // attempting to use this prefix when lokup up program paths.
+ if (!PrefixDir.empty()) {
+ llvm::sys::Path P(PrefixDir);
+ P.appendComponent(Name);
+ if (P.exists())
+ return P.str();
+ }
+
const ToolChain::path_list &List = TC.getFilePaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
@@ -1102,6 +1115,15 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const {
std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC,
bool WantFile) const {
+ // Respect a limited subset of the '-Bprefix' functionality in GCC by
+ // attempting to use this prefix when lokup up program paths.
+ if (!PrefixDir.empty()) {
+ llvm::sys::Path P(PrefixDir);
+ P.appendComponent(Name);
+ if (WantFile ? P.exists() : P.canExecute())
+ return P.str();
+ }
+
const ToolChain::path_list &List = TC.getProgramPaths();
for (ToolChain::path_list::const_iterator
it = List.begin(), ie = List.end(); it != ie; ++it) {
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index d8e086d..d9e2e37 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -144,13 +144,15 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args,
TCTriple.setArch(Arch);
// If we recognized the arch, match it to the toolchains we support.
- if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ const char *UseNewToolChain = ::getenv("CCC_ENABLE_NEW_DARWIN_TOOLCHAIN");
+ if (UseNewToolChain ||
+ Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
+ TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion);
+ } else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
// We still use the legacy DarwinGCC toolchain on X86.
TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion,
GCCVersion);
- } else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion);
- else
+ } else
TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple);
}
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 1c34df0..2a37991 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -56,6 +56,35 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
<< A->getAsString(Args) << "-static";
}
+// Quote target names for inclusion in GNU Make dependency files.
+// Only the characters '$', '#', ' ', '\t' are quoted.
+static void QuoteTarget(llvm::StringRef Target,
+ llvm::SmallVectorImpl<char> &Res) {
+ for (unsigned i = 0, e = Target.size(); i != e; ++i) {
+ switch (Target[i]) {
+ case ' ':
+ case '\t':
+ // Escape the preceding backslashes
+ for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
+ Res.push_back('\\');
+
+ // Escape the space/tab
+ Res.push_back('\\');
+ break;
+ case '$':
+ Res.push_back('$');
+ break;
+ case '#':
+ Res.push_back('\\');
+ break;
+ default:
+ break;
+ }
+
+ Res.push_back(Target[i]);
+ }
+}
+
void Clang::AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -91,9 +120,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
- // Add an -MT option if the user didn't specify their own.
- //
- // FIXME: This should use -MQ, when we support it.
+ // Add a default target if one wasn't specified.
if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
const char *DepTarget;
@@ -114,7 +141,9 @@ void Clang::AddPreprocessingOptions(const Driver &D,
}
CmdArgs.push_back("-MT");
- CmdArgs.push_back(DepTarget);
+ llvm::SmallString<128> Quoted;
+ QuoteTarget(DepTarget, Quoted);
+ CmdArgs.push_back(Args.MakeArgString(Quoted));
}
if (A->getOption().matches(options::OPT_M) ||
@@ -123,7 +152,25 @@ void Clang::AddPreprocessingOptions(const Driver &D,
}
Args.AddLastArg(CmdArgs, options::OPT_MP);
- Args.AddAllArgs(CmdArgs, options::OPT_MT);
+
+ // Convert all -MQ <target> args to -MT <quoted target>
+ for (arg_iterator it = Args.filtered_begin(options::OPT_MT,
+ options::OPT_MQ),
+ ie = Args.filtered_end(); it != ie; ++it) {
+
+ it->claim();
+
+ if (it->getOption().matches(options::OPT_MQ)) {
+ CmdArgs.push_back("-MT");
+ llvm::SmallString<128> Quoted;
+ QuoteTarget(it->getValue(Args), Quoted);
+ CmdArgs.push_back(Args.MakeArgString(Quoted));
+
+ // -MT flag - no change
+ } else {
+ it->render(Args, CmdArgs);
+ }
+ }
// Add -i* options, and automatically translate to
// -include-pch/-include-pth for transparent PCH support. It's
@@ -796,6 +843,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("plist");
+ // Disable the presentation of standard compiler warnings when
+ // using --analyze. We only want to show static analyzer diagnostics
+ // or frontend errors.
+ CmdArgs.push_back("-w");
+
// Add -Xanalyzer arguments when running as analyzer.
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
}
@@ -925,7 +977,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
- (Unsupported = Args.getLastArg(options::OPT_MQ)) ||
(Unsupported = Args.getLastArg(options::OPT_iframework)) ||
(Unsupported = Args.getLastArg(options::OPT_fshort_enums)))
D.Diag(clang::diag::err_drv_clang_unsupported)
@@ -943,6 +994,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-g");
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
+ Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
// Pass the path to compiler resource files.
@@ -1701,6 +1753,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
if (!Args.hasArg(options::OPT_Q))
CmdArgs.push_back("-quiet");
Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
+ Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_v);
Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
Args.AddLastArg(CmdArgs, options::OPT_P);
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 935c415..7243f70 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -378,7 +378,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
- "a.out", false, Diags);
+ "a.out", false, false, Diags);
// Don't check that inputs exist, they have been remapped.
TheDriver.setCheckInputsExist(false);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 7b4932d..879e9f6 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -29,6 +29,7 @@
#include "llvm/LLVMContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Timer.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
@@ -479,6 +480,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
if (getFrontendOpts().ShowTimers)
createFrontendTimer();
+ if (getFrontendOpts().ShowStats)
+ llvm::EnableStatistics();
+
for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) {
const std::string &InFile = getFrontendOpts().Inputs[i].second;
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6e18f34..dc2c6bf 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -436,6 +436,8 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
}
if (!Opts.UseStandardIncludes)
Res.push_back("-nostdinc");
+ if (!Opts.UseStandardCXXIncludes)
+ Res.push_back("-nostdinc++");
if (Opts.Verbose)
Res.push_back("-v");
}
@@ -1014,6 +1016,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.Verbose = Args.hasArg(OPT_v);
Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc);
Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc);
+ Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx);
Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir);
// Add -I... and -F... options in order.
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index de2b056..14aee35 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -48,14 +48,15 @@ public:
IncludeSystemHeaders(Opts.IncludeSystemHeaders),
PhonyTarget(Opts.UsePhonyTargets) {}
- ~DependencyFileCallback() {
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+
+ virtual void EndOfMainFile() {
OutputDependencyFile();
OS->flush();
delete OS;
+ OS = 0;
}
-
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType);
};
}
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
index 0b04cf2..20d452e 100644
--- a/lib/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -93,7 +93,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
// completely ignore it, even if it's an error: fix-it locations
// are meant to perform specific fix-ups even in the presence of
// other errors.
- if (Info.getNumCodeModificationHints() == 0)
+ if (Info.getNumFixItHints() == 0)
return;
// See if the location of the error is one that matches what the
@@ -122,10 +122,10 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
// Make sure that we can perform all of the modifications we
// in this diagnostic.
- bool CanRewrite = Info.getNumCodeModificationHints() > 0;
- for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ bool CanRewrite = Info.getNumFixItHints() > 0;
+ for (unsigned Idx = 0, Last = Info.getNumFixItHints();
Idx < Last; ++Idx) {
- const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ const FixItHint &Hint = Info.getFixItHint(Idx);
if (Hint.RemoveRange.isValid() &&
Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
CanRewrite = false;
@@ -140,7 +140,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
}
if (!CanRewrite) {
- if (Info.getNumCodeModificationHints() > 0)
+ if (Info.getNumFixItHints() > 0)
Diag(Info.getLocation(), diag::note_fixit_in_macro);
// If this was an error, refuse to perform any rewriting.
@@ -152,9 +152,9 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
}
bool Failed = false;
- for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ for (unsigned Idx = 0, Last = Info.getNumFixItHints();
Idx < Last; ++Idx) {
- const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ const FixItHint &Hint = Info.getFixItHint(Idx);
if (!Hint.RemoveRange.isValid()) {
// We're adding code.
if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert))
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 66df7a6..110612d 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -169,6 +169,10 @@ void FrontendAction::EndSourceFile() {
CI.setASTContext(0);
}
+ // Inform the preprocessor we are done.
+ if (CI.hasPreprocessor())
+ CI.getPreprocessor().EndSourceFile();
+
if (CI.getFrontendOpts().ShowStats) {
llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
CI.getPreprocessor().PrintStats();
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index da99cb8..022a34d 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -484,8 +484,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// FIXME: This code is disabled because it seems to mangle the HTML
// output. I'm leaving it here because it's generally the right idea,
// but needs some help from someone more familiar with the rewriter.
- for (const CodeModificationHint *Hint = P.code_modifications_begin(),
- *HintEnd = P.code_modifications_end();
+ for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end();
Hint != HintEnd; ++Hint) {
if (Hint->RemoveRange.isValid()) {
HighlightRange(R, LPosInfo.first, Hint->RemoveRange,
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index cd749d2..9f5bced 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -82,7 +82,8 @@ public:
/// AddDefaultSystemIncludePaths - Adds the default system include paths so
/// that e.g. stdio.h is found.
void AddDefaultSystemIncludePaths(const LangOptions &Lang,
- const llvm::Triple &triple);
+ const llvm::Triple &triple,
+ bool UseStandardCXXIncludes);
/// Realize - Merges all search path lists into one list and send it to
/// HeaderSearch.
@@ -594,8 +595,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
}
void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
- const llvm::Triple &triple) {
- if (Lang.CPlusPlus)
+ const llvm::Triple &triple,
+ bool UseStandardCXXIncludes) {
+ if (Lang.CPlusPlus && UseStandardCXXIncludes)
AddDefaultCPlusPlusIncludePaths(triple);
AddDefaultCIncludePaths(triple);
@@ -765,7 +767,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
}
if (HSOpts.UseStandardIncludes)
- Init.AddDefaultSystemIncludePaths(Lang, Triple);
+ Init.AddDefaultSystemIncludePaths(Lang, Triple,
+ HSOpts.UseStandardCXXIncludes);
Init.Realize();
}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index e659ff0..6d39952 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -905,11 +905,18 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
return Failure;
}
- if (Record.size() < 8) {
+ if (Record.size() < 10) {
Error("source location entry is incorrect");
return Failure;
}
+ if ((off_t)Record[4] != File->getSize() ||
+ (time_t)Record[5] != File->getModificationTime()) {
+ Diag(diag::err_fe_pch_file_modified)
+ << Filename;
+ return Failure;
+ }
+
FileID FID = SourceMgr.createFileID(File,
SourceLocation::getFromRawEncoding(Record[1]),
(SrcMgr::CharacteristicKind)Record[2],
@@ -920,10 +927,10 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
// Reconstruct header-search information for this file.
HeaderFileInfo HFI;
- HFI.isImport = Record[4];
- HFI.DirInfo = Record[5];
- HFI.NumIncludes = Record[6];
- HFI.ControllingMacroID = Record[7];
+ HFI.isImport = Record[6];
+ HFI.DirInfo = Record[7];
+ HFI.NumIncludes = Record[8];
+ HFI.ControllingMacroID = Record[9];
if (Listener)
Listener->ReadHeaderFileInfo(HFI, File->getUID());
break;
@@ -2068,20 +2075,21 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
}
case pch::TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 3) {
+ if (Record.size() != 4) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = GetType(Record[0]);
- return Context->getFunctionNoProtoType(ResultType, Record[1],
- (CallingConv)Record[2]);
+ FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]);
+ return Context->getFunctionNoProtoType(ResultType, Info);
}
case pch::TYPE_FUNCTION_PROTO: {
QualType ResultType = GetType(Record[0]);
bool NoReturn = Record[1];
- CallingConv CallConv = (CallingConv)Record[2];
- unsigned Idx = 3;
+ unsigned RegParm = Record[2];
+ CallingConv CallConv = (CallingConv)Record[3];
+ unsigned Idx = 4;
unsigned NumParams = Record[Idx++];
llvm::SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
@@ -2097,7 +2105,9 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
- Exceptions.data(), NoReturn, CallConv);
+ Exceptions.data(),
+ FunctionType::ExtInfo(NoReturn, RegParm,
+ CallConv));
}
case pch::TYPE_UNRESOLVED_USING:
@@ -2341,7 +2351,7 @@ void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
-void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) {
+void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 4752cd3..4dd8dc3 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -141,9 +141,11 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getResultType(), Record);
- Record.push_back(T->getNoReturnAttr());
+ FunctionType::ExtInfo C = T->getExtInfo();
+ Record.push_back(C.getNoReturn());
+ Record.push_back(C.getRegParm());
// FIXME: need to stabilize encoding of calling convention...
- Record.push_back(T->getCallConv());
+ Record.push_back(C.getCC());
}
void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -404,7 +406,7 @@ void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) {
void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
-void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) {
+void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
@@ -921,6 +923,9 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives
+ // FileEntry fields.
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
// HeaderFileInfo fields.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo
@@ -1063,6 +1068,10 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// The source location entry is a file. The blob associated
// with this entry is the file name.
+ // Emit size/modification time for this file.
+ Record.push_back(Content->Entry->getSize());
+ Record.push_back(Content->Entry->getModificationTime());
+
// Emit header-search information associated with this file.
HeaderFileInfo HFI;
HeaderSearch &HS = PP.getHeaderSearchInfo();
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 79aecce..cba9298 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -2262,8 +2262,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SelGetUidIdent, getFuncType, 0,
@@ -2359,8 +2359,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
false, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2380,8 +2380,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2404,8 +2404,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2425,8 +2425,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2451,8 +2451,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2472,8 +2472,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
QualType msgSendType = Context->getFunctionType(Context->DoubleTy,
&ArgTys[0], ArgTys.size(),
true /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
msgSendIdent, msgSendType, 0,
@@ -2488,8 +2488,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
@@ -2505,8 +2505,8 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
QualType getClassType = Context->getFunctionType(Context->getObjCClassType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getSuperClassIdent, getClassType, 0,
@@ -2521,8 +2521,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
&ArgTys[0], ArgTys.size(),
false /*isVariadic*/, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
getClassIdent, getClassType, 0,
@@ -2964,8 +2964,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
&ArgTypes[0], ArgTypes.size(),
// If we don't have a method decl, force a variadic cast.
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
cast);
@@ -2995,8 +2995,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
castType = Context->getFunctionType(returnType,
&ArgTypes[0], ArgTypes.size(),
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0,
- false, false, 0, 0, false,
- CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
cast);
@@ -4547,7 +4547,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
QualType PtrToFuncCastType = Context->getFunctionType(Exp->getType(),
&ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0,
false, false, 0, 0,
- false, CC_Default);
+ FunctionType::ExtInfo());
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
@@ -5673,4 +5673,3 @@ void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
}
OutFile->flush();
}
-
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 24d51e2..4e91f8d 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -276,7 +276,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
SourceRange *Ranges,
unsigned NumRanges,
SourceManager &SM,
- const CodeModificationHint *Hints,
+ const FixItHint *Hints,
unsigned NumHints,
unsigned Columns) {
assert(LangOpts && "Unexpected diagnostic outside source file processing");
@@ -409,7 +409,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
std::string FixItInsertionLine;
if (NumHints && DiagOpts->ShowFixits) {
- for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints;
+ for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints;
Hint != LastHint; ++Hint) {
if (Hint->InsertionLoc.isValid()) {
// We have an insertion hint. Determine whether the inserted
@@ -833,7 +833,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (DiagOpts->ShowCarets && Info.getLocation().isValid() &&
((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
(LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
- Info.getNumCodeModificationHints())) {
+ Info.getNumFixItHints())) {
// Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
LastLoc = Info.getLocation();
LastCaretDiagnosticWasNote = (Level == Diagnostic::Note);
@@ -845,9 +845,9 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
for (unsigned i = 0; i != NumRanges; ++i)
Ranges[i] = Info.getRange(i);
- unsigned NumHints = Info.getNumCodeModificationHints();
+ unsigned NumHints = Info.getNumFixItHints();
for (unsigned idx = 0; idx < NumHints; ++idx) {
- const CodeModificationHint &Hint = Info.getCodeModificationHint(idx);
+ const FixItHint &Hint = Info.getFixItHint(idx);
if (Hint.RemoveRange.isValid()) {
assert(NumRanges < 20 && "Out of space");
Ranges[NumRanges++] = Hint.RemoveRange;
@@ -855,8 +855,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
}
EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
- Info.getCodeModificationHints(),
- Info.getNumCodeModificationHints(),
+ Info.getFixItHints(),
+ Info.getNumFixItHints(),
DiagOpts->MessageLength);
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index b09a627..6b9dd2a 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -36,417 +36,417 @@ typedef long long __m128i __attribute__((__vector_size__(16)));
typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_add_sd(__m128d a, __m128d b)
{
a[0] += b[0];
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_add_pd(__m128d a, __m128d b)
{
return a + b;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_sub_sd(__m128d a, __m128d b)
{
a[0] -= b[0];
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_sub_pd(__m128d a, __m128d b)
{
return a - b;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_mul_sd(__m128d a, __m128d b)
{
a[0] *= b[0];
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_mul_pd(__m128d a, __m128d b)
{
return a * b;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_div_sd(__m128d a, __m128d b)
{
a[0] /= b[0];
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_div_pd(__m128d a, __m128d b)
{
return a / b;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_sd(__m128d a, __m128d b)
{
__m128d c = __builtin_ia32_sqrtsd(b);
return (__m128d) { c[0], a[1] };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_pd(__m128d a)
{
return __builtin_ia32_sqrtpd(a);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_min_sd(__m128d a, __m128d b)
{
return __builtin_ia32_minsd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_min_pd(__m128d a, __m128d b)
{
return __builtin_ia32_minpd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_max_sd(__m128d a, __m128d b)
{
return __builtin_ia32_maxsd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_max_pd(__m128d a, __m128d b)
{
return __builtin_ia32_maxpd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_and_pd(__m128d a, __m128d b)
{
return (__m128d)((__v4si)a & (__v4si)b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_andnot_pd(__m128d a, __m128d b)
{
return (__m128d)(~(__v4si)a & (__v4si)b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_or_pd(__m128d a, __m128d b)
{
return (__m128d)((__v4si)a | (__v4si)b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_xor_pd(__m128d a, __m128d b)
{
return (__m128d)((__v4si)a ^ (__v4si)b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 0);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmple_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(b, a, 1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(b, a, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 7);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 3);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 4);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 5);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(a, b, 6);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(b, a, 5);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_pd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmppd(b, a, 6);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 0);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmple_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(b, a, 1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(b, a, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 7);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 3);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 4);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 5);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(a, b, 6);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(b, a, 5);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_sd(__m128d a, __m128d b)
{
return (__m128d)__builtin_ia32_cmpsd(b, a, 6);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comieq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdeq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comilt_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdlt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comile_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdle(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comigt_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdgt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comineq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_comisdneq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomieq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdeq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomilt_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdlt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomile_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdle(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomigt_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdgt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomineq_sd(__m128d a, __m128d b)
{
return __builtin_ia32_ucomisdneq(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpd_ps(__m128d a)
{
return __builtin_ia32_cvtpd2ps(a);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtps_pd(__m128 a)
{
return __builtin_ia32_cvtps2pd(a);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi32_pd(__m128i a)
{
return __builtin_ia32_cvtdq2pd((__v4si)a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtpd_epi32(__m128d a)
{
return __builtin_ia32_cvtpd2dq(a);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvtsd_si32(__m128d a)
{
return __builtin_ia32_cvtsd2si(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtsd_ss(__m128 a, __m128d b)
{
a[0] = b[0];
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi32_sd(__m128d a, int b)
{
a[0] = b;
return a;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtss_sd(__m128d a, __m128 b)
{
a[0] = b[0];
return a;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvttpd_epi32(__m128d a)
{
return (__m128i)__builtin_ia32_cvttpd2dq(a);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvttsd_si32(__m128d a)
{
return a[0];
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpd_pi32(__m128d a)
{
return (__m64)__builtin_ia32_cvtpd2pi(a);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvttpd_pi32(__m128d a)
{
return (__m64)__builtin_ia32_cvttpd2pi(a);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtpi32_pd(__m64 a)
{
return __builtin_ia32_cvtpi2pd((__v2si)a);
}
-static inline double __attribute__((__always_inline__, __nodebug__))
+static __inline__ double __attribute__((__always_inline__, __nodebug__))
_mm_cvtsd_f64(__m128d a)
{
return a[0];
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_load_pd(double const *dp)
{
return *(__m128d*)dp;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_load1_pd(double const *dp)
{
return (__m128d){ dp[0], dp[0] };
@@ -454,542 +454,542 @@ _mm_load1_pd(double const *dp)
#define _mm_load_pd1(dp) _mm_load1_pd(dp)
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadr_pd(double const *dp)
{
return (__m128d){ dp[1], dp[0] };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadu_pd(double const *dp)
{
return __builtin_ia32_loadupd(dp);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_load_sd(double const *dp)
{
return (__m128d){ *dp, 0.0 };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadh_pd(__m128d a, double const *dp)
{
return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadl_pd(__m128d a, double const *dp)
{
return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_set_sd(double w)
{
return (__m128d){ w, 0 };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_set1_pd(double w)
{
return (__m128d){ w, w };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_set_pd(double w, double x)
{
return (__m128d){ x, w };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_setr_pd(double w, double x)
{
return (__m128d){ w, x };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_setzero_pd(void)
{
return (__m128d){ 0, 0 };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_move_sd(__m128d a, __m128d b)
{
return (__m128d){ b[0], a[1] };
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store_sd(double *dp, __m128d a)
{
dp[0] = a[0];
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store1_pd(double *dp, __m128d a)
{
dp[0] = a[0];
dp[1] = a[0];
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store_pd(double *dp, __m128d a)
{
*(__m128d *)dp = a;
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storeu_pd(double *dp, __m128d a)
{
__builtin_ia32_storeupd(dp, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storer_pd(double *dp, __m128d a)
{
dp[0] = a[1];
dp[1] = a[0];
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storeh_pd(double *dp, __m128d a)
{
dp[0] = a[1];
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storel_pd(double *dp, __m128d a)
{
dp[0] = a[0];
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_add_epi8(__m128i a, __m128i b)
{
return (__m128i)((__v16qi)a + (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_add_epi16(__m128i a, __m128i b)
{
return (__m128i)((__v8hi)a + (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_add_epi32(__m128i a, __m128i b)
{
return (__m128i)((__v4si)a + (__v4si)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_add_si64(__m64 a, __m64 b)
{
return a + b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_add_epi64(__m128i a, __m128i b)
{
return a + b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_adds_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_paddsb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_adds_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_paddsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_adds_epu8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_paddusb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_adds_epu16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_paddusw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_avg_epu8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pavgb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_avg_epu16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pavgw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_madd_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epu8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmaxub128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pminsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epu8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pminub128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mulhi_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmulhw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mulhi_epu16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mullo_epi16(__m128i a, __m128i b)
{
return (__m128i)((__v8hi)a * (__v8hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_mul_su32(__m64 a, __m64 b)
{
return __builtin_ia32_pmuludq((__v2si)a, (__v2si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mul_epu32(__m128i a, __m128i b)
{
return __builtin_ia32_pmuludq128((__v4si)a, (__v4si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sad_epu8(__m128i a, __m128i b)
{
return __builtin_ia32_psadbw128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sub_epi8(__m128i a, __m128i b)
{
return (__m128i)((__v16qi)a - (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sub_epi16(__m128i a, __m128i b)
{
return (__m128i)((__v8hi)a - (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sub_epi32(__m128i a, __m128i b)
{
return (__m128i)((__v4si)a - (__v4si)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sub_si64(__m64 a, __m64 b)
{
return a - b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sub_epi64(__m128i a, __m128i b)
{
return a - b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_subs_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psubsb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_subs_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psubsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_subs_epu8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psubusb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_subs_epu16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psubusw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_and_si128(__m128i a, __m128i b)
{
return a & b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_andnot_si128(__m128i a, __m128i b)
{
return ~a & b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_or_si128(__m128i a, __m128i b)
{
return a | b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_xor_si128(__m128i a, __m128i b)
{
return a ^ b;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_slli_si128(__m128i a, int imm)
{
return __builtin_ia32_pslldqi128(a, imm * 8);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_slli_epi16(__m128i a, int count)
{
return (__m128i)__builtin_ia32_psllwi128((__v8hi)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sll_epi16(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_psllw128((__v8hi)a, (__v8hi)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_slli_epi32(__m128i a, int count)
{
return (__m128i)__builtin_ia32_pslldi128((__v4si)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sll_epi32(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_pslld128((__v4si)a, (__v4si)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_slli_epi64(__m128i a, int count)
{
return __builtin_ia32_psllqi128(a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sll_epi64(__m128i a, __m128i count)
{
return __builtin_ia32_psllq128(a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srai_epi16(__m128i a, int count)
{
return (__m128i)__builtin_ia32_psrawi128((__v8hi)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sra_epi16(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_psraw128((__v8hi)a, (__v8hi)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srai_epi32(__m128i a, int count)
{
return (__m128i)__builtin_ia32_psradi128((__v4si)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sra_epi32(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_psrad128((__v4si)a, (__v4si)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srli_si128(__m128i a, int imm)
{
return __builtin_ia32_psrldqi128(a, imm * 8);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srli_epi16(__m128i a, int count)
{
return (__m128i)__builtin_ia32_psrlwi128((__v8hi)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srl_epi16(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_psrlw128((__v8hi)a, (__v8hi)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srli_epi32(__m128i a, int count)
{
return (__m128i)__builtin_ia32_psrldi128((__v4si)a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srl_epi32(__m128i a, __m128i count)
{
return (__m128i)__builtin_ia32_psrld128((__v4si)a, (__v4si)count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srli_epi64(__m128i a, int count)
{
return __builtin_ia32_psrlqi128(a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_srl_epi64(__m128i a, __m128i count)
{
return __builtin_ia32_psrlq128(a, count);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi8(__m128i a, __m128i b)
{
return (__m128i)((__v16qi)a == (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi16(__m128i a, __m128i b)
{
return (__m128i)((__v8hi)a == (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi32(__m128i a, __m128i b)
{
return (__m128i)((__v4si)a == (__v4si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi8(__m128i a, __m128i b)
{
return (__m128i)((__v16qi)a > (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi16(__m128i a, __m128i b)
{
return (__m128i)((__v8hi)a > (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi32(__m128i a, __m128i b)
{
return (__m128i)((__v4si)a > (__v4si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_epi8(__m128i a, __m128i b)
{
return _mm_cmpgt_epi8(b,a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_epi16(__m128i a, __m128i b)
{
return _mm_cmpgt_epi16(b,a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_epi32(__m128i a, __m128i b)
{
return _mm_cmpgt_epi32(b,a);
}
#ifdef __x86_64__
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi64_sd(__m128d a, long long b)
{
a[0] = b;
return a;
}
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvtsd_si64(__m128d a)
{
return __builtin_ia32_cvtsd2si64(a);
}
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvttsd_si64(__m128d a)
{
return a[0];
}
#endif
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi32_ps(__m128i a)
{
return __builtin_ia32_cvtdq2ps((__v4si)a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtps_epi32(__m128 a)
{
return (__m128i)__builtin_ia32_cvtps2dq(a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvttps_epi32(__m128 a)
{
return (__m128i)__builtin_ia32_cvttps2dq(a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi32_si128(int a)
{
return (__m128i)(__v4si){ a, 0, 0, 0 };
}
#ifdef __x86_64__
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi64_si128(long long a)
{
return (__m128i){ a, 0 };
}
#endif
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi128_si32(__m128i a)
{
__v4si b = (__v4si)a;
@@ -997,207 +997,207 @@ _mm_cvtsi128_si32(__m128i a)
}
#ifdef __x86_64__
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi128_si64(__m128i a)
{
return a[0];
}
#endif
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_load_si128(__m128i const *p)
{
return *p;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_loadu_si128(__m128i const *p)
{
return (__m128i)__builtin_ia32_loaddqu((char const *)p);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_loadl_epi64(__m128i const *p)
{
return (__m128i) { *(long long*)p, 0};
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi64x(long long q1, long long q0)
{
return (__m128i){ q0, q1 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi64(__m64 q1, __m64 q0)
{
return (__m128i){ (long long)q0, (long long)q1 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi32(int i3, int i2, int i1, int i0)
{
return (__m128i)(__v4si){ i0, i1, i2, i3};
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi16(short w7, short w6, short w5, short w4, short w3, short w2, short w1, short w0)
{
return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9, char b8, char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0)
{
return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi64x(long long q)
{
return (__m128i){ q, q };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi64(__m64 q)
{
return (__m128i){ (long long)q, (long long)q };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi32(int i)
{
return (__m128i)(__v4si){ i, i, i, i };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi16(short w)
{
return (__m128i)(__v8hi){ w, w, w, w, w, w, w, w };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_set1_epi8(char b)
{
return (__m128i)(__v16qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_setr_epi64(__m64 q0, __m64 q1)
{
return (__m128i){ (long long)q0, (long long)q1 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_setr_epi32(int i0, int i1, int i2, int i3)
{
return (__m128i)(__v4si){ i0, i1, i2, i3};
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_setr_epi16(short w0, short w1, short w2, short w3, short w4, short w5, short w6, short w7)
{
return (__m128i)(__v8hi){ w0, w1, w2, w3, w4, w5, w6, w7 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_setr_epi8(char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9, char b10, char b11, char b12, char b13, char b14, char b15)
{
return (__m128i)(__v16qi){ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_setzero_si128(void)
{
return (__m128i){ 0LL, 0LL };
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store_si128(__m128i *p, __m128i b)
{
*p = b;
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storeu_si128(__m128i *p, __m128i b)
{
__builtin_ia32_storedqu((char *)p, (__v16qi)b);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_maskmoveu_si128(__m128i d, __m128i n, char *p)
{
__builtin_ia32_maskmovdqu((__v16qi)d, (__v16qi)n, p);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storel_epi64(__m128i *p, __m128i a)
{
__builtin_ia32_storelv4si((__v2si *)p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_pd(double *p, __m128d a)
{
__builtin_ia32_movntpd(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_si128(__m128i *p, __m128i a)
{
__builtin_ia32_movntdq(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_si32(int *p, int a)
{
__builtin_ia32_movnti(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_clflush(void const *p)
{
__builtin_ia32_clflush(p);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_lfence(void)
{
__builtin_ia32_lfence();
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_mfence(void)
{
__builtin_ia32_mfence();
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_packs_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_packsswb128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_packs_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_packssdw128((__v4si)a, (__v4si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_packus_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_packuswb128((__v8hi)a, (__v8hi)b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_extract_epi16(__m128i a, int imm)
{
__v8hi b = (__v8hi)a;
return b[imm];
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_insert_epi16(__m128i a, int b, int imm)
{
__v8hi c = (__v8hi)a;
@@ -1205,7 +1205,7 @@ _mm_insert_epi16(__m128i a, int b, int imm)
return (__m128i)c;
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_movemask_epi8(__m128i a)
{
return __builtin_ia32_pmovmskb128((__v16qi)a);
@@ -1226,85 +1226,85 @@ _mm_movemask_epi8(__m128i a)
4 + ((imm) & 0x30) >> 4, \
4 + ((imm) & 0xc0) >> 6))
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 2, 4+2, 3, 4+3);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_epi64(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector(a, b, 1, 2+1);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 0, 4+0, 1, 4+1);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_epi64(__m128i a, __m128i b)
{
return (__m128i)__builtin_shufflevector(a, b, 0, 2+0);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_movepi64_pi64(__m128i a)
{
return (__m64)a[0];
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_movpi64_pi64(__m64 a)
{
return (__m128i){ (long long)a, 0 };
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_move_epi64(__m128i a)
{
return __builtin_shufflevector(a, (__m128i){ 0 }, 0, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_pd(__m128d a, __m128d b)
{
return __builtin_shufflevector(a, b, 1, 2+1);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_pd(__m128d a, __m128d b)
{
return __builtin_shufflevector(a, b, 0, 2+0);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_movemask_pd(__m128d a)
{
return __builtin_ia32_movmskpd(a);
@@ -1313,43 +1313,43 @@ _mm_movemask_pd(__m128d a)
#define _mm_shuffle_pd(a, b, i) (__builtin_shufflevector((a), (b), (i) & 1, \
(((i) & 2) >> 1) + 2))
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_castpd_ps(__m128d in)
{
return (__m128)in;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_castpd_si128(__m128d in)
{
return (__m128i)in;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_castps_pd(__m128 in)
{
return (__m128d)in;
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_castps_si128(__m128 in)
{
return (__m128i)in;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_castsi128_ps(__m128i in)
{
return (__m128)in;
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_castsi128_pd(__m128i in)
{
return (__m128d)in;
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_pause(void)
{
__asm__ volatile ("pause");
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
index a680c47..fba8651 100644
--- a/lib/Headers/mm_malloc.h
+++ b/lib/Headers/mm_malloc.h
@@ -27,7 +27,8 @@
#include <errno.h>
#include <stdlib.h>
-static inline void *__attribute__((__always_inline__, __nodebug__)) _mm_malloc(size_t size, size_t align)
+static __inline__ void *__attribute__((__always_inline__, __nodebug__))
+_mm_malloc(size_t size, size_t align)
{
if (align & (align - 1)) {
errno = EINVAL;
@@ -44,13 +45,15 @@ static inline void *__attribute__((__always_inline__, __nodebug__)) _mm_malloc(s
if (!mallocedMemory)
return 0;
- void *alignedMemory = (void *)(((size_t)mallocedMemory + align) & ~((size_t)align - 1));
+ void *alignedMemory =
+ (void *)(((size_t)mallocedMemory + align) & ~((size_t)align - 1));
((void **)alignedMemory)[-1] = mallocedMemory;
return alignedMemory;
}
-static inline void __attribute__((__always_inline__, __nodebug__)) _mm_free(void *p)
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_mm_free(void *p)
{
if (p)
free(((void **)p)[-1]);
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index 0f06f78..401d8a7 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -34,409 +34,409 @@ typedef int __v2si __attribute__((__vector_size__(8)));
typedef short __v4hi __attribute__((__vector_size__(8)));
typedef char __v8qi __attribute__((__vector_size__(8)));
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_empty(void)
{
__builtin_ia32_emms();
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi32_si64(int __i)
{
return (__m64)(__v2si){__i, 0};
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi64_si32(__m64 __m)
{
__v2si __mmx_var2 = (__v2si)__m;
return __mmx_var2[0];
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi64_m64(long long __i)
{
return (__m64)__i;
}
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvtm64_si64(__m64 __m)
{
return (long long)__m;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_packs_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_packsswb((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_packs_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_packssdw((__v2si)__m1, (__v2si)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_packs_pu16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_packuswb((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 4, 8+4, 5,
8+5, 6, 8+6, 7, 8+7);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 2, 4+2, 3,
4+3);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 1, 2+1);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v8qi)__m1, (__v8qi)__m2, 0, 8+0, 1,
8+1, 2, 8+2, 3, 8+3);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v4hi)__m1, (__v4hi)__m2, 0, 4+0, 1,
4+1);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_shufflevector((__v2si)__m1, (__v2si)__m2, 0, 2+0);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_add_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)((__v8qi)__m1 + (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_add_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)((__v4hi)__m1 + (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_add_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)((__v2si)__m1 + (__v2si)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_adds_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_paddsb((__v8qi)__m1, (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_adds_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_paddsw((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_adds_pu8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_paddusb((__v8qi)__m1, (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_adds_pu16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_paddusw((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sub_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)((__v8qi)__m1 - (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sub_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)((__v4hi)__m1 - (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sub_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)((__v2si)__m1 - (__v2si)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_subs_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_psubsb((__v8qi)__m1, (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_subs_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_psubsw((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_subs_pu8(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_psubusb((__v8qi)__m1, (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_subs_pu16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_psubusw((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_madd_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_pmaddwd((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_mulhi_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)__builtin_ia32_pmulhw((__v4hi)__m1, (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_mullo_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)((__v4hi)__m1 * (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sll_pi16(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psllw((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_slli_pi16(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_psllwi((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sll_pi32(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_pslld((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_slli_pi32(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_pslldi((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sll_si64(__m64 __m, __m64 __count)
{
return __builtin_ia32_psllq(__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_slli_si64(__m64 __m, int __count)
{
return __builtin_ia32_psllqi(__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sra_pi16(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psraw((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srai_pi16(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_psrawi((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sra_pi32(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psrad((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srai_pi32(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_psradi((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srl_pi16(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psrlw((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srli_pi16(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_psrlwi((__v4hi)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srl_pi32(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psrld((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srli_pi32(__m64 __m, int __count)
{
return (__m64)__builtin_ia32_psrldi((__v2si)__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srl_si64(__m64 __m, __m64 __count)
{
return (__m64)__builtin_ia32_psrlq(__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_srli_si64(__m64 __m, int __count)
{
return __builtin_ia32_psrlqi(__m, __count);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_and_si64(__m64 __m1, __m64 __m2)
{
return __m1 & __m2;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_andnot_si64(__m64 __m1, __m64 __m2)
{
return ~__m1 & __m2;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_or_si64(__m64 __m1, __m64 __m2)
{
return __m1 | __m2;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_xor_si64(__m64 __m1, __m64 __m2)
{
return __m1 ^ __m2;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)((__v8qi)__m1 == (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)((__v4hi)__m1 == (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)((__v2si)__m1 == (__v2si)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_pi8(__m64 __m1, __m64 __m2)
{
return (__m64)((__v8qi)__m1 > (__v8qi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_pi16(__m64 __m1, __m64 __m2)
{
return (__m64)((__v4hi)__m1 > (__v4hi)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_pi32(__m64 __m1, __m64 __m2)
{
return (__m64)((__v2si)__m1 > (__v2si)__m2);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_setzero_si64(void)
{
return (__m64){ 0LL };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set_pi32(int __i1, int __i0)
{
return (__m64)(__v2si){ __i0, __i1 };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set_pi16(short __s3, short __s2, short __s1, short __s0)
{
return (__m64)(__v4hi){ __s0, __s1, __s2, __s3 };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
char __b1, char __b0)
{
return (__m64)(__v8qi){ __b0, __b1, __b2, __b3, __b4, __b5, __b6, __b7 };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set1_pi32(int __i)
{
return (__m64)(__v2si){ __i, __i };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set1_pi16(short __s)
{
return (__m64)(__v4hi){ __s, __s, __s, __s };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_set1_pi8(char __b)
{
return (__m64)(__v8qi){ __b, __b, __b, __b, __b, __b, __b, __b };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_setr_pi32(int __i1, int __i0)
{
return (__m64)(__v2si){ __i1, __i0 };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_setr_pi16(short __s3, short __s2, short __s1, short __s0)
{
return (__m64)(__v4hi){ __s3, __s2, __s1, __s0 };
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
char __b1, char __b0)
{
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index cd90166..7ca386c 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -30,67 +30,67 @@
#include <emmintrin.h>
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_lddqu_si128(__m128i const *p)
{
return (__m128i)__builtin_ia32_lddqu((char const *)p);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_addsub_ps(__m128 a, __m128 b)
{
return __builtin_ia32_addsubps(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_hadd_ps(__m128 a, __m128 b)
{
return __builtin_ia32_haddps(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_hsub_ps(__m128 a, __m128 b)
{
return __builtin_ia32_hsubps(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_movehdup_ps(__m128 a)
{
return __builtin_shufflevector(a, a, 1, 1, 3, 3);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_moveldup_ps(__m128 a)
{
return __builtin_shufflevector(a, a, 0, 0, 2, 2);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_addsub_pd(__m128d a, __m128d b)
{
return __builtin_ia32_addsubpd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_hadd_pd(__m128d a, __m128d b)
{
return __builtin_ia32_haddpd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_hsub_pd(__m128d a, __m128d b)
{
return __builtin_ia32_hsubpd(a, b);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loaddup_pd(double const *dp)
{
return (__m128d){ *dp, *dp };
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_movedup_pd(__m128d a)
{
return __builtin_shufflevector(a, a, 0, 0);
@@ -104,13 +104,13 @@ _mm_movedup_pd(__m128d a)
#define _MM_GET_DENORMALS_ZERO_MODE() (_mm_getcsr() & _MM_DENORMALS_ZERO_MASK)
#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_monitor(void const *p, unsigned extensions, unsigned hints)
{
__builtin_ia32_monitor((void *)p, extensions, hints);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_mwait(unsigned extensions, unsigned hints)
{
__builtin_ia32_mwait(extensions, hints);
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 9c8d53d..e271f99 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -1,25 +1,25 @@
-/*===---- smmintrin.h - SSE intrinsics -------------------------------------===
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*
-*===-----------------------------------------------------------------------===
-*/
+/*===---- smmintrin.h - SSE4 intrinsics ------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
#ifndef _SMMINTRIN_H
#define _SMMINTRIN_H
@@ -67,53 +67,53 @@ typedef long long __v2di __attribute__ ((__vector_size__ (16)));
#define _mm_round_sd(X, Y, M) __builtin_ia32_roundsd((X), (Y), (M))
/* SSE4 Packed Blending Intrinsics. */
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_blend_pd (__m128d __V1, __m128d __V2, const int __M)
{
return (__m128d) __builtin_ia32_blendpd ((__v2df)__V1, (__v2df)__V2, __M);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_blend_ps (__m128 __V1, __m128 __V2, const int __M)
{
return (__m128) __builtin_ia32_blendps ((__v4sf)__V1, (__v4sf)__V2, __M);
}
-static inline __m128d __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
{
return (__m128d) __builtin_ia32_blendvpd ((__v2df)__V1, (__v2df)__V2,
(__v2df)__M);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_blendv_ps (__m128 __V1, __m128 __V2, __m128 __M)
{
return (__m128) __builtin_ia32_blendvps ((__v4sf)__V1, (__v4sf)__V2,
(__v4sf)__M);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
{
return (__m128i) __builtin_ia32_pblendvb128 ((__v16qi)__V1, (__v16qi)__V2,
(__v16qi)__M);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_blend_epi16 (__m128i __V1, __m128i __V2, const int __M)
{
return (__m128i) __builtin_ia32_pblendw128 ((__v8hi)__V1, (__v8hi)__V2, __M);
}
/* SSE4 Dword Multiply Instructions. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mullo_epi32 (__m128i __V1, __m128i __V2)
{
- return (__m128i) __builtin_ia32_pmulld128((__v4si)__V1, (__v4si)__V2);
+ return (__m128i) ((__v4si)__V1 * (__v4si)__V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mul_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmuldq128 ((__v4si)__V1, (__v4si)__V2);
@@ -124,56 +124,56 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2)
#define _mm_dp_pd(X, Y, M) __builtin_ia32_dppd ((X), (Y), (M))
/* SSE4 Streaming Load Hint Instruction. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_stream_load_si128 (__m128i *__V)
{
return (__m128i) __builtin_ia32_movntdqa ((__v2di *) __V);
}
/* SSE4 Packed Integer Min/Max Instructions. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epi8 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminsb128 ((__v16qi) __V1, (__v16qi) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epi8 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxsb128 ((__v16qi) __V1, (__v16qi) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epu16 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminuw128 ((__v8hi) __V1, (__v8hi) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epu16 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxuw128 ((__v8hi) __V1, (__v8hi) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminsd128 ((__v4si) __V1, (__v4si) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epi32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxsd128 ((__v4si) __V1, (__v4si) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_min_epu32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pminud128((__v4si) __V1, (__v4si) __V2);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_max_epu32 (__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pmaxud128((__v4si) __V1, (__v4si) __V2);
@@ -224,19 +224,19 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
#endif /* __x86_64 */
/* SSE4 128-bit Packed Integer Comparisons. */
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_testz_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestz128((__v2di)__M, (__v2di)__V);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_testc_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestc128((__v2di)__M, (__v2di)__V);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_testnzc_si128(__m128i __M, __m128i __V)
{
return __builtin_ia32_ptestnzc128((__v2di)__M, (__v2di)__V);
@@ -247,88 +247,88 @@ _mm_testnzc_si128(__m128i __M, __m128i __V)
#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((V), (V))
/* SSE4 64-bit Packed Integer Comparisons. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_epi64(__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2);
}
/* SSE4 Packed Integer Sign-Extension. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi8_epi16(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxbw128((__v16qi) __V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi8_epi32(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxbd128((__v16qi) __V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi8_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxbq128((__v16qi) __V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi16_epi32(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxwd128((__v8hi) __V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi16_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxwq128((__v8hi)__V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepi32_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovsxdq128((__v4si)__V);
}
/* SSE4 Packed Integer Zero-Extension. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu8_epi16(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxbw128((__v16qi) __V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu8_epi32(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxbd128((__v16qi)__V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu8_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxbq128((__v16qi)__V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu16_epi32(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxwd128((__v8hi)__V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu16_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxwq128((__v8hi)__V);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cvtepu32_epi64(__m128i __V)
{
return (__m128i) __builtin_ia32_pmovzxdq128((__v4si)__V);
}
/* SSE4 Pack with Unsigned Saturation. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_packus_epi32(__m128i __V1, __m128i __V2)
{
return (__m128i) __builtin_ia32_packusdw128((__v4si)__V1, (__v4si)__V2);
@@ -400,33 +400,33 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2)
__builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M))
/* SSE4.2 Compare Packed Data -- Greater Than. */
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_epi64(__m128i __V1, __m128i __V2)
{
return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2);
}
/* SSE4.2 Accumulate CRC32. */
-static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u8(unsigned int __C, unsigned char __D)
{
return __builtin_ia32_crc32qi(__C, __D);
}
-static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u16(unsigned int __C, unsigned short __D)
{
return __builtin_ia32_crc32hi(__C, __D);
}
-static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u32(unsigned int __C, unsigned int __D)
{
return __builtin_ia32_crc32si(__C, __D);
}
#ifdef __x86_64__
-static inline unsigned long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
_mm_crc32_u64(unsigned long long __C, unsigned long long __D)
{
return __builtin_ia32_crc32di(__C, __D);
@@ -434,14 +434,14 @@ _mm_crc32_u64(unsigned long long __C, unsigned long long __D)
#endif /* __x86_64__ */
/* SSE4.2 Population Count. */
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_popcnt_u32(unsigned int __A)
{
return __builtin_popcount(__A);
}
#ifdef __x86_64__
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_popcnt_u64(unsigned long long __A)
{
return __builtin_popcountll(__A);
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index 7adb776..09ebc23 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -30,37 +30,37 @@
#include <pmmintrin.h>
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_abs_pi8(__m64 a)
{
return (__m64)__builtin_ia32_pabsb((__v8qi)a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_abs_epi8(__m128i a)
{
return (__m128i)__builtin_ia32_pabsb128((__v16qi)a);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_abs_pi16(__m64 a)
{
return (__m64)__builtin_ia32_pabsw((__v4hi)a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_abs_epi16(__m128i a)
{
return (__m128i)__builtin_ia32_pabsw128((__v8hi)a);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_abs_pi32(__m64 a)
{
return (__m64)__builtin_ia32_pabsd((__v2si)a);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_abs_epi32(__m128i a)
{
return (__m128i)__builtin_ia32_pabsd128((__v4si)a);
@@ -69,145 +69,145 @@ _mm_abs_epi32(__m128i a)
#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8)))
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phaddw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadd_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phaddd128((__v4si)a, (__v4si)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hadd_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phaddw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hadd_pi32(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phaddd((__v2si)a, (__v2si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hadds_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phaddsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hadds_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phaddsw((__v4hi)a, (__v4hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hsub_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phsubw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hsub_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phsubd128((__v4si)a, (__v4si)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hsub_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phsubw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hsub_pi32(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phsubd((__v2si)a, (__v2si)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_hsubs_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_phsubsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_hsubs_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_phsubsw((__v4hi)a, (__v4hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_maddubs_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)a, (__v16qi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_maddubs_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pmaddubsw((__v8qi)a, (__v8qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_mulhrs_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)a, (__v8hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_mulhrs_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pmulhrsw((__v4hi)a, (__v4hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_shuffle_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_pshufb128((__v16qi)a, (__v16qi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_shuffle_pi8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pshufb((__v8qi)a, (__v8qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sign_epi8(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psignb128((__v16qi)a, (__v16qi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sign_epi16(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psignw128((__v8hi)a, (__v8hi)b);
}
-static inline __m128i __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_sign_epi32(__m128i a, __m128i b)
{
return (__m128i)__builtin_ia32_psignd128((__v4si)a, (__v4si)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sign_pi8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_psignb((__v8qi)a, (__v8qi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sign_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_psignw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sign_pi32(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_psignd((__v2si)a, (__v2si)b);
diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h
new file mode 100644
index 0000000..6b2e468
--- /dev/null
+++ b/lib/Headers/wmmintrin.h
@@ -0,0 +1,67 @@
+/*===---- wmmintrin.h - AES intrinsics ------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef _WMMINTRIN_H
+#define _WMMINTRIN_H
+
+#if !defined (__AES__)
+# error "AES instructions not enabled"
+#else
+
+#include <smmintrin.h>
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenc_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenc128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesenclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesenclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdec_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdec128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesdeclast_si128(__m128i __V, __m128i __R)
+{
+ return (__m128i)__builtin_ia32_aesdeclast128(__V, __R);
+}
+
+static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
+_mm_aesimc_si128(__m128i __V)
+{
+ return (__m128i)__builtin_ia32_aesimc128(__V);
+}
+
+#define _mm_aeskeygenassist_si128(C, R) \
+ __builtin_ia32_aeskeygenassist128((C), (R))
+
+#endif /* __AES__ */
+#endif /* _WMMINTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 06e616b..4e313b2 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -36,365 +36,365 @@ typedef float __m128 __attribute__((__vector_size__(16)));
#include <mm_malloc.h>
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_add_ss(__m128 a, __m128 b)
{
a[0] += b[0];
return a;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_add_ps(__m128 a, __m128 b)
{
return a + b;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sub_ss(__m128 a, __m128 b)
{
a[0] -= b[0];
return a;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sub_ps(__m128 a, __m128 b)
{
return a - b;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_mul_ss(__m128 a, __m128 b)
{
a[0] *= b[0];
return a;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_mul_ps(__m128 a, __m128 b)
{
return a * b;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_div_ss(__m128 a, __m128 b)
{
a[0] /= b[0];
return a;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_div_ps(__m128 a, __m128 b)
{
return a / b;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_ss(__m128 a)
{
return __builtin_ia32_sqrtss(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_sqrt_ps(__m128 a)
{
return __builtin_ia32_sqrtps(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rcp_ss(__m128 a)
{
return __builtin_ia32_rcpss(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rcp_ps(__m128 a)
{
return __builtin_ia32_rcpps(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rsqrt_ss(__m128 a)
{
return __builtin_ia32_rsqrtss(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_rsqrt_ps(__m128 a)
{
return __builtin_ia32_rsqrtps(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_min_ss(__m128 a, __m128 b)
{
return __builtin_ia32_minss(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_min_ps(__m128 a, __m128 b)
{
return __builtin_ia32_minps(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_max_ss(__m128 a, __m128 b)
{
return __builtin_ia32_maxss(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_max_ps(__m128 a, __m128 b)
{
return __builtin_ia32_maxps(a, b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_and_ps(__m128 a, __m128 b)
{
return (__m128)((__v4si)a & (__v4si)b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_andnot_ps(__m128 a, __m128 b)
{
return (__m128)(~(__v4si)a & (__v4si)b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_or_ps(__m128 a, __m128 b)
{
return (__m128)((__v4si)a | (__v4si)b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_xor_ps(__m128 a, __m128 b)
{
return (__m128)((__v4si)a ^ (__v4si)b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 0);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpeq_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 0);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 1);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmplt_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 1);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmple_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 2);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmple_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 2);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(b, a, 1);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpgt_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(b, a, 1);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(b, a, 2);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpge_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(b, a, 2);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 4);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpneq_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 4);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnlt_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 6);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnle_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 6);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(b, a, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpngt_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(b, a, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(b, a, 6);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpnge_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(b, a, 6);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 7);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpord_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 7);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_ss(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpss(a, b, 3);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cmpunord_ps(__m128 a, __m128 b)
{
return (__m128)__builtin_ia32_cmpps(a, b, 3);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comieq_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comieq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comilt_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comilt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comile_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comile(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comigt_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comigt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comige_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comige(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_comineq_ss(__m128 a, __m128 b)
{
return __builtin_ia32_comineq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomieq_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomieq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomilt_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomilt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomile_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomile(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomigt_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomigt(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomige_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomige(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_ucomineq_ss(__m128 a, __m128 b)
{
return __builtin_ia32_ucomineq(a, b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvtss_si32(__m128 a)
{
return __builtin_ia32_cvtss2si(a);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvt_ss2si(__m128 a)
{
return _mm_cvtss_si32(a);
@@ -402,7 +402,7 @@ _mm_cvt_ss2si(__m128 a)
#ifdef __x86_64__
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvtss_si64(__m128 a)
{
return __builtin_ia32_cvtss2si64(a);
@@ -410,37 +410,37 @@ _mm_cvtss_si64(__m128 a)
#endif
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtps_pi32(__m128 a)
{
return (__m64)__builtin_ia32_cvtps2pi(a);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvttss_si32(__m128 a)
{
return a[0];
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_cvtt_ss2si(__m128 a)
{
return _mm_cvttss_si32(a);
}
-static inline long long __attribute__((__always_inline__, __nodebug__))
+static __inline__ long long __attribute__((__always_inline__, __nodebug__))
_mm_cvttss_si64(__m128 a)
{
return a[0];
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvttps_pi32(__m128 a)
{
return (__m64)__builtin_ia32_cvttps2pi(a);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi32_ss(__m128 a, int b)
{
a[0] = b;
@@ -449,7 +449,7 @@ _mm_cvtsi32_ss(__m128 a, int b)
#ifdef __x86_64__
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtsi64_ss(__m128 a, long long b)
{
a[0] = b;
@@ -458,19 +458,19 @@ _mm_cvtsi64_ss(__m128 a, long long b)
#endif
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpi32_ps(__m128 a, __m64 b)
{
return __builtin_ia32_cvtpi2ps(a, (__v2si)b);
}
-static inline float __attribute__((__always_inline__, __nodebug__))
+static __inline__ float __attribute__((__always_inline__, __nodebug__))
_mm_cvtss_f32(__m128 a)
{
return a[0];
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadh_pi(__m128 a, const __m64 *p)
{
__m128 b;
@@ -479,7 +479,7 @@ _mm_loadh_pi(__m128 a, const __m64 *p)
return __builtin_shufflevector(a, b, 0, 1, 4, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadl_pi(__m128 a, const __m64 *p)
{
__m128 b;
@@ -488,13 +488,13 @@ _mm_loadl_pi(__m128 a, const __m64 *p)
return __builtin_shufflevector(a, b, 4, 5, 2, 3);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_load_ss(const float *p)
{
return (__m128){ *p, 0, 0, 0 };
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_load1_ps(const float *p)
{
return (__m128){ *p, *p, *p, *p };
@@ -502,100 +502,100 @@ _mm_load1_ps(const float *p)
#define _mm_load_ps1(p) _mm_load1_ps(p)
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_load_ps(const float *p)
{
return *(__m128*)p;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadu_ps(const float *p)
{
return __builtin_ia32_loadups(p);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadr_ps(const float *p)
{
__m128 a = _mm_load_ps(p);
return __builtin_shufflevector(a, a, 3, 2, 1, 0);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_set_ss(float w)
{
return (__m128){ w, 0, 0, 0 };
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_set1_ps(float w)
{
return (__m128){ w, w, w, w };
}
// Microsoft specific.
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_set_ps1(float w)
{
return _mm_set1_ps(w);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_set_ps(float z, float y, float x, float w)
{
return (__m128){ w, x, y, z };
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_setr_ps(float z, float y, float x, float w)
{
return (__m128){ z, y, x, w };
}
-static inline __m128 __attribute__((__always_inline__))
+static __inline__ __m128 __attribute__((__always_inline__))
_mm_setzero_ps(void)
{
return (__m128){ 0, 0, 0, 0 };
}
-static inline void __attribute__((__always_inline__))
+static __inline__ void __attribute__((__always_inline__))
_mm_storeh_pi(__m64 *p, __m128 a)
{
__builtin_ia32_storehps((__v2si *)p, a);
}
-static inline void __attribute__((__always_inline__))
+static __inline__ void __attribute__((__always_inline__))
_mm_storel_pi(__m64 *p, __m128 a)
{
__builtin_ia32_storelps((__v2si *)p, a);
}
-static inline void __attribute__((__always_inline__))
+static __inline__ void __attribute__((__always_inline__))
_mm_store_ss(float *p, __m128 a)
{
*p = a[0];
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storeu_ps(float *p, __m128 a)
{
__builtin_ia32_storeups(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store1_ps(float *p, __m128 a)
{
a = __builtin_shufflevector(a, a, 0, 0, 0, 0);
_mm_storeu_ps(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_store_ps(float *p, __m128 a)
{
*(__m128 *)p = a;
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_storer_ps(float *p, __m128 a)
{
a = __builtin_shufflevector(a, a, 3, 2, 1, 0);
@@ -612,32 +612,32 @@ _mm_storer_ps(float *p, __m128 a)
#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)a, 0, sel))
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_pi(__m64 *p, __m64 a)
{
__builtin_ia32_movntq(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_ps(float *p, __m128 a)
{
__builtin_ia32_movntps(p, a);
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_sfence(void)
{
__builtin_ia32_sfence();
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_extract_pi16(__m64 a, int n)
{
__v4hi b = (__v4hi)a;
return (unsigned short)b[n & 3];
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_insert_pi16(__m64 a, int d, int n)
{
__v4hi b = (__v4hi)a;
@@ -645,37 +645,37 @@ _mm_insert_pi16(__m64 a, int d, int n)
return (__m64)b;
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_max_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pmaxsw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_max_pu8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pmaxub((__v8qi)a, (__v8qi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_min_pi16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pminsw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_min_pu8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pminub((__v8qi)a, (__v8qi)b);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_movemask_pi8(__m64 a)
{
return __builtin_ia32_pmovmskb((__v8qi)a);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_mulhi_pu16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b);
@@ -686,37 +686,37 @@ _mm_mulhi_pu16(__m64 a, __m64 b)
(n) & 0x3, ((n) & 0xc) >> 2, \
((n) & 0x30) >> 4, ((n) & 0xc0) >> 6))
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_maskmove_si64(__m64 d, __m64 n, char *p)
{
__builtin_ia32_maskmovq((__v8qi)d, (__v8qi)n, p);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_avg_pu8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pavgb((__v8qi)a, (__v8qi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_avg_pu16(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_pavgw((__v4hi)a, (__v4hi)b);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_sad_pu8(__m64 a, __m64 b)
{
return (__m64)__builtin_ia32_psadbw((__v8qi)a, (__v8qi)b);
}
-static inline unsigned int __attribute__((__always_inline__, __nodebug__))
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
_mm_getcsr(void)
{
return __builtin_ia32_stmxcsr();
}
-static inline void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_setcsr(unsigned int i)
{
__builtin_ia32_ldmxcsr(i);
@@ -727,37 +727,37 @@ _mm_setcsr(unsigned int i)
(((mask) & 0x30) >> 4) + 4, \
(((mask) & 0xc0) >> 6) + 4))
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_unpackhi_ps(__m128 a, __m128 b)
{
return __builtin_shufflevector(a, b, 2, 6, 3, 7);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_unpacklo_ps(__m128 a, __m128 b)
{
return __builtin_shufflevector(a, b, 0, 4, 1, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_move_ss(__m128 a, __m128 b)
{
return __builtin_shufflevector(a, b, 4, 1, 2, 3);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_movehl_ps(__m128 a, __m128 b)
{
return __builtin_shufflevector(a, b, 6, 7, 2, 3);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_movelh_ps(__m128 a, __m128 b)
{
return __builtin_shufflevector(a, b, 0, 1, 4, 5);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpi16_ps(__m64 a)
{
__m64 b, c;
@@ -775,7 +775,7 @@ _mm_cvtpi16_ps(__m64 a)
return r;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpu16_ps(__m64 a)
{
__m64 b, c;
@@ -792,7 +792,7 @@ _mm_cvtpu16_ps(__m64 a)
return r;
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpi8_ps(__m64 a)
{
__m64 b;
@@ -804,7 +804,7 @@ _mm_cvtpi8_ps(__m64 a)
return _mm_cvtpi16_ps(b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpu8_ps(__m64 a)
{
__m64 b;
@@ -815,7 +815,7 @@ _mm_cvtpu8_ps(__m64 a)
return _mm_cvtpi16_ps(b);
}
-static inline __m128 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_cvtpi32x2_ps(__m64 a, __m64 b)
{
__m128 c;
@@ -827,7 +827,7 @@ _mm_cvtpi32x2_ps(__m64 a, __m64 b)
return _mm_cvtpi32_ps(c, a);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtps_pi16(__m128 a)
{
__m64 b, c;
@@ -839,7 +839,7 @@ _mm_cvtps_pi16(__m128 a)
return _mm_packs_pi16(b, c);
}
-static inline __m64 __attribute__((__always_inline__, __nodebug__))
+static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
_mm_cvtps_pi8(__m128 a)
{
__m64 b, c;
@@ -850,7 +850,7 @@ _mm_cvtps_pi8(__m128 a)
return _mm_packs_pi16(b, c);
}
-static inline int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
_mm_movemask_ps(__m128 a)
{
return __builtin_ia32_movmskps(a);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 2f89142..19f25ea 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1372,8 +1372,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
Diag(BufferEnd, diag::ext_no_newline_eof)
- << CodeModificationHint::CreateInsertion(getSourceLocation(BufferEnd),
- "\n");
+ << FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
BufferPtr = CurPtr;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 7b60101..757ba90 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -127,10 +127,10 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
// Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
// because it is more trouble than it is worth to insert /**/ and check that
// there is no /**/ in the range also.
- CodeModificationHint FixItHint;
+ FixItHint Hint;
if (Features.GNUMode || Features.C99 || Features.CPlusPlus)
- FixItHint = CodeModificationHint::CreateInsertion(Tmp.getLocation(),"//");
- Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << FixItHint;
+ Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//");
+ Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint;
DiscardUntilEndOfDirective();
}
}
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 6d1c132..335d3db 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -255,6 +255,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
if (!I->second->isUsed())
Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
}
+
return true;
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index ffae8ab..1c6a5ad 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -258,10 +258,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
InstantiationEnd,Identifier.getLength());
Identifier.setLocation(Loc);
- // If this is #define X X, we must mark the result as unexpandible.
- if (IdentifierInfo *NewII = Identifier.getIdentifierInfo())
- if (getMacroInfo(NewII) == MI)
- Identifier.setFlag(Token::DisableExpand);
+ // If this is a disabled macro or #define X X, we must mark the result as
+ // unexpandable.
+ if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) {
+ if (MacroInfo *NewMI = getMacroInfo(NewII))
+ if (!NewMI->isEnabled() || NewMI == MI)
+ Identifier.setFlag(Token::DisableExpand);
+ }
// Since this is not an identifier token, it can't be macro expanded, so
// we're done.
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 9d59300..8b4b1dd 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -519,6 +519,11 @@ bool Preprocessor::EnterMainSourceFile() {
return EnterSourceFile(FID, 0, ErrorStr);
}
+void Preprocessor::EndSourceFile() {
+ // Notify the client that we reached the end of the source file.
+ if (Callbacks)
+ Callbacks->EndOfMainFile();
+}
//===----------------------------------------------------------------------===//
// Lexer Event Handling.
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index 0795164..51d2e23 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -85,7 +85,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
TokenInfo[tok::star ] |= aci_avoid_equal; // *=
TokenInfo[tok::exclaim ] |= aci_avoid_equal; // !=
TokenInfo[tok::lessless ] |= aci_avoid_equal; // <<=
- TokenInfo[tok::greaterequal] |= aci_avoid_equal; // >>=
+ TokenInfo[tok::greatergreater] |= aci_avoid_equal; // >>=
TokenInfo[tok::caret ] |= aci_avoid_equal; // ^=
TokenInfo[tok::equal ] |= aci_avoid_equal; // ==
}
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index a66dd96..3cd74d5 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -92,7 +92,6 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("dllimport", AT_dllimport)
.Case("dllexport", AT_dllexport)
.Case("may_alias", IgnoredAttribute) // FIXME: TBAA
- .Case("gcc_tdiag", IgnoredAttribute) // GCC diagnostics type checking.
.Case("base_check", AT_base_check)
.Case("deprecated", AT_deprecated)
.Case("visibility", AT_visibility)
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 4a699e7..11865ab 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -481,7 +481,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
if (TypeSpecComplex != TSC_unspecified) {
if (TypeSpecType == TST_unspecified) {
Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex)
- << CodeModificationHint::CreateInsertion(
+ << FixItHint::CreateInsertion(
PP.getLocForEndOfToken(getTypeSpecComplexLoc()),
" double");
TypeSpecType = TST_double; // _Complex -> _Complex double.
@@ -507,7 +507,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec)
<< SpecName
- << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));
+ << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));
ClearStorageClassSpecs();
}
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index f1e639c..87e22fa 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -122,6 +122,9 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
+ // Save the current token position.
+ SourceLocation origLoc = Tok.getLocation();
+
// Parse the default argument from its saved token stream.
Toks->push_back(Tok); // So that the current token doesn't get lost
PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
@@ -139,6 +142,15 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
else
Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
move(DefArgResult));
+
+ assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
+ Tok.getLocation()) &&
+ "ParseAssignmentExpression went over the default arg tokens!");
+ // There could be leftover tokens (e.g. because of an error).
+ // Skip through until we reach the original token position.
+ while (Tok.getLocation() != origLoc)
+ ConsumeAnyToken();
+
delete Toks;
LM.DefaultArgs[I].Toks = 0;
}
@@ -177,6 +189,9 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
if (LM.TemplateScope)
Actions.ActOnReenterTemplateScope(CurScope, LM.D);
+ // Save the current token position.
+ SourceLocation origLoc = Tok.getLocation();
+
assert(!LM.Toks.empty() && "Empty body!");
// Append the current token at the end of the new token stream so that it
// doesn't get lost.
@@ -195,6 +210,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
if (Tok.is(tok::kw_try)) {
ParseFunctionTryBlock(LM.D);
+ assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
+ Tok.getLocation()) &&
+ "ParseFunctionTryBlock went over the cached tokens!");
+ assert(Tok.getLocation() == origLoc &&
+ "ParseFunctionTryBlock left tokens in the token stream!");
continue;
}
if (Tok.is(tok::colon))
@@ -204,6 +224,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
// FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
ParseFunctionStatementBody(LM.D);
+ assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
+ Tok.getLocation()) &&
+ "We consumed more than the cached tokens!");
+ assert(Tok.getLocation() == origLoc &&
+ "Tokens were left in the token stream!");
}
for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index cff35b7..e87d052 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -734,7 +734,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
if (TagName) {
Diag(Loc, diag::err_use_of_tag_name_without_tag)
<< Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus
- << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName);
+ << FixItHint::CreateInsertion(Tok.getLocation(),TagName);
// Parse this as a tag as if the missing tag were present.
if (TagKind == tok::kw_enum)
@@ -1360,7 +1360,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(EndProtoLoc);
Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
- << CodeModificationHint::CreateInsertion(Loc, "id")
+ << FixItHint::CreateInsertion(Loc, "id")
<< SourceRange(Loc, EndProtoLoc);
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.
@@ -1756,7 +1756,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
@@ -1999,7 +1999,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) {
!(getLang().C99 || getLang().CPlusPlus0x))
Diag(CommaLoc, diag::ext_enumerator_list_comma)
<< getLang().CPlusPlus
- << CodeModificationHint::CreateRemoval(CommaLoc);
+ << FixItHint::CreateRemoval(CommaLoc);
}
// Eat the }.
@@ -3009,7 +3009,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// We have ellipsis without a preceding ',', which is ill-formed
// in C. Complain and provide the fix.
Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
- << CodeModificationHint::CreateInsertion(EllipsisLoc, ", ");
+ << FixItHint::CreateInsertion(EllipsisLoc, ", ");
}
}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 9e232cb..813c24c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -837,7 +837,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Diag(TemplateId->TemplateNameLoc,
diag::err_explicit_instantiation_with_definition)
<< SourceRange(TemplateInfo.TemplateLoc)
- << CodeModificationHint::CreateInsertion(LAngleLoc, "<>");
+ << FixItHint::CreateInsertion(LAngleLoc, "<>");
// Create a fake template parameter list that contains only
// "template<>", so that we treat this construct as a class
@@ -1079,7 +1079,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
if (IsVirtual) {
// Complain about duplicate 'virtual'
Diag(VirtualLoc, diag::err_dup_virtual)
- << CodeModificationHint::CreateRemoval(VirtualLoc);
+ << FixItHint::CreateRemoval(VirtualLoc);
}
IsVirtual = true;
@@ -1554,7 +1554,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
@@ -1579,10 +1579,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// If attributes exist after class contents, parse them.
llvm::OwningPtr<AttributeList> AttrList;
if (Tok.is(tok::kw___attribute))
- AttrList.reset(ParseGNUAttributes()); // FIXME: where should I put them?
+ AttrList.reset(ParseGNUAttributes());
Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
- LBraceLoc, RBraceLoc);
+ LBraceLoc, RBraceLoc,
+ AttrList.get());
// C++ 9.2p2: Within the class member-specification, the class is regarded as
// complete within function bodies, default arguments,
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index f1e989f..8528f8f 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -246,7 +246,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// recover like this.
PP.LookAhead(1).is(tok::identifier)) {
Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
- << CodeModificationHint::CreateReplacement(Next.getLocation(), "::");
+ << FixItHint::CreateReplacement(Next.getLocation(), "::");
// Recover as if the user wrote '::'.
Next.setKind(tok::coloncolon);
@@ -1313,7 +1313,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
Diag(TemplateId->TemplateNameLoc,
diag::err_out_of_line_constructor_template_id)
<< TemplateId->Name
- << CodeModificationHint::CreateRemoval(
+ << FixItHint::CreateRemoval(
SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc));
Result.setConstructorName(Actions.getTypeName(*TemplateId->Name,
TemplateId->TemplateNameLoc,
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index c4e79ca..9154d8d 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -76,9 +76,8 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
SourceLocation ColonLoc = ConsumeToken();
Diag(Tok, diag::ext_gnu_old_style_field_designator)
- << CodeModificationHint::CreateReplacement(SourceRange(NameLoc,
- ColonLoc),
- NewSyntax.str());
+ << FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),
+ NewSyntax.str());
Designation D;
D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
@@ -218,7 +217,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator())) {
Diag(Tok, diag::ext_gnu_missing_equal_designator)
- << CodeModificationHint::CreateInsertion(Tok.getLocation(), "= ");
+ << FixItHint::CreateInsertion(Tok.getLocation(), "= ");
return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
true, ParseInitializer());
}
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7b2b6e8..9a3473f 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -988,7 +988,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
- << CodeModificationHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
continue;
}
@@ -1236,7 +1236,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
if (Tok.is(tok::l_brace)) // we have ivars
ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/,
- tok::objc_protected, atLoc);
+ tok::objc_private, atLoc);
ObjCImpDecl = ImplClsType;
PendingObjCImpDecl.push_back(ObjCImpDecl);
@@ -1571,7 +1571,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
if (Tok.is(tok::semi)) {
if (ObjCImpDecl) {
Diag(Tok, diag::warn_semicolon_before_method_body)
- << CodeModificationHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
}
ConsumeToken();
}
@@ -1817,9 +1817,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SkipUntil(tok::r_square);
return ExprError();
}
-
+
if (Tok.isNot(tok::r_square)) {
- Diag(Tok, diag::err_expected_rsquare);
+ if (Tok.is(tok::identifier))
+ Diag(Tok, diag::err_expected_colon);
+ else
+ Diag(Tok, diag::err_expected_rsquare);
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 9fd145d..b752b48c 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -125,10 +125,12 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
// expression[opt] ';'
OwningExprResult Expr(ParseExpression());
if (Expr.isInvalid()) {
- // If the expression is invalid, skip ahead to the next semicolon. Not
- // doing this opens us up to the possibility of infinite loops if
+ // If the expression is invalid, skip ahead to the next semicolon or '}'.
+ // Not doing this opens us up to the possibility of infinite loops if
// ParseExpression does not consume any tokens.
- SkipUntil(tok::semi);
+ SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
+ if (Tok.is(tok::semi))
+ ConsumeToken();
return StmtError();
}
// Otherwise, eat the semicolon.
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 12f26bf..ff69953 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -660,7 +660,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
ReplaceStr = "> > ";
Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space)
- << CodeModificationHint::CreateReplacement(
+ << FixItHint::CreateReplacement(
SourceRange(Tok.getLocation()), ReplaceStr);
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d45aaed..489586c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -95,8 +95,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK,
}
Diag(Loc, DK)
- << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
- << CodeModificationHint::CreateInsertion(EndLoc, ")");
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
}
/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
@@ -146,7 +146,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
// Show what code to insert to fix this problem.
Diag(EndLoc, DiagID)
<< Msg
- << CodeModificationHint::CreateInsertion(EndLoc, Spelling);
+ << FixItHint::CreateInsertion(EndLoc, Spelling);
} else
Diag(Tok, DiagID) << Msg;
@@ -395,7 +395,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr)
case tok::semi:
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::ext_top_level_semi)
- << CodeModificationHint::CreateRemoval(Tok.getLocation());
+ << FixItHint::CreateRemoval(Tok.getLocation());
ConsumeToken();
// TODO: Invoke action for top-level semicolon.
@@ -829,7 +829,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
PP.getLocForEndOfToken(Tok.getLocation()));
Diag(Tok, diag::warn_file_asm_volatile)
- << CodeModificationHint::CreateRemoval(RemovalRange);
+ << FixItHint::CreateRemoval(RemovalRange);
ConsumeToken();
}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index c4ceec0..d1f00ca 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -154,7 +154,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
continue;
}
Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (CEE->getType().getNoReturnAttr()) {
+ if (getFunctionExtInfo(CEE->getType()).getNoReturn()) {
NoReturnEdge = true;
HasFakeEdge = true;
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
@@ -189,7 +189,7 @@ struct CheckFallThroughDiagnostics {
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
-
+
static CheckFallThroughDiagnostics MakeForFunction() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -205,7 +205,7 @@ struct CheckFallThroughDiagnostics {
D.funMode = true;
return D;
}
-
+
static CheckFallThroughDiagnostics MakeForBlock() {
CheckFallThroughDiagnostics D;
D.diag_MaybeFallThrough_HasNoReturn =
@@ -221,7 +221,7 @@ struct CheckFallThroughDiagnostics {
D.funMode = false;
return D;
}
-
+
bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
bool HasNoReturn) const {
if (funMode) {
@@ -232,7 +232,7 @@ struct CheckFallThroughDiagnostics {
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
== Diagnostic::Ignored || !ReturnsVoid);
}
-
+
// For blocks.
return ReturnsVoid && !HasNoReturn
&& (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
@@ -255,14 +255,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
ReturnsVoid = FD->getResultType()->isVoidType();
HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+ FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getResultType()->isVoidType();
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
- if (const FunctionType *FT =
+ if (const FunctionType *FT =
BlockTy->getPointeeType()->getAs<FunctionType>()) {
if (FT->getResultType()->isVoidType())
ReturnsVoid = true;
@@ -276,7 +276,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// Short circuit for compilation speed.
if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
return;
-
+
// FIXME: Function try block
if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
switch (CheckFallThrough(AC)) {
@@ -312,25 +312,23 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
- Diagnostic &D = S.getDiagnostics();
-
+clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
+ enableCheckUnreachable = 0;
+}
- enableCheckUnreachable = (unsigned)
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+ Diagnostic &D = S.getDiagnostics();
+ DefaultPolicy.enableCheckUnreachable = (unsigned)
(D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
}
-void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
- QualType BlockTy) {
-
+void clang::sema::
+AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
+ const Decl *D, QualType BlockTy,
+ const bool analyzeStaticInline) {
+
assert(BlockTy.isNull() || isa<BlockDecl>(D));
-
- // Do not do any analysis for declarations in system headers if we are
- // going to just ignore them.
- if (S.getDiagnostics().getSuppressSystemWarnings() &&
- S.SourceMgr.isInSystemHeader(D->getLocation()))
- return;
// We avoid doing analysis-based warnings when there are errors for
// two reasons:
@@ -339,13 +337,30 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
// (2) The code already has problems; running the analysis just takes more
// time.
if (S.getDiagnostics().hasErrorOccurred())
- return;
-
+ return;
+
+ // Do not do any analysis for declarations in system headers if we are
+ // going to just ignore them.
+ if (S.getDiagnostics().getSuppressSystemWarnings() &&
+ S.SourceMgr.isInSystemHeader(D->getLocation()))
+ return;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// For function templates, class templates and member function templates
// we'll do the analysis at instantiation time.
if (FD->isDependentContext())
return;
+
+ // Only analyze 'static inline' functions when explicitly asked.
+ if (!analyzeStaticInline && FD->isInlineSpecified() &&
+ FD->getStorageClass() == FunctionDecl::Static) {
+ FD = FD->getCanonicalDecl();
+ VisitFlag &visitFlag = VisitedFD[FD];
+ if (visitFlag == Pending)
+ visitFlag = Visited;
+ else
+ return;
+ }
}
const Stmt *Body = D->getBody();
@@ -354,16 +369,61 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destrutors that can result and the compile time hit.
AnalysisContext AC(D, false);
+ bool performedCheck = false;
// Warning: check missing 'return'
- if (enableCheckFallThrough) {
+ if (P.enableCheckFallThrough) {
const CheckFallThroughDiagnostics &CD =
(isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
: CheckFallThroughDiagnostics::MakeForFunction());
CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+ performedCheck = true;
}
// Warning: check for unreachable code
- if (enableCheckUnreachable)
+ if (P.enableCheckUnreachable) {
CheckUnreachable(S, AC);
+ performedCheck = true;
+ }
+
+ // If this block or function calls a 'static inline' function,
+ // we should analyze those functions as well.
+ if (performedCheck) {
+ // The CFG should already be constructed, so this should not
+ // incur any extra cost. We might not have a CFG, however, for
+ // invalid code.
+ if (const CFG *cfg = AC.getCFG()) {
+ // All CallExprs are block-level expressions in the CFG. This means
+ // that walking the basic blocks in the CFG is more efficient
+ // than walking the entire AST to find all calls.
+ for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) {
+ const CFGBlock *B = *I;
+ for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI)
+ if (const CallExpr *CE = dyn_cast<CallExpr>(*BI))
+ if (const DeclRefExpr *DR =
+ dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts()))
+ if (const FunctionDecl *calleeD =
+ dyn_cast<FunctionDecl>(DR->getDecl())) {
+ calleeD = calleeD->getCanonicalDecl();
+ if (calleeD->isInlineSpecified() &&
+ calleeD->getStorageClass() == FunctionDecl::Static) {
+ // Have we analyzed this static inline function before?
+ VisitFlag &visitFlag = VisitedFD[calleeD];
+ if (visitFlag == NotVisited) {
+ // Mark the callee visited prior to analyzing it
+ // so we terminate in case of recursion.
+ if (calleeD->getBody()) {
+ visitFlag = Visited;
+ IssueWarnings(DefaultPolicy, calleeD, QualType(), true);
+ }
+ else {
+ // Delay warnings until we encounter the definition.
+ visitFlag = Pending;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h
index 39da1b1..b5db8af 100644
--- a/lib/Sema/AnalysisBasedWarnings.h
+++ b/lib/Sema/AnalysisBasedWarnings.h
@@ -14,22 +14,44 @@
#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
-namespace clang { namespace sema {
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class Sema;
+
+namespace sema {
class AnalysisBasedWarnings {
- Sema &S;
- // The warnings to run.
- unsigned enableCheckFallThrough : 1;
- unsigned enableCheckUnreachable : 1;
-
public:
+ class Policy {
+ friend class AnalysisBasedWarnings;
+ // The warnings to run.
+ unsigned enableCheckFallThrough : 1;
+ unsigned enableCheckUnreachable : 1;
+ public:
+ Policy();
+ void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+ };
+
+private:
+ Sema &S;
+ Policy DefaultPolicy;
+ enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
+ llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD;
+
+public:
AnalysisBasedWarnings(Sema &s);
- void IssueWarnings(const Decl *D, QualType BlockTy = QualType());
-
- void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+
+ Policy getDefaultPolicy() { return DefaultPolicy; }
+
+ void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(),
+ const bool analyzeStaticInline = false);
+
};
-
+
}} // end namespace clang::sema
#endif
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 6b26945..f310c25 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -397,6 +397,12 @@ public:
configure();
}
+ /// \brief Change this lookup's redeclaration kind.
+ void setRedeclarationKind(Sema::RedeclarationKind RK) {
+ Redecl = RK;
+ configure();
+ }
+
void print(llvm::raw_ostream &);
/// Suppress the diagnostics that would normally fire because of this
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7112687..ccfbe1e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -132,7 +132,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), NonInstantiationEntries(0),
- CurrentInstantiationScope(0), TyposCorrected(0)
+ CurrentInstantiationScope(0), TyposCorrected(0),
+ AnalysisWarnings(*this)
{
TUScope = 0;
if (getLangOptions().CPlusPlus)
@@ -347,6 +348,30 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
}
}
+Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) {
+ if (isSFINAEContext()) {
+ switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) {
+ case Diagnostic::SFINAE_Report:
+ // Fall through; we'll report the diagnostic below.
+ break;
+
+ case Diagnostic::SFINAE_SubstitutionFailure:
+ // Count this failure so that we know that template argument deduction
+ // has failed.
+ ++NumSFINAEErrors;
+ // Fall through
+
+ case Diagnostic::SFINAE_Suppress:
+ // Suppress this diagnostic.
+ Diags.setLastDiagnosticIgnored();
+ return SemaDiagnosticBuilder(*this);
+ }
+ }
+
+ DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+ return SemaDiagnosticBuilder(DB, *this, DiagID);
+}
+
Sema::SemaDiagnosticBuilder
Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b529e5b..0766b1e 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -19,6 +19,7 @@
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
#include "SemaTemplate.h"
+#include "AnalysisBasedWarnings.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
@@ -298,7 +299,7 @@ public:
/// \brief The set of static functions seen so far that have not been used.
std::vector<FunctionDecl*> UnusedStaticFuncs;
-
+
class AccessedEntity {
public:
/// A member declaration found through lookup. The target is the
@@ -311,30 +312,33 @@ public:
bool isMemberAccess() const { return IsMember; }
- AccessedEntity(MemberNonce _,
+ AccessedEntity(ASTContext &Context,
+ MemberNonce _,
CXXRecordDecl *NamingClass,
AccessSpecifier Access,
NamedDecl *Target)
: Access(Access), IsMember(true),
Target(Target), NamingClass(NamingClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(MemberNonce _,
+ AccessedEntity(ASTContext &Context,
+ MemberNonce _,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl)
: Access(FoundDecl.getAccess()), IsMember(true),
Target(FoundDecl.getDecl()), NamingClass(NamingClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
- AccessedEntity(BaseNonce _,
+ AccessedEntity(ASTContext &Context,
+ BaseNonce _,
CXXRecordDecl *BaseClass,
CXXRecordDecl *DerivedClass,
AccessSpecifier Access)
: Access(Access), IsMember(false),
Target(BaseClass), NamingClass(DerivedClass),
- Diag(0) {
+ Diag(0, Context.getDiagAllocator()) {
}
bool isQuiet() const { return Diag.getDiagID() == 0; }
@@ -362,7 +366,7 @@ public:
PartialDiagnostic &setDiag(unsigned DiagID) {
assert(isQuiet() && "partial diagnostic already defined");
assert(DiagID && "creating null diagnostic");
- Diag = PartialDiagnostic(DiagID);
+ Diag.Reset(DiagID);
return Diag;
}
const PartialDiagnostic &getDiag() const {
@@ -609,23 +613,16 @@ public:
};
/// \brief Emit a diagnostic.
- SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
- if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) {
- // If we encountered an error during template argument
- // deduction, and that error is one of the SFINAE errors,
- // suppress the diagnostic.
- ++NumSFINAEErrors;
- Diags.setLastDiagnosticIgnored();
- return SemaDiagnosticBuilder(*this);
- }
-
- DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
- return SemaDiagnosticBuilder(DB, *this, DiagID);
- }
+ SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
/// \brief Emit a partial diagnostic.
SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD);
+ /// \brief Build a partial diagnostic.
+ PartialDiagnostic PDiag(unsigned DiagID = 0) {
+ return PartialDiagnostic(DiagID, Context.getDiagAllocator());
+ }
+
virtual void DeleteExpr(ExprTy *E);
virtual void DeleteStmt(StmtTy *S);
@@ -727,6 +724,7 @@ public:
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc,
+ bool *MissingExceptionSpecification = 0,
bool *MissingEmptyExceptionSpecification = 0);
bool CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
@@ -742,10 +740,12 @@ public:
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
- std::pair<SourceLocation,
- PartialDiagnostic> Note =
- std::make_pair(SourceLocation(), PDiag()));
-
+ std::pair<SourceLocation, PartialDiagnostic> Note);
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD);
+ bool RequireCompleteType(SourceLocation Loc, QualType T,
+ unsigned DiagID);
+
QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E);
@@ -783,7 +783,8 @@ public:
const LookupResult &Previous,
Scope *S);
void DiagnoseFunctionSpecifiers(Declarator& D);
- void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R);
+ void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
+ void CheckShadow(Scope *S, VarDecl *D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@@ -827,6 +828,7 @@ public:
virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init);
void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit);
void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto);
+ virtual void ActOnInitializerError(DeclPtrTy Dcl);
virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc);
virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclPtrTy *Group,
@@ -1110,9 +1112,6 @@ public:
bool SuppressUserConversions, bool ForceRValue,
bool InOverloadResolution);
- bool PerformCopyInitialization(Expr *&From, QualType ToType,
- AssignmentAction Action, bool Elidable = false);
-
OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
OwningExprResult Init);
@@ -1121,6 +1120,7 @@ public:
CXXRecordDecl *ActingContext);
bool PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method);
ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From);
@@ -1128,6 +1128,7 @@ public:
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
NamedDecl *Member);
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
@@ -1248,11 +1249,15 @@ public:
const PartialDiagnostic &PDiag);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
- bool Complain);
+ bool Complain,
+ DeclAccessPair &Found);
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
- Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+ Expr *FixOverloadedFunctionReference(Expr *E,
+ NamedDecl *FoundDecl,
+ FunctionDecl *Fn);
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
+ NamedDecl *FoundDecl,
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
@@ -1448,7 +1453,7 @@ public:
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
- bool &IncompleteImpl);
+ bool &IncompleteImpl, unsigned DiagID);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
ObjCMethodDecl *IntfMethod);
@@ -1464,7 +1469,7 @@ public:
bool& IncompleteImpl,
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
- ObjCInterfaceDecl *IDecl);
+ ObjCContainerDecl *CDecl);
/// CheckImplementationIvars - This routine checks if the instance variables
/// listed in the implelementation match those listed in the interface.
@@ -2397,7 +2402,9 @@ public:
Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
QualType EncodedType,
SourceLocation RParenLoc);
- CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method);
+ CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp,
+ NamedDecl *FoundDecl,
+ CXXMethodDecl *Method);
virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc,
SourceLocation EncodeLoc,
@@ -2471,9 +2478,7 @@ public:
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
- unsigned NumInitializers,
- bool IsImplicitConstructor,
- bool AnyErrors);
+ unsigned NumInitializers, bool AnyErrors);
/// MarkBaseAndMemberDestructorsReferenced - Given a record decl,
/// mark all the non-trivial destructors of its members and bases as
@@ -2495,7 +2500,8 @@ public:
/// MarkVirtualMembersReferenced - Will mark all virtual members of the given
/// CXXRecordDecl referenced.
- void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD);
+ void MarkVirtualMembersReferenced(SourceLocation Loc,
+ const CXXRecordDecl *RD);
/// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes
/// that might need to have their virtual members marked as referenced.
@@ -2513,7 +2519,8 @@ public:
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac);
+ SourceLocation RBrac,
+ AttributeList *AttrList);
virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template);
virtual void ActOnStartDelayedMemberDeclarations(Scope *S,
@@ -2640,15 +2647,21 @@ public:
Expr *ObjectExpr,
Expr *ArgExpr,
DeclAccessPair FoundDecl);
+ AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr,
+ DeclAccessPair FoundDecl);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
QualType Base, QualType Derived,
const CXXBasePath &Path,
unsigned DiagID,
bool ForceCheck = false,
bool ForceUnprivileged = false);
-
void CheckLookupAccess(const LookupResult &R);
+ void HandleDependentAccessCheck(const DependentDiagnostic &DD,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+ void PerformDependentDiagnostics(const DeclContext *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
+
void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
enum AbstractDiagSelID {
@@ -2869,12 +2882,29 @@ public:
Decl *Param,
TemplateArgumentListBuilder &Converted);
+ /// \brief Specifies the context in which a particular template
+ /// argument is being checked.
+ enum CheckTemplateArgumentKind {
+ /// \brief The template argument was specified in the code or was
+ /// instantiated with some deduced template arguments.
+ CTAK_Specified,
+
+ /// \brief The template argument was deduced via template argument
+ /// deduction.
+ CTAK_Deduced,
+
+ /// \brief The template argument was deduced from an array bound
+ /// via template argument deduction.
+ CTAK_DeducedFromArrayBound
+ };
+
bool CheckTemplateArgument(NamedDecl *Param,
const TemplateArgumentLoc &Arg,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
- TemplateArgumentListBuilder &Converted);
+ TemplateArgumentListBuilder &Converted,
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
@@ -2888,15 +2918,22 @@ public:
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
TypeSourceInfo *Arg);
- bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
- NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg,
TemplateArgument &Converted);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted);
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
+
+ OwningExprResult
+ BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+ QualType ParamType,
+ SourceLocation Loc);
+ OwningExprResult
+ BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc);
/// \brief Enumeration describing how template parameter lists are compared
/// for equality.
@@ -3119,14 +3156,15 @@ public:
TemplateDeductionResult
SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info);
TemplateDeductionResult
FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info);
@@ -3480,15 +3518,27 @@ public:
/// \brief Whether we have already exited this scope.
bool Exited;
+ /// \brief Whether this scope is temporary, meaning that we should
+ /// remove any additions we make once we exit this
+ /// scope. Temporary scopes are always combined with their outer
+ /// scopes.
+ bool Temporary;
+
+ /// \brief List of the declarations that we have added into this
+ /// temporary scope. They will be removed when we exit the
+ /// temporary scope.
+ llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
+ bool Temporary = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false) {
- if (!CombineWithOuterScope)
+ Exited(false), Temporary(Temporary) {
+ if (!CombineWithOuterScope && !Temporary)
SemaRef.CurrentInstantiationScope = this;
else
assert(SemaRef.CurrentInstantiationScope &&
@@ -3496,8 +3546,11 @@ public:
}
~LocalInstantiationScope() {
- if (!Exited)
+ if (!Exited) {
SemaRef.CurrentInstantiationScope = Outer;
+ for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I)
+ LocalDecls.erase(AddedTemporaryDecls[I]);
+ }
}
/// \brief Exit this local instantiation scope early.
@@ -3530,6 +3583,10 @@ public:
void InstantiatedLocal(const Decl *D, Decl *Inst) {
Decl *&Stored = LocalDecls[D];
assert((!Stored || Stored == Inst) && "Already instantiated this local");
+
+ if (Temporary && !Stored)
+ AddedTemporaryDecls.push_back(D);
+
Stored = Inst;
}
};
@@ -3541,6 +3598,9 @@ public:
/// \brief The number of typos corrected by CorrectTypo.
unsigned TyposCorrected;
+ /// \brief Worker object for performing CFG-based warnings.
+ sema::AnalysisBasedWarnings AnalysisWarnings;
+
/// \brief An entity for which implicit template instantiation is required.
///
/// The source location associated with the declaration is the first place in
@@ -3714,7 +3774,7 @@ public:
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \arg PropertyTy.
- void CheckObjCPropertyAttributes(QualType PropertyTy,
+ void CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
SourceLocation Loc,
unsigned &Attributes);
void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC);
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 40b320c..f628884 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
using namespace clang;
@@ -52,136 +53,323 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
namespace {
struct EffectiveContext {
- EffectiveContext() : Function(0) {}
+ EffectiveContext() : Inner(0), Dependent(false) {}
- explicit EffectiveContext(DeclContext *DC) {
- if (isa<FunctionDecl>(DC)) {
- Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
- DC = Function->getDeclContext();
- } else
- Function = 0;
+ explicit EffectiveContext(DeclContext *DC)
+ : Inner(DC),
+ Dependent(DC->isDependentContext()) {
// C++ [class.access.nest]p1:
// A nested class is a member and as such has the same access
// rights as any other member.
// C++ [class.access]p2:
// A member of a class can also access all the names to which
- // the class has access.
- // This implies that the privileges of nesting are transitive.
- while (isa<CXXRecordDecl>(DC)) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
- Records.push_back(Record);
- DC = Record->getDeclContext();
+ // the class has access. A local class of a member function
+ // may access the same names that the member function itself
+ // may access.
+ // This almost implies that the privileges of nesting are transitive.
+ // Technically it says nothing about the local classes of non-member
+ // functions (which can gain privileges through friendship), but we
+ // take that as an oversight.
+ while (true) {
+ if (isa<CXXRecordDecl>(DC)) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ Records.push_back(Record);
+ DC = Record->getDeclContext();
+ } else if (isa<FunctionDecl>(DC)) {
+ FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
+ Functions.push_back(Function);
+ DC = Function->getDeclContext();
+ } else if (DC->isFileContext()) {
+ break;
+ } else {
+ DC = DC->getParent();
+ }
}
}
+ bool isDependent() const { return Dependent; }
+
bool includesClass(const CXXRecordDecl *R) const {
R = R->getCanonicalDecl();
return std::find(Records.begin(), Records.end(), R)
!= Records.end();
}
+ /// Retrieves the innermost "useful" context. Can be null if we're
+ /// doing access-control without privileges.
+ DeclContext *getInnerContext() const {
+ return Inner;
+ }
+
+ typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
+
+ DeclContext *Inner;
+ llvm::SmallVector<FunctionDecl*, 4> Functions;
llvm::SmallVector<CXXRecordDecl*, 4> Records;
- FunctionDecl *Function;
+ bool Dependent;
};
}
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+ DeclContext *DC = D->getDeclContext();
+
+ // This can only happen at top: enum decls only "publish" their
+ // immediate members.
+ if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
while (DeclaringClass->isAnonymousStructOrUnion())
DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
return DeclaringClass;
}
+static bool MightInstantiateTo(Sema &S, DeclContext *Context,
+ DeclContext *Friend) {
+ if (Friend == Context)
+ return true;
+
+ assert(!Friend->isDependentContext() &&
+ "can't handle friends with dependent contexts here");
+
+ if (!Context->isDependentContext())
+ return false;
+
+ if (Friend->isFileContext())
+ return false;
+
+ // TODO: this is very conservative
+ return true;
+}
+
+// Asks whether the type in 'context' can ever instantiate to the type
+// in 'friend'.
+static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
+ if (Friend == Context)
+ return true;
+
+ if (!Friend->isDependentType() && !Context->isDependentType())
+ return false;
+
+ // TODO: this is very conservative.
+ return true;
+}
+
+static bool MightInstantiateTo(Sema &S,
+ FunctionDecl *Context,
+ FunctionDecl *Friend) {
+ if (Context->getDeclName() != Friend->getDeclName())
+ return false;
+
+ if (!MightInstantiateTo(S,
+ Context->getDeclContext(),
+ Friend->getDeclContext()))
+ return false;
+
+ CanQual<FunctionProtoType> FriendTy
+ = S.Context.getCanonicalType(Friend->getType())
+ ->getAs<FunctionProtoType>();
+ CanQual<FunctionProtoType> ContextTy
+ = S.Context.getCanonicalType(Context->getType())
+ ->getAs<FunctionProtoType>();
+
+ // There isn't any way that I know of to add qualifiers
+ // during instantiation.
+ if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
+ return false;
+
+ if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
+ return false;
+
+ if (!MightInstantiateTo(S,
+ ContextTy->getResultType(),
+ FriendTy->getResultType()))
+ return false;
+
+ for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
+ if (!MightInstantiateTo(S,
+ ContextTy->getArgType(I),
+ FriendTy->getArgType(I)))
+ return false;
+
+ return true;
+}
+
+static bool MightInstantiateTo(Sema &S,
+ FunctionTemplateDecl *Context,
+ FunctionTemplateDecl *Friend) {
+ return MightInstantiateTo(S,
+ Context->getTemplatedDecl(),
+ Friend->getTemplatedDecl());
+}
+
static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Friend) {
- // FIXME: close matches becuse of dependency
if (EC.includesClass(Friend))
return Sema::AR_accessible;
+ if (EC.isDependent()) {
+ CanQualType FriendTy
+ = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
+
+ for (EffectiveContext::record_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ CanQualType ContextTy
+ = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
+ if (MightInstantiateTo(S, ContextTy, FriendTy))
+ return Sema::AR_dependent;
+ }
+ }
+
return Sema::AR_inaccessible;
}
static Sema::AccessResult MatchesFriend(Sema &S,
const EffectiveContext &EC,
- FriendDecl *Friend) {
- if (Type *T = Friend->getFriendType()) {
- CanQualType CT = T->getCanonicalTypeUnqualified();
- if (const RecordType *RT = CT->getAs<RecordType>())
- return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
-
- // TODO: we can fail early for a lot of type classes.
- if (T->isDependentType())
- return Sema::AR_dependent;
+ CanQualType Friend) {
+ if (const RecordType *RT = Friend->getAs<RecordType>())
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
- return Sema::AR_inaccessible;
- }
+ // TODO: we can do better than this
+ if (Friend->isDependentType())
+ return Sema::AR_dependent;
- NamedDecl *D
- = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
+ return Sema::AR_inaccessible;
+}
- // FIXME: declarations with dependent or templated scope.
+/// Determines whether the given friend class template matches
+/// anything in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ ClassTemplateDecl *Friend) {
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
- // For class templates, we want to check whether any of the records
- // are possible specializations of the template.
- if (isa<ClassTemplateDecl>(D)) {
- for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
- I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
- CXXRecordDecl *Record = *I;
- ClassTemplateDecl *CTD;
+ // Check whether the friend is the template of a class in the
+ // context chain.
+ for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ CXXRecordDecl *Record = *I;
- // A specialization of the template...
- if (isa<ClassTemplateSpecializationDecl>(Record)) {
- CTD = cast<ClassTemplateSpecializationDecl>(Record)
- ->getSpecializedTemplate();
+ // Figure out whether the current class has a template:
+ ClassTemplateDecl *CTD;
- // ... or the template pattern itself.
- } else {
- CTD = Record->getDescribedClassTemplate();
- }
+ // A specialization of the template...
+ if (isa<ClassTemplateSpecializationDecl>(Record)) {
+ CTD = cast<ClassTemplateSpecializationDecl>(Record)
+ ->getSpecializedTemplate();
- if (CTD && D == CTD->getCanonicalDecl())
- return Sema::AR_accessible;
+ // ... or the template pattern itself.
+ } else {
+ CTD = Record->getDescribedClassTemplate();
+ if (!CTD) continue;
}
- return Sema::AR_inaccessible;
+ // It's a match.
+ if (Friend == CTD->getCanonicalDecl())
+ return Sema::AR_accessible;
+
+ // If the context isn't dependent, it can't be a dependent match.
+ if (!EC.isDependent())
+ continue;
+
+ // If the template names don't match, it can't be a dependent
+ // match. This isn't true in C++0x because of template aliases.
+ if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
+ continue;
+
+ // If the class's context can't instantiate to the friend's
+ // context, it can't be a dependent match.
+ if (!MightInstantiateTo(S, CTD->getDeclContext(),
+ Friend->getDeclContext()))
+ continue;
+
+ // Otherwise, it's a dependent match.
+ OnFailure = Sema::AR_dependent;
+ }
+
+ return OnFailure;
+}
+
+/// Determines whether the given friend function matches anything in
+/// the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionDecl *Friend) {
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+
+ for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
+ if (Friend == *I)
+ return Sema::AR_accessible;
+
+ if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
+ OnFailure = Sema::AR_dependent;
}
- // Same thing for function templates.
- if (isa<FunctionTemplateDecl>(D)) {
- if (!EC.Function) return Sema::AR_inaccessible;
+ return OnFailure;
+}
+
+/// Determines whether the given friend function template matches
+/// anything in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionTemplateDecl *Friend) {
+ if (EC.Functions.empty()) return Sema::AR_inaccessible;
- FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
+ Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+
+ for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
+ I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
+
+ FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
if (!FTD)
- FTD = EC.Function->getDescribedFunctionTemplate();
+ FTD = (*I)->getDescribedFunctionTemplate();
+ if (!FTD)
+ continue;
+
+ FTD = FTD->getCanonicalDecl();
- if (FTD && D == FTD->getCanonicalDecl())
+ if (Friend == FTD)
return Sema::AR_accessible;
-
- return Sema::AR_inaccessible;
+
+ if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
+ OnFailure = Sema::AR_dependent;
}
- // Friend functions. FIXME: close matches due to dependency.
- //
- // The decl pointers in EC have been canonicalized, so pointer
- // equality is sufficient.
- if (D == EC.Function)
- return Sema::AR_accessible;
+ return OnFailure;
+}
- if (isa<CXXRecordDecl>(D))
- return MatchesFriend(S, EC, cast<CXXRecordDecl>(D));
+/// Determines whether the given friend declaration matches anything
+/// in the effective context.
+static Sema::AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *FriendD) {
+ if (TypeSourceInfo *T = FriendD->getFriendType())
+ return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
- return Sema::AR_inaccessible;
+ NamedDecl *Friend
+ = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
+
+ // FIXME: declarations with dependent or templated scope.
+
+ if (isa<ClassTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
+
+ if (isa<FunctionTemplateDecl>(Friend))
+ return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
+
+ if (isa<CXXRecordDecl>(Friend))
+ return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
+
+ assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
+ return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
static Sema::AccessResult GetFriendKind(Sema &S,
const EffectiveContext &EC,
const CXXRecordDecl *Class) {
- // A class always has access to its own members.
- if (EC.includesClass(Class))
- return Sema::AR_accessible;
-
Sema::AccessResult OnFailure = Sema::AR_inaccessible;
// Okay, check friends.
@@ -209,9 +397,88 @@ static Sema::AccessResult GetFriendKind(Sema &S,
return OnFailure;
}
+static Sema::AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *NamingClass,
+ AccessSpecifier Access) {
+ assert(NamingClass->getCanonicalDecl() == NamingClass &&
+ "declaration should be canonicalized before being passed here");
+
+ if (Access == AS_public) return Sema::AR_accessible;
+ assert(Access == AS_private || Access == AS_protected);
+
+ for (EffectiveContext::record_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ // All the declarations in EC have been canonicalized, so pointer
+ // equality from this point on will work fine.
+ const CXXRecordDecl *ECRecord = *I;
+
+ // [B2] and [M2]
+ if (ECRecord == NamingClass)
+ return Sema::AR_accessible;
+
+ // [B3] and [M3]
+ if (Access == AS_protected &&
+ ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
+ return Sema::AR_accessible;
+ }
+
+ return GetFriendKind(S, EC, NamingClass);
+}
+
/// Finds the best path from the naming class to the declaring class,
/// taking friend declarations into account.
///
+/// C++0x [class.access.base]p5:
+/// A member m is accessible at the point R when named in class N if
+/// [M1] m as a member of N is public, or
+/// [M2] m as a member of N is private, and R occurs in a member or
+/// friend of class N, or
+/// [M3] m as a member of N is protected, and R occurs in a member or
+/// friend of class N, or in a member or friend of a class P
+/// derived from N, where m as a member of P is public, private,
+/// or protected, or
+/// [M4] there exists a base class B of N that is accessible at R, and
+/// m is accessible at R when named in class B.
+///
+/// C++0x [class.access.base]p4:
+/// A base class B of N is accessible at R, if
+/// [B1] an invented public member of B would be a public member of N, or
+/// [B2] R occurs in a member or friend of class N, and an invented public
+/// member of B would be a private or protected member of N, or
+/// [B3] R occurs in a member or friend of a class P derived from N, and an
+/// invented public member of B would be a private or protected member
+/// of P, or
+/// [B4] there exists a class S such that B is a base class of S accessible
+/// at R and S is a base class of N accessible at R.
+///
+/// Along a single inheritance path we can restate both of these
+/// iteratively:
+///
+/// First, we note that M1-4 are equivalent to B1-4 if the member is
+/// treated as a notional base of its declaring class with inheritance
+/// access equivalent to the member's access. Therefore we need only
+/// ask whether a class B is accessible from a class N in context R.
+///
+/// Let B_1 .. B_n be the inheritance path in question (i.e. where
+/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
+/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
+/// closest accessible base in the path:
+/// Access(a, b) = (* access on the base specifier from a to b *)
+/// Merge(a, forbidden) = forbidden
+/// Merge(a, private) = forbidden
+/// Merge(a, b) = min(a,b)
+/// Accessible(c, forbidden) = false
+/// Accessible(c, private) = (R is c) || IsFriend(c, R)
+/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
+/// Accessible(c, public) = true
+/// ACAB(n) = public
+/// ACAB(i) =
+/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
+/// if Accessible(B_i, AccessToBase) then public else AccessToBase
+///
+/// B is an accessible base of N at R iff ACAB(1) = public.
+///
/// \param FinalAccess the access of the "final step", or AS_none if
/// there is no final step.
/// \return null if friendship is dependent
@@ -230,6 +497,8 @@ static CXXBasePath *FindBestPath(Sema &S,
assert(FinalAccess != AS_none && "forbidden access after declaring class");
+ bool AnyDependent = false;
+
// Derive the friend-modified access along each path.
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
PI != PE; ++PI) {
@@ -251,19 +520,15 @@ static CXXBasePath *FindBestPath(Sema &S,
}
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
- if (BaseAccess != AS_public) {
- switch (GetFriendKind(S, EC, I->Class)) {
- case Sema::AR_inaccessible:
- PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
- break;
- case Sema::AR_accessible:
- PathAccess = AS_public;
- break;
- case Sema::AR_dependent:
- return 0;
- case Sema::AR_delayed:
- llvm_unreachable("friend resolution is never delayed"); break;
- }
+ PathAccess = std::max(PathAccess, BaseAccess);
+ switch (HasAccess(S, EC, I->Class, PathAccess)) {
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_accessible: PathAccess = AS_public; break;
+ case Sema::AR_dependent:
+ AnyDependent = true;
+ goto Next;
+ case Sema::AR_delayed:
+ llvm_unreachable("friend resolution is never delayed"); break;
}
}
@@ -272,9 +537,23 @@ static CXXBasePath *FindBestPath(Sema &S,
if (BestPath == 0 || PathAccess < BestPath->Access) {
BestPath = &*PI;
BestPath->Access = PathAccess;
+
+ // Short-circuit if we found a public path.
+ if (BestPath->Access == AS_public)
+ return BestPath;
}
+
+ Next: ;
}
+ assert((!BestPath || BestPath->Access != AS_public) &&
+ "fell out of loop with public path");
+
+ // We didn't find a public path, but at least one path was subject
+ // to dependent friendship, so delay the check.
+ if (AnyDependent)
+ return 0;
+
return BestPath;
}
@@ -282,16 +561,27 @@ static CXXBasePath *FindBestPath(Sema &S,
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- CXXRecordDecl *DeclaringClass,
- NamedDecl *D, AccessSpecifier Access) {
+ const Sema::AccessedEntity &Entity) {
+ AccessSpecifier Access = Entity.getAccess();
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ NamingClass = NamingClass->getCanonicalDecl();
+
+ NamedDecl *D;
+ CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ D = Entity.getTargetDecl();
+ DeclaringClass = FindDeclaringClass(D);
+ } else {
+ D = 0;
+ DeclaringClass = Entity.getBaseClass();
+ }
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+
// Easy case: the decl's natural access determined its path access.
// We have to check against AS_private here in case Access is AS_none,
// indicating a non-public member of a private base class.
- //
- // DependentFriend should be impossible here.
if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (GetFriendKind(S, EC, DeclaringClass)) {
+ switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) {
case Sema::AR_inaccessible: {
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
@@ -357,144 +647,166 @@ static void DiagnoseAccessPath(Sema &S,
llvm_unreachable("access not apparently constrained by path");
}
-/// Diagnose an inaccessible class member.
-static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- NamedDecl *D = Entity.getTargetDecl();
- CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity) {
+ const CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ NamedDecl *D;
+ const CXXRecordDecl *DeclaringClass;
+ if (Entity.isMemberAccess()) {
+ D = Entity.getTargetDecl();
+ DeclaringClass = FindDeclaringClass(D);
+ } else {
+ D = 0;
+ DeclaringClass = Entity.getBaseClass();
+ }
S.Diag(Loc, Entity.getDiag())
- << (Access == AS_protected)
- << D->getDeclName()
+ << (Entity.getAccess() == AS_protected)
+ << (D ? D->getDeclName() : DeclarationName())
<< S.Context.getTypeDeclType(NamingClass)
<< S.Context.getTypeDeclType(DeclaringClass);
- DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
+ DiagnoseAccessPath(S, EC, Entity);
}
-/// Diagnose an inaccessible hierarchy conversion.
-static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- S.Diag(Loc, Entity.getDiag())
- << (Access == AS_protected)
- << DeclarationName()
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass());
- DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
- Entity.getBaseClass(), 0, Access);
-}
+/// Determines whether the accessed entity is accessible. Public members
+/// have been weeded out by this point.
+static Sema::AccessResult IsAccessible(Sema &S,
+ const EffectiveContext &EC,
+ const Sema::AccessedEntity &Entity) {
+ // Determine the actual naming class.
+ CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ while (NamingClass->isAnonymousStructOrUnion())
+ NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
+ NamingClass = NamingClass->getCanonicalDecl();
-static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
- const EffectiveContext &EC,
- CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- const Sema::AccessedEntity &Entity) {
- if (Entity.isMemberAccess())
- DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
- else
- DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
-}
+ AccessSpecifier UnprivilegedAccess = Entity.getAccess();
+ assert(UnprivilegedAccess != AS_public && "public access not weeded out");
+ // Before we try to recalculate access paths, try to white-list
+ // accesses which just trade in on the final step, i.e. accesses
+ // which don't require [M4] or [B4]. These are by far the most
+ // common forms of access.
+ if (UnprivilegedAccess != AS_none) {
+ switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) {
+ case Sema::AR_dependent:
+ // This is actually an interesting policy decision. We don't
+ // *have* to delay immediately here: we can do the full access
+ // calculation in the hope that friendship on some intermediate
+ // class will make the declaration accessible non-dependently.
+ // But that's not cheap, and odds are very good (note: assertion
+ // made without data) that the friend declaration will determine
+ // access.
+ return Sema::AR_dependent;
+
+ case Sema::AR_accessible: return Sema::AR_accessible;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_delayed:
+ llvm_unreachable("friendship never subject to contextual delay");
+ }
+ }
-/// Try to elevate access using friend declarations. This is
-/// potentially quite expensive.
-static void TryElevateAccess(Sema &S,
- const EffectiveContext &EC,
- const Sema::AccessedEntity &Entity,
- AccessSpecifier &Access) {
+ // Determine the declaring class.
CXXRecordDecl *DeclaringClass;
if (Entity.isMemberAccess()) {
DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
} else {
DeclaringClass = Entity.getBaseClass();
}
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+
+ // We lower member accesses to base accesses by pretending that the
+ // member is a base class of its declaring class.
+ AccessSpecifier FinalAccess;
- // Adjust the declaration of the referred entity.
- AccessSpecifier DeclAccess = AS_public;
if (Entity.isMemberAccess()) {
+ // Determine if the declaration is accessible from EC when named
+ // in its declaring class.
NamedDecl *Target = Entity.getTargetDecl();
- DeclAccess = Target->getAccess();
- if (DeclAccess != AS_public) {
- switch (GetFriendKind(S, EC, DeclaringClass)) {
- case Sema::AR_accessible: DeclAccess = AS_public; break;
- case Sema::AR_inaccessible: break;
- case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
- case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
- }
+ FinalAccess = Target->getAccess();
+ switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) {
+ case Sema::AR_accessible: FinalAccess = AS_public; break;
+ case Sema::AR_inaccessible: break;
+ case Sema::AR_dependent: return Sema::AR_dependent; // see above
+ case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
}
- if (DeclaringClass == NamingClass) {
- Access = DeclAccess;
- return;
- }
+ if (DeclaringClass == NamingClass)
+ return (FinalAccess == AS_public
+ ? Sema::AR_accessible
+ : Sema::AR_inaccessible);
+ } else {
+ FinalAccess = AS_public;
}
assert(DeclaringClass != NamingClass);
// Append the declaration's access if applicable.
CXXBasePaths Paths;
- CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
- DeclaringClass, DeclAccess, Paths);
- if (!Path) {
- // FIXME: delay dependent friendship
- return;
- }
+ CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass,
+ FinalAccess, Paths);
+ if (!Path)
+ return Sema::AR_dependent;
+
+ assert(Path->Access <= UnprivilegedAccess &&
+ "access along best path worse than direct?");
+ if (Path->Access == AS_public)
+ return Sema::AR_accessible;
+ return Sema::AR_inaccessible;
+}
- // Grab the access along the best path (note that this includes the
- // final-step access).
- AccessSpecifier NewAccess = Path->Access;
- assert(NewAccess <= Access && "access along best path worse than direct?");
- Access = NewAccess;
+static void DelayAccess(Sema &S,
+ const EffectiveContext &EC,
+ SourceLocation Loc,
+ const Sema::AccessedEntity &Entity) {
+ assert(EC.isDependent() && "delaying non-dependent access");
+ DeclContext *DC = EC.getInnerContext();
+ assert(DC->isDependentContext() && "delaying non-dependent access");
+ DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
+ Loc,
+ Entity.isMemberAccess(),
+ Entity.getAccess(),
+ Entity.getTargetDecl(),
+ Entity.getNamingClass(),
+ Entity.getDiag());
}
/// Checks access to an entity from the given effective context.
static Sema::AccessResult CheckEffectiveAccess(Sema &S,
const EffectiveContext &EC,
SourceLocation Loc,
- Sema::AccessedEntity const &Entity) {
- AccessSpecifier Access = Entity.getAccess();
- assert(Access != AS_public && "called for public access!");
+ const Sema::AccessedEntity &Entity) {
+ assert(Entity.getAccess() != AS_public && "called for public access!");
- // Find a non-anonymous naming class. For records with access,
- // there should always be one of these.
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
- while (NamingClass->isAnonymousStructOrUnion())
- NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
+ switch (IsAccessible(S, EC, Entity)) {
+ case Sema::AR_dependent:
+ DelayAccess(S, EC, Loc, Entity);
+ return Sema::AR_dependent;
- // White-list accesses from classes with privileges equivalent to the
- // naming class --- but only if the access path isn't forbidden
- // (i.e. an access of a private member from a subclass).
- if (Access != AS_none && EC.includesClass(NamingClass))
- return Sema::AR_accessible;
+ case Sema::AR_delayed:
+ llvm_unreachable("IsAccessible cannot contextually delay");
- // Try to elevate access.
- // FIXME: delay if elevation was dependent?
- // TODO: on some code, it might be better to do the protected check
- // without trying to elevate first.
- TryElevateAccess(S, EC, Entity, Access);
- if (Access == AS_public) return Sema::AR_accessible;
+ case Sema::AR_inaccessible:
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, Entity);
+ return Sema::AR_inaccessible;
- // Protected access.
- if (Access == AS_protected) {
- // FIXME: implement [class.protected]p1
- for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
- I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
- if ((*I)->isDerivedFrom(NamingClass))
- return Sema::AR_accessible;
+ case Sema::AR_accessible:
+ break;
+ }
- // FIXME: delay if we can't decide class derivation yet.
+ // We only consider the natural access of the declaration when
+ // deciding whether to do the protected check.
+ if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) {
+ NamedDecl *D = Entity.getTargetDecl();
+ if (isa<FieldDecl>(D) ||
+ (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) {
+ // FIXME: implement [class.protected]
+ }
}
- // Okay, that's it, reject it.
- if (!Entity.isQuiet())
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
- return Sema::AR_inaccessible;
+ return Sema::AR_accessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
@@ -526,6 +838,37 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
DD.Triggered = true;
}
+void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ SourceLocation Loc = DD.getAccessLoc();
+ AccessSpecifier Access = DD.getAccess();
+
+ Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
+ TemplateArgs);
+ if (!NamingD) return;
+ Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
+ TemplateArgs);
+ if (!TargetD) return;
+
+ if (DD.isAccessToMember()) {
+ AccessedEntity Entity(Context,
+ AccessedEntity::Member,
+ cast<CXXRecordDecl>(NamingD),
+ Access,
+ cast<NamedDecl>(TargetD));
+ Entity.setDiag(DD.getDiagnostic());
+ CheckAccess(*this, Loc, Entity);
+ } else {
+ AccessedEntity Entity(Context,
+ AccessedEntity::Base,
+ cast<CXXRecordDecl>(TargetD),
+ cast<CXXRecordDecl>(NamingD),
+ Access);
+ Entity.setDiag(DD.getDiagnostic());
+ CheckAccess(*this, Loc, Entity);
+ }
+}
+
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
DeclAccessPair Found) {
if (!getLangOptions().AccessControl ||
@@ -533,7 +876,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
+ Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getNameLoc(), Entity);
@@ -547,7 +891,8 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
+ Found);
Entity.setDiag(diag::err_access) << E->getSourceRange();
return CheckAccess(*this, E->getMemberLoc(), Entity);
@@ -565,7 +910,7 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
return AR_accessible;
CXXRecordDecl *NamingClass = Dtor->getParent();
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Dtor, Access));
Entity.setDiag(PDiag); // TODO: avoid copy
@@ -581,7 +926,7 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Constructor, Access));
Entity.setDiag(diag::err_access_ctor);
@@ -599,7 +944,7 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
return AR_accessible;
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
- AccessedEntity Entity(AccessedEntity::Member, NamingClass,
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
DeclAccessPair::make(Target, Access));
Entity.setDiag(Diag);
return CheckAccess(*this, UseLoc, Entity);
@@ -616,7 +961,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
Found.getAccess() == AS_public)
return AR_accessible;
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
Entity.setDiag(diag::err_access)
<< PlacementRange;
@@ -637,7 +982,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
Entity.setDiag(diag::err_access)
<< ObjectExpr->getSourceRange()
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
@@ -645,6 +990,32 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
return CheckAccess(*this, OpLoc, Entity);
}
+Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
+ DeclAccessPair Found) {
+ if (!getLangOptions().AccessControl ||
+ Found.getAccess() == AS_none ||
+ Found.getAccess() == AS_public)
+ return AR_accessible;
+
+ OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
+ NestedNameSpecifier *Qualifier = Ovl->getQualifier();
+ assert(Qualifier && "address of overloaded member without qualifier");
+
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(Ovl->getQualifierRange());
+ DeclContext *DC = computeDeclContext(SS);
+ assert(DC && DC->isRecord() && "scope did not resolve to record");
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC);
+
+ AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
+ Entity.setDiag(diag::err_access)
+ << Ovl->getSourceRange();
+
+ return CheckAccess(*this, Ovl->getNameLoc(), Entity);
+}
+
+
/// Checks access for a hierarchy conversion.
///
/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
@@ -671,7 +1042,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
+ AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
+ Path.Access);
if (DiagID)
Entity.setDiag(DiagID) << Derived << Base;
@@ -688,7 +1060,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (I.getAccess() != AS_public) {
- AccessedEntity Entity(AccessedEntity::Member,
+ AccessedEntity Entity(Context, AccessedEntity::Member,
R.getNamingClass(),
I.getPair());
Entity.setDiag(diag::err_access);
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 014cec2..11c8e6d 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -315,7 +315,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- PDiag(diag::err_bad_dynamic_cast_incomplete)
+ Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
<< DestRange))
return;
} else {
@@ -353,7 +353,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- PDiag(diag::err_bad_dynamic_cast_incomplete)
+ Self.PDiag(diag::err_bad_dynamic_cast_incomplete)
<< SrcExpr->getSourceRange()))
return;
} else {
@@ -621,8 +621,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Failed;
}
- // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
- // than nothing.
+ // FIXME: We should probably have an AST node for lvalue-to-rvalue
+ // conversions.
return TC_Success;
}
@@ -698,8 +698,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
QualType OrigDestType, unsigned &msg,
CastExpr::CastKind &Kind) {
// We can only work with complete types. But don't complain if it doesn't work
- if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) ||
- Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0)))
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) ||
+ Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0)))
return TC_NotApplicable;
// Downcast can only happen in class hierarchies, so we need classes.
@@ -808,8 +808,10 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
return TC_NotApplicable;
bool WasOverloadedFunction = false;
+ DeclAccessPair FoundOverload;
if (FunctionDecl *Fn
- = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) {
+ = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false,
+ FoundOverload)) {
CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
SrcType = Self.Context.getMemberPointerType(Fn->getType(),
Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
@@ -870,13 +872,14 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
// allowing complaints if something goes wrong.
FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr,
DestType,
- true);
+ true,
+ FoundOverload);
if (!Fn) {
msg = 0;
return TC_Failed;
}
- SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn);
+ SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn);
if (!SrcExpr) {
msg = 0;
return TC_Failed;
@@ -913,27 +916,24 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// At this point of CheckStaticCast, if the destination is a reference,
// this has to work. There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
- // the reinterpret_cast way. So in C-style mode, we first try the call
- // with an ICS to suppress errors.
- if (CStyle) {
- ImplicitConversionSequence ICS;
- if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false, /*ForceRValue=*/false,
- &ICS))
- return TC_NotApplicable;
+ // the reinterpret_cast way.
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
+ InitializationKind InitKind = InitializationKind::CreateCast(OpRange,
+ CStyle);
+ InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+ if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle)
+ return TC_NotApplicable;
+
+ Sema::OwningExprResult Result
+ = InitSeq.Perform(Self, Entity, InitKind,
+ Action::MultiExprArg(Self, (void**)&SrcExpr, 1));
+ if (Result.isInvalid()) {
+ msg = 0;
+ return TC_Failed;
}
- // Now we're committed either way.
- if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false, 0,
- /*IgnoreBaseAccess=*/CStyle))
- return TC_Success;
-
- // We already got an error message.
- msg = 0;
- return TC_Failed;
+
+ SrcExpr = Result.takeAs<Expr>();
+ return TC_Success;
}
if (DestType->isRecordType()) {
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 95b79ab..c90f75e 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -486,13 +486,13 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_suggest)
<< Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
else
Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
<< Name << Found.getLookupName()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
- Found.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
+ Found.getLookupName().getAsString());
if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_previous_decl)
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 0a33485..f2520fc 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -184,13 +184,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_or:
case Builtin::BI__sync_fetch_and_and:
case Builtin::BI__sync_fetch_and_xor:
- case Builtin::BI__sync_fetch_and_nand:
case Builtin::BI__sync_add_and_fetch:
case Builtin::BI__sync_sub_and_fetch:
case Builtin::BI__sync_and_and_fetch:
case Builtin::BI__sync_or_and_fetch:
case Builtin::BI__sync_xor_and_fetch:
- case Builtin::BI__sync_nand_and_fetch:
case Builtin::BI__sync_val_compare_and_swap:
case Builtin::BI__sync_bool_compare_and_swap:
case Builtin::BI__sync_lock_test_and_set:
@@ -222,11 +220,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) {
if (CheckablePrintfAttr(Format, TheCall)) {
bool HasVAListArg = Format->getFirstArg() == 0;
- if (!HasVAListArg) {
- if (const FunctionProtoType *Proto
- = FDecl->getType()->getAs<FunctionProtoType>())
- HasVAListArg = !Proto->isVariadic();
- }
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
}
@@ -257,12 +250,6 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
return false;
bool HasVAListArg = Format->getFirstArg() == 0;
- if (!HasVAListArg) {
- const FunctionType *FT =
- Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
- if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
- HasVAListArg = !Proto->isVariadic();
- }
CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
HasVAListArg ? 0 : Format->getFirstArg() - 1);
@@ -315,14 +302,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
BUILTIN_ROW(__sync_fetch_and_or),
BUILTIN_ROW(__sync_fetch_and_and),
BUILTIN_ROW(__sync_fetch_and_xor),
- BUILTIN_ROW(__sync_fetch_and_nand),
BUILTIN_ROW(__sync_add_and_fetch),
BUILTIN_ROW(__sync_sub_and_fetch),
BUILTIN_ROW(__sync_and_and_fetch),
BUILTIN_ROW(__sync_or_and_fetch),
BUILTIN_ROW(__sync_xor_and_fetch),
- BUILTIN_ROW(__sync_nand_and_fetch),
BUILTIN_ROW(__sync_val_compare_and_swap),
BUILTIN_ROW(__sync_bool_compare_and_swap),
@@ -357,26 +342,24 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) {
case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break;
case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break;
case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break;
- case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break;
- case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break;
- case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break;
- case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break;
- case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break;
- case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break;
- case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break;
+ case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 5; break;
+ case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 6; break;
+ case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 7; break;
+ case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 8; break;
+ case Builtin::BI__sync_xor_and_fetch: BuiltinIndex = 9; break;
case Builtin::BI__sync_val_compare_and_swap:
- BuiltinIndex = 12;
+ BuiltinIndex = 10;
NumFixed = 2;
break;
case Builtin::BI__sync_bool_compare_and_swap:
- BuiltinIndex = 13;
+ BuiltinIndex = 11;
NumFixed = 2;
break;
- case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break;
+ case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break;
case Builtin::BI__sync_lock_release:
- BuiltinIndex = 15;
+ BuiltinIndex = 13;
NumFixed = 0;
break;
}
@@ -1045,6 +1028,7 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
Sema &S;
const StringLiteral *FExpr;
const Expr *OrigFormatExpr;
+ const unsigned FirstDataArg;
const unsigned NumDataArgs;
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
@@ -1056,11 +1040,12 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
bool atFirstArg;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
- const Expr *origFormatExpr,
+ const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjCLiteral,
const char *beg, bool hasVAListArg,
const CallExpr *theCall, unsigned formatIdx)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
+ FirstDataArg(firstDataArg),
NumDataArgs(numDataArgs),
IsObjCLiteral(isObjCLiteral), Beg(beg),
HasVAListArg(hasVAListArg),
@@ -1183,11 +1168,9 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
}
const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
- return TheCall->getArg(FormatIdx + i + 1);
+ return TheCall->getArg(FirstDataArg + i);
}
-
-
void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
llvm::StringRef flag,
llvm::StringRef cspec,
@@ -1329,9 +1312,18 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
return true;
if (argIndex >= NumDataArgs) {
- S.Diag(getLocationOfByte(CS.getStart()),
- diag::warn_printf_insufficient_data_args)
- << getFormatSpecifierRange(startSpecifier, specifierLen);
+ if (FS.usesPositionalArg()) {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_positional_arg_exceeds_data_args)
+ << (argIndex+1) << NumDataArgs
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+ else {
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_insufficient_data_args)
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+
// Don't do any more checking.
return false;
}
@@ -1400,7 +1392,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr,
return;
}
- CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
+ CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
TheCall->getNumArgs() - firstDataArg,
isa<ObjCStringLiteral>(OrigFormatExpr), Str,
HasVAListArg, TheCall, format_idx);
@@ -2262,10 +2254,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
}
-
- if (getLangOptions().CPlusPlus)
- if (const RecordType *RT = Param->getType()->getAs<RecordType>())
- FinalizeVarWithDestructor(Param, RT);
}
return HasInvalidParm;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e11e161..f3d0dcf 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -14,7 +14,6 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
-#include "AnalysisBasedWarnings.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -89,8 +88,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
return 0;
// We know from the grammar that this name refers to a type, so build a
- // TypenameType node to describe the type.
- // FIXME: Record somewhere that this TypenameType node has no "typename"
+ // DependentNameType node to describe the type.
+ // FIXME: Record somewhere that this DependentNameType node has no "typename"
// keyword associated with it.
return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
II, SS->getRange()).getAsOpaquePtr();
@@ -199,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
} else if (UnresolvedUsingTypenameDecl *UUDecl =
dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
// FIXME: preserve source structure information.
- T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II);
+ T = Context.getDependentNameType(ETK_None,
+ UUDecl->getTargetNestedNameSpecifier(),
+ &II);
} else {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
@@ -256,13 +257,13 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
if (!SS || !SS->isSet())
Diag(IILoc, diag::err_unknown_typename_suggest)
<< &II << Lookup.getLookupName()
- << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
else if (DeclContext *DC = computeDeclContext(*SS, false))
Diag(IILoc, diag::err_unknown_nested_typename_suggest)
<< &II << DC << Lookup.getLookupName() << SS->getRange()
- << CodeModificationHint::CreateReplacement(SourceRange(IILoc),
- Result->getNameAsString());
+ << FixItHint::CreateReplacement(SourceRange(IILoc),
+ Result->getNameAsString());
else
llvm_unreachable("could not have corrected a typo here");
@@ -286,8 +287,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
Diag(SS->getRange().getBegin(), diag::err_typename_missing)
<< (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
- << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(),
- "typename ");
+ << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get();
} else {
assert(SS && SS->isInvalid() &&
@@ -512,14 +512,30 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
// Types of valid local variables should be complete, so this should succeed.
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+
+ // White-list anything with an __attribute__((unused)) type.
+ QualType Ty = VD->getType();
+
+ // Only look at the outermost level of typedef.
+ if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) {
+ if (TT->getDecl()->hasAttr<UnusedAttr>())
+ return false;
+ }
+
+ if (const TagType *TT = Ty->getAs<TagType>()) {
+ const TagDecl *Tag = TT->getDecl();
+ if (Tag->hasAttr<UnusedAttr>())
+ return false;
+
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (!RD->hasTrivialConstructor())
return false;
if (!RD->hasTrivialDestructor())
return false;
}
}
+
+ // TODO: __attribute__((unused)) templates?
}
return true;
@@ -575,8 +591,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
(IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
Diag(RecoverLoc, diag::err_undef_interface_suggest)
<< Id << IDecl->getDeclName()
- << CodeModificationHint::CreateReplacement(RecoverLoc,
- IDecl->getNameAsString());
+ << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString());
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< IDecl->getDeclName();
@@ -982,25 +997,28 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// other tests to run.
const FunctionType *OldType = OldQType->getAs<FunctionType>();
const FunctionType *NewType = New->getType()->getAs<FunctionType>();
- if (OldType->getCallConv() != CC_Default &&
- NewType->getCallConv() == CC_Default) {
- NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
+ const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
+ const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
+ if (OldTypeInfo.getCC() != CC_Default &&
+ NewTypeInfo.getCC() == CC_Default) {
+ NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC());
New->setType(NewQType);
NewQType = Context.getCanonicalType(NewQType);
- } else if (!Context.isSameCallConv(OldType->getCallConv(),
- NewType->getCallConv())) {
+ } else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
+ NewTypeInfo.getCC())) {
// Calling conventions really aren't compatible, so complain.
Diag(New->getLocation(), diag::err_cconv_change)
- << FunctionType::getNameForCallConv(NewType->getCallConv())
- << (OldType->getCallConv() == CC_Default)
- << (OldType->getCallConv() == CC_Default ? "" :
- FunctionType::getNameForCallConv(OldType->getCallConv()));
+ << FunctionType::getNameForCallConv(NewTypeInfo.getCC())
+ << (OldTypeInfo.getCC() == CC_Default)
+ << (OldTypeInfo.getCC() == CC_Default ? "" :
+ FunctionType::getNameForCallConv(OldTypeInfo.getCC()));
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}
// FIXME: diagnose the other way around?
- if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) {
+ if (OldType->getNoReturnAttr() &&
+ !NewType->getNoReturnAttr()) {
NewQType = Context.getNoReturnType(NewQType);
New->setType(NewQType);
assert(NewQType.isCanonical());
@@ -1094,8 +1112,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
OldProto->isVariadic(),
OldProto->getTypeQuals(),
false, false, 0, 0,
- OldProto->getNoReturnAttr(),
- OldProto->getCallConv());
+ OldProto->getExtInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -1176,8 +1193,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
ArgTypes.size(),
OldProto->isVariadic(), 0,
false, false, 0, 0,
- OldProto->getNoReturnAttr(),
- OldProto->getCallConv()));
+ OldProto->getExtInfo()));
return MergeCompatibleFunctionDecls(New, Old);
}
@@ -2132,7 +2148,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< D.getCXXScopeSpec().getRange();
D.setInvalidType();
// Pretend we didn't see the scope specifier.
- DC = 0;
+ DC = CurContext;
+ Previous.clear();
}
if (getLangOptions().CPlusPlus) {
@@ -2328,8 +2345,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (SC == VarDecl::Static) {
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
} else if (SC == VarDecl::None)
SC = VarDecl::Static;
}
@@ -2405,7 +2421,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Diagnose shadowed variables before filtering for scope.
if (!D.getCXXScopeSpec().isSet())
- DiagnoseShadow(S, D, Previous);
+ CheckShadow(S, NewVD, Previous);
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
@@ -2458,19 +2474,16 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
return NewVD;
}
-/// \brief Diagnose variable or built-in function shadowing.
-///
-/// This method is called as soon as a NamedDecl materializes to check
-/// if it shadows another local or global variable, or a built-in function.
+/// \brief Diagnose variable or built-in function shadowing. Implements
+/// -Wshadow.
///
-/// For performance reasons, the lookup results are reused from the calling
-/// context.
+/// This method is called whenever a VarDecl is added to a "useful"
+/// scope.
///
/// \param S the scope in which the shadowing name is being declared
/// \param R the lookup of the name
///
-void Sema::DiagnoseShadow(Scope *S, Declarator &D,
- const LookupResult& R) {
+void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// Return if warning is ignored.
if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored)
return;
@@ -2524,6 +2537,14 @@ void Sema::DiagnoseShadow(Scope *S, Declarator &D,
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
+/// \brief Check -Wshadow without the advantage of a previous lookup.
+void Sema::CheckShadow(Scope *S, VarDecl *D) {
+ LookupResult R(*this, D->getDeclName(), D->getLocation(),
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ LookupName(R, S);
+ CheckShadow(S, D, R);
+}
+
/// \brief Perform semantic checking on a newly-created variable
/// declaration.
///
@@ -2913,6 +2934,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else {
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
+
+ // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);".
+ if (isFriend && isFunctionTemplateSpecialization) {
+ // We want to remove the "template<>", found here.
+ SourceRange RemoveRange = TemplateParams->getSourceRange();
+
+ // If we remove the template<> and the name is not a
+ // template-id, we're actually silently creating a problem:
+ // the friend declaration will refer to an untemplated decl,
+ // and clearly the user wants a template specialization. So
+ // we need to insert '<>' after the name.
+ SourceLocation InsertLoc;
+ if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+ InsertLoc = D.getName().getSourceRange().getEnd();
+ InsertLoc = PP.getLocForEndOfToken(InsertLoc);
+ }
+
+ Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
+ << Name << RemoveRange
+ << FixItHint::CreateRemoval(RemoveRange)
+ << FixItHint::CreateInsertion(InsertLoc, "<>");
+ }
}
// FIXME: Free this memory properly.
@@ -2931,8 +2974,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (!CurContext->isRecord()) {
// 'virtual' was specified outside of the class.
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getVirtualSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc());
} else {
// Okay: Add virtual to the method.
CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC);
@@ -2949,16 +2991,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_out_of_class)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getExplicitSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
} else if (!isa<CXXConstructorDecl>(NewFD) &&
!isa<CXXConversionDecl>(NewFD)) {
// 'explicit' was specified on a function that wasn't a constructor
// or conversion function.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_ctor_or_conv_function)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getExplicitSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
}
}
@@ -2971,13 +3011,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
"previously-undeclared friend function being created "
"in a non-namespace context");
+ // For now, claim that the objects have no previous declaration.
if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(
- /* PreviouslyDeclared= */ !Previous.empty());
+ FunctionTemplate->setObjectOfFriendDecl(false);
FunctionTemplate->setAccess(AS_public);
+ } else {
+ NewFD->setObjectOfFriendDecl(false);
}
- else
- NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty());
NewFD->setAccess(AS_public);
}
@@ -2993,8 +3033,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// member function definition.
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
- << CodeModificationHint::CreateRemoval(
- D.getDeclSpec().getStorageClassSpecLoc());
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
}
// Handle GNU asm-label extension (encoded as an attribute).
@@ -3092,18 +3131,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// too few of them).
Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << CodeModificationHint::CreateInsertion(
+ << FixItHint::CreateInsertion(
D.getDeclSpec().getSourceRange().getBegin(),
"template<> ");
isFunctionTemplateSpecialization = true;
+ } else {
+ // "friend void foo<>(int);" is an implicit specialization decl.
+ isFunctionTemplateSpecialization = true;
}
}
if (isFunctionTemplateSpecialization) {
- if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
- Previous))
- NewFD->setInvalidDecl();
+ if (isFriend && NewFD->getType()->isDependentType()) {
+ // FIXME: When we see a friend of a function template
+ // specialization with a dependent type, we can't match it now;
+ // for now, we just drop it, until we have a reasonable way to
+ // represent the parsed-but-not-matched friend function template
+ // specialization in the AST.
+ return 0;
+ } else if (CheckFunctionTemplateSpecialization(NewFD,
+ (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ Previous))
+ NewFD->setInvalidDecl();
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -3117,6 +3166,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
+ if (isFriend && Redeclaration) {
+ AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess();
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ FunctionTemplate->setAccess(Access);
+ } else {
+ NewFD->setObjectOfFriendDecl(true);
+ }
+ NewFD->setAccess(Access);
+ }
+
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
@@ -3303,7 +3363,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Turn this into a variadic function with no parameters.
QualType R = Context.getFunctionType(
NewFD->getType()->getAs<FunctionType>()->getResultType(),
- 0, 0, true, 0, false, false, 0, 0, false, CC_Default);
+ 0, 0, true, 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
NewFD->setType(R);
return NewFD->setInvalidDecl();
}
@@ -3747,6 +3808,41 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
return;
}
+/// ActOnInitializerError - Given that there was an error parsing an
+/// initializer for the given declaration, try to return to some form
+/// of sanity.
+void Sema::ActOnInitializerError(DeclPtrTy dcl) {
+ // Our main concern here is re-establishing invariants like "a
+ // variable's type is either dependent or complete".
+ Decl *D = dcl.getAs<Decl>();
+ if (!D || D->isInvalidDecl()) return;
+
+ VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (!VD) return;
+
+ QualType Ty = VD->getType();
+ if (Ty->isDependentType()) return;
+
+ // Require a complete type.
+ if (RequireCompleteType(VD->getLocation(),
+ Context.getBaseElementType(Ty),
+ diag::err_typecheck_decl_incomplete_type)) {
+ VD->setInvalidDecl();
+ return;
+ }
+
+ // Require an abstract type.
+ if (RequireNonAbstractType(VD->getLocation(), Ty,
+ diag::err_abstract_type_in_decl,
+ AbstractVariableType)) {
+ VD->setInvalidDecl();
+ return;
+ }
+
+ // Don't bother complaining about constructors or destructors,
+ // though.
+}
+
void Sema::ActOnUninitializedDecl(DeclPtrTy dcl,
bool TypeContainsUndeducedAuto) {
Decl *RealDecl = dcl.getAs<Decl>();
@@ -3984,8 +4080,6 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
II = 0;
D.SetIdentifier(0, D.getIdentifierLoc());
D.setInvalidType(true);
- } else {
- DiagnoseShadow(S, D, R);
}
}
}
@@ -4075,7 +4169,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
<< ";\n";
Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
<< FTI.ArgInfo[i].Ident
- << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str());
+ << FixItHint::CreateInsertion(LocAfterDecls, Code.str());
// Implicitly declare the argument as type 'int' for lack of a better
// type.
@@ -4213,14 +4307,21 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
// Check the validity of our function parameters
CheckParmsForFunctionDef(FD);
+ bool ShouldCheckShadow =
+ Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
+
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
- if (Param->getIdentifier() && FnBodyScope)
+ if (Param->getIdentifier() && FnBodyScope) {
+ if (ShouldCheckShadow)
+ CheckShadow(FnBodyScope, Param);
+
PushOnScopeChains(Param, FnBodyScope);
+ }
}
// Checking attributes of current function definition
@@ -4266,7 +4367,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
else
FD = dyn_cast_or_null<FunctionDecl>(dcl);
- sema::AnalysisBasedWarnings W(*this);
+ sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
if (FD) {
FD->setBody(Body);
@@ -4274,7 +4375,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
// C and C++ allow for main to automagically return 0.
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
- W.disableCheckFallThrough();
+ WP.disableCheckFallThrough();
}
if (!FD->isInvalidDecl())
@@ -4294,8 +4395,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Body->Destroy(Context);
return DeclPtrTy();
}
- if (!IsInstantiation)
- PopDeclContext();
// Verify and clean out per-function state.
@@ -4371,12 +4470,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
ResultType = MD->getResultType();
}
- W.IssueWarnings(dcl);
+ AnalysisWarnings.IssueWarnings(WP, dcl);
}
assert(ExprTemporaries.empty() && "Leftover temporaries in function");
}
+ if (!IsInstantiation)
+ PopDeclContext();
+
PopFunctionOrBlockScope();
// If any errors have occurred, clear out any temporaries that may have
@@ -4577,7 +4679,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
<< (NewTag == TagDecl::TK_class)
<< isTemplate << &Name
- << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc),
+ << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
OldTag == TagDecl::TK_class? "class" : "struct");
Diag(Previous->getLocation(), diag::note_previous_use);
return true;
@@ -4684,7 +4786,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
// A tag 'foo::bar' must already exist.
- Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
+ Diag(NameLoc, diag::err_not_tag_in_scope)
+ << Kind << Name << DC << SS.getRange();
Name = 0;
Invalid = true;
goto CreateNewDecl;
@@ -4732,6 +4835,79 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ // If we didn't find a previous declaration, and this is a reference
+ // (or friend reference), move to the correct scope. In C++, we
+ // also need to do a redeclaration lookup there, just in case
+ // there's a shadow friend decl.
+ if (Name && Previous.empty() &&
+ (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ if (Invalid) goto CreateNewDecl;
+ assert(SS.isEmpty());
+
+ if (TUK == TUK_Reference) {
+ // C++ [basic.scope.pdecl]p5:
+ // -- for an elaborated-type-specifier of the form
+ //
+ // class-key identifier
+ //
+ // if the elaborated-type-specifier is used in the
+ // decl-specifier-seq or parameter-declaration-clause of a
+ // function defined in namespace scope, the identifier is
+ // declared as a class-name in the namespace that contains
+ // the declaration; otherwise, except as a friend
+ // declaration, the identifier is declared in the smallest
+ // non-class, non-function-prototype scope that contains the
+ // declaration.
+ //
+ // C99 6.7.2.3p8 has a similar (but not identical!) provision for
+ // C structs and unions.
+ //
+ // It is an error in C++ to declare (rather than define) an enum
+ // type, including via an elaborated type specifier. We'll
+ // diagnose that later; for now, declare the enum in the same
+ // scope as we would have picked for any other tag type.
+ //
+ // GNU C also supports this behavior as part of its incomplete
+ // enum types extension, while GNU C++ does not.
+ //
+ // Find the context where we'll be declaring the tag.
+ // FIXME: We would like to maintain the current DeclContext as the
+ // lexical context,
+ while (SearchDC->isRecord())
+ SearchDC = SearchDC->getParent();
+
+ // Find the scope where we'll be declaring the tag.
+ while (S->isClassScope() ||
+ (getLangOptions().CPlusPlus &&
+ S->isFunctionPrototypeScope()) ||
+ ((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->isTransparentContext()))
+ S = S->getParent();
+ } else {
+ assert(TUK == TUK_Friend);
+ // C++ [namespace.memdef]p3:
+ // If a friend declaration in a non-local class first declares a
+ // class or function, the friend class or function is a member of
+ // the innermost enclosing namespace.
+ SearchDC = SearchDC->getEnclosingNamespaceContext();
+
+ // Look up through our scopes until we find one with an entity which
+ // matches our declaration context.
+ while (S->getEntity() &&
+ ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
+ S = S->getParent();
+ assert(S && "No enclosing scope matching the enclosing namespace.");
+ }
+ }
+
+ // In C++, look for a shadow friend decl.
+ if (getLangOptions().CPlusPlus) {
+ Previous.setRedeclarationKind(ForRedeclaration);
+ LookupQualifiedName(Previous, SearchDC);
+ }
+ }
+
if (!Previous.empty()) {
assert(Previous.isSingleResult());
NamedDecl *PrevDecl = Previous.getFoundDecl();
@@ -4750,8 +4926,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (SafeToContinue)
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(SourceRange(KWLoc),
- PrevTagDecl->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(KWLoc),
+ PrevTagDecl->getKindName());
else
Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
@@ -4829,7 +5005,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else {
// PrevDecl is a namespace, template, or anything else
// that lives in the IDNS_Tag identifier namespace.
- if (isDeclInScope(PrevDecl, SearchDC, S)) {
+ if (TUK == TUK_Reference || TUK == TUK_Friend ||
+ isDeclInScope(PrevDecl, SearchDC, S)) {
// The tag name clashes with a namespace name, issue an error and
// recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
@@ -4843,60 +5020,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Previous.clear();
}
}
- } else if (TUK == TUK_Reference && SS.isEmpty() && Name) {
- // C++ [basic.scope.pdecl]p5:
- // -- for an elaborated-type-specifier of the form
- //
- // class-key identifier
- //
- // if the elaborated-type-specifier is used in the
- // decl-specifier-seq or parameter-declaration-clause of a
- // function defined in namespace scope, the identifier is
- // declared as a class-name in the namespace that contains
- // the declaration; otherwise, except as a friend
- // declaration, the identifier is declared in the smallest
- // non-class, non-function-prototype scope that contains the
- // declaration.
- //
- // C99 6.7.2.3p8 has a similar (but not identical!) provision for
- // C structs and unions.
- //
- // It is an error in C++ to declare (rather than define) an enum
- // type, including via an elaborated type specifier. We'll
- // diagnose that later; for now, declare the enum in the same
- // scope as we would have picked for any other tag type.
- //
- // GNU C also supports this behavior as part of its incomplete
- // enum types extension, while GNU C++ does not.
- //
- // Find the context where we'll be declaring the tag.
- // FIXME: We would like to maintain the current DeclContext as the
- // lexical context,
- while (SearchDC->isRecord())
- SearchDC = SearchDC->getParent();
-
- // Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
- (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) ||
- ((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() &&
- ((DeclContext *)S->getEntity())->isTransparentContext()))
- S = S->getParent();
-
- } else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
- // C++ [namespace.memdef]p3:
- // If a friend declaration in a non-local class first declares a
- // class or function, the friend class or function is a member of
- // the innermost enclosing namespace.
- SearchDC = SearchDC->getEnclosingNamespaceContext();
-
- // Look up through our scopes until we find one with an entity which
- // matches our declaration context.
- while (S->getEntity() &&
- ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) {
- S = S->getParent();
- assert(S && "No enclosing scope matching the enclosing namespace.");
- }
}
CreateNewDecl:
@@ -5013,7 +5136,7 @@ CreateNewDecl:
New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty());
// Set the access specifier.
- if (!Invalid && TUK != TUK_Friend)
+ if (!Invalid && SearchDC->isRecord())
SetMemberAccessSpecifier(New, PrevDecl, AS);
if (TUK == TUK_Definition)
@@ -5026,13 +5149,11 @@ CreateNewDecl:
if (PrevDecl)
New->setAccess(PrevDecl->getAccess());
- // Friend tag decls are visible in fairly strange ways.
- if (!CurContext->isDependentContext()) {
- DeclContext *DC = New->getDeclContext()->getLookupContext();
- DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ DeclContext *DC = New->getDeclContext()->getLookupContext();
+ DC->makeDeclVisibleInContext(New, /* Recoverable = */ false);
+ if (Name) // can be null along some error paths
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false);
- }
} else if (Name) {
S = getNonFieldDeclScope(S);
PushOnScopeChains(New, S);
@@ -5261,6 +5382,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *NewFD
= CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
AS, PrevDecl, &D);
+
+ if (NewFD->isInvalidDecl())
+ Record->setInvalidDecl();
+
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
// with the same name in the same scope.
@@ -5804,7 +5929,7 @@ void Sema::ActOnFields(Scope* S,
} else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension())
- Diag(LBrac, diag::err_misplaced_ivar);
+ Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
else {
// FIXME. Class extension does not have a LocEnd field.
// CDecl->setLocEnd(RBrac);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 73a34f8..cc24735 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -490,6 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
}
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // NOTE: We don't add the attribute to a FunctionDecl because the noreturn
+ // trait will be part of the function's type.
+
// Don't apply as a decl attribute to ValueDecl.
// FIXME: probably ought to diagnose this.
if (isa<ValueDecl>(d))
@@ -521,7 +524,8 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
return;
}
- if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d)) {
+ if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) &&
+ !isa<TypeDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 2 /*variable and function*/;
return;
@@ -834,18 +838,24 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
return;
}
- if (!isFunction(D)) {
+ if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
- if (getFunctionType(D)->getResultType()->isVoidType()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_void_function)
- << Attr.getName();
+ if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
+ << Attr.getName() << 0;
return;
}
-
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (MD->getResultType()->isVoidType()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
+ << Attr.getName() << 1;
+ return;
+ }
+
D->addAttr(::new (S.Context) WarnUnusedResultAttr());
}
@@ -1115,6 +1125,7 @@ enum FormatAttrKind {
NSStringFormat,
StrftimeFormat,
SupportedFormat,
+ IgnoredFormat,
InvalidFormat
};
@@ -1136,6 +1147,10 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
Format == "zcmn_err")
return SupportedFormat;
+ if (Format == "gcc_diag" || Format == "gcc_cdiag" ||
+ Format == "gcc_cxxdiag" || Format == "gcc_tdiag")
+ return IgnoredFormat;
+
return InvalidFormat;
}
@@ -1171,6 +1186,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// Check for supported formats.
FormatAttrKind Kind = getFormatAttrKind(Format);
+
+ if (Kind == IgnoredFormat)
+ return;
+
if (Kind == InvalidFormat) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< "format" << Attr.getParameterName()->getName();
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 13a7ead..47df435 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1104,8 +1104,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << true << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
Diag(Member->getLocation(), diag::note_previous_decl)
<< Member->getDeclName();
@@ -1123,8 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << false << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec
: VirtualBaseSpec;
@@ -1429,134 +1429,106 @@ bool
Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
unsigned NumInitializers,
- bool IsImplicitConstructor,
bool AnyErrors) {
+ if (Constructor->isDependentContext()) {
+ // Just store the initializers as written, they will be checked during
+ // instantiation.
+ if (NumInitializers > 0) {
+ Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+ CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+ new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+ memcpy(baseOrMemberInitializers, Initializers,
+ NumInitializers * sizeof(CXXBaseOrMemberInitializer*));
+ Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+ }
+
+ return false;
+ }
+
// We need to build the initializer AST according to order of construction
// and not what user specified in the Initializers list.
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition();
+ if (!ClassDecl)
+ return true;
+
llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
- bool HasDependentBaseInit = false;
bool HadError = false;
for (unsigned i = 0; i < NumInitializers; i++) {
CXXBaseOrMemberInitializer *Member = Initializers[i];
- if (Member->isBaseInitializer()) {
- if (Member->getBaseClass()->isDependentType())
- HasDependentBaseInit = true;
+
+ if (Member->isBaseInitializer())
AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
- } else {
+ else
AllBaseFields[Member->getMember()] = Member;
- }
}
- if (HasDependentBaseInit) {
- // FIXME. This does not preserve the ordering of the initializers.
- // Try (with -Wreorder)
- // template<class X> struct A {};
- // template<class X> struct B : A<X> {
- // B() : x1(10), A<X>() {}
- // int x1;
- // };
- // B<int> x;
- // On seeing one dependent type, we should essentially exit this routine
- // while preserving user-declared initializer list. When this routine is
- // called during instantiatiation process, this routine will rebuild the
- // ordered initializer list correctly.
-
- // If we have a dependent base initialization, we can't determine the
- // association between initializers and bases; just dump the known
- // initializers into the list, and don't try to deal with other bases.
- for (unsigned i = 0; i < NumInitializers; i++) {
- CXXBaseOrMemberInitializer *Member = Initializers[i];
- if (Member->isBaseInitializer())
- AllToInit.push_back(Member);
- }
- } else {
- llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
-
- // Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase =
- ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- if (VBase->getType()->isDependentType())
- continue;
- if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
- } else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, VBase);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
+ llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit;
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be checked again at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
-
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(VBase->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
- }
- }
+ // Push virtual bases before others.
+ for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
+ E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
- for (CXXRecordDecl::base_class_iterator Base =
- ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Virtuals are in the virtual base list and already constructed.
- if (Base->isVirtual())
- continue;
- // Skip dependent types.
- if (Base->getType()->isDependentType())
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, VBase);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
continue;
- if (CXXBaseOrMemberInitializer *Value
- = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
- AllToInit.push_back(Value);
}
- else if (!AnyErrors) {
- InitializedEntity InitEntity
- = InitializedEntity::InitializeBase(Context, Base);
- InitializationKind InitKind
- = InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
- OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
- MultiExprArg(*this, 0, 0));
- BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
- if (BaseInit.isInvalid()) {
- HadError = true;
- continue;
- }
-
- // Don't attach synthesized base initializers in a dependent
- // context; they'll be regenerated at template instantiation
- // time.
- if (CurContext->isDependentContext())
- continue;
- CXXBaseOrMemberInitializer *CXXBaseInit =
- new (Context) CXXBaseOrMemberInitializer(Context,
- Context.getTrivialTypeSourceInfo(Base->getType(),
- SourceLocation()),
- SourceLocation(),
- BaseInit.takeAs<Expr>(),
- SourceLocation());
- AllToInit.push_back(CXXBaseInit);
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(VBase->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ E = ClassDecl->bases_end(); Base != E; ++Base) {
+ // Virtuals are in the virtual base list and already constructed.
+ if (Base->isVirtual())
+ continue;
+
+ if (CXXBaseOrMemberInitializer *Value
+ = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ AllToInit.push_back(Value);
+ } else if (!AnyErrors) {
+ InitializedEntity InitEntity
+ = InitializedEntity::InitializeBase(Context, Base);
+ InitializationKind InitKind
+ = InitializationKind::CreateDefault(Constructor->getLocation());
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0);
+ OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind,
+ MultiExprArg(*this, 0, 0));
+ BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit));
+ if (BaseInit.isInvalid()) {
+ HadError = true;
+ continue;
}
+
+ CXXBaseOrMemberInitializer *CXXBaseInit =
+ new (Context) CXXBaseOrMemberInitializer(Context,
+ Context.getTrivialTypeSourceInfo(Base->getType(),
+ SourceLocation()),
+ SourceLocation(),
+ BaseInit.takeAs<Expr>(),
+ SourceLocation());
+ AllToInit.push_back(CXXBaseInit);
}
}
@@ -1624,14 +1596,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
}
else if (FT->isReferenceType()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 0 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
}
else if (FT.isConstQualified()) {
Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor)
- << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl)
+ << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl)
<< 1 << (*Field)->getDeclName();
Diag((*Field)->getLocation(), diag::note_declared_at);
HadError = true;
@@ -1665,121 +1637,70 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) {
return static_cast<void *>(Field);
}
-static void *GetKeyForBase(QualType BaseType) {
- if (const RecordType *RT = BaseType->getAs<RecordType>())
- return (void *)RT;
-
- assert(0 && "Unexpected base type!");
- return 0;
+static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
+ return Context.getCanonicalType(BaseType).getTypePtr();
}
-static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member,
+static void *GetKeyForMember(ASTContext &Context,
+ CXXBaseOrMemberInitializer *Member,
bool MemberMaybeAnon = false) {
+ if (!Member->isMemberInitializer())
+ return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
+
// For fields injected into the class via declaration of an anonymous union,
// use its anonymous union class declaration as the unique key.
- if (Member->isMemberInitializer()) {
- FieldDecl *Field = Member->getMember();
-
- // After SetBaseOrMemberInitializers call, Field is the anonymous union
- // data member of the class. Data member used in the initializer list is
- // in AnonUnionMember field.
- if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
- Field = Member->getAnonUnionMember();
- if (Field->getDeclContext()->isRecord()) {
- RecordDecl *RD = cast<RecordDecl>(Field->getDeclContext());
- if (RD->isAnonymousStructOrUnion())
- return static_cast<void *>(RD);
- }
- return static_cast<void *>(Field);
- }
-
- return GetKeyForBase(QualType(Member->getBaseClass(), 0));
-}
-
-/// ActOnMemInitializers - Handle the member initializers for a constructor.
-void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
- SourceLocation ColonLoc,
- MemInitTy **MemInits, unsigned NumMemInits,
- bool AnyErrors) {
- if (!ConstructorDecl)
- return;
+ FieldDecl *Field = Member->getMember();
- AdjustDeclIfTemplate(ConstructorDecl);
-
- CXXConstructorDecl *Constructor
- = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
-
- if (!Constructor) {
- Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
- return;
- }
-
- if (!Constructor->isDependentContext()) {
- llvm::DenseMap<void*, CXXBaseOrMemberInitializer *>Members;
- bool err = false;
- for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *KeyToMember = GetKeyForMember(Member);
- CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
- if (!PrevMember) {
- PrevMember = Member;
- continue;
- }
- if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::error_multiple_mem_initialization)
- << Field->getNameAsString()
- << Member->getSourceRange();
- else {
- Type *BaseClass = Member->getBaseClass();
- assert(BaseClass && "ActOnMemInitializers - neither field or base");
- Diag(Member->getSourceLocation(),
- diag::error_multiple_base_initialization)
- << QualType(BaseClass, 0)
- << Member->getSourceRange();
- }
- Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
- << 0;
- err = true;
- }
-
- if (err)
- return;
- }
+ // After SetBaseOrMemberInitializers call, Field is the anonymous union
+ // data member of the class. Data member used in the initializer list is
+ // in AnonUnionMember field.
+ if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
+ Field = Member->getAnonUnionMember();
+
+ // If the field is a member of an anonymous union, we use record decl of the
+ // union as the key.
+ RecordDecl *RD = Field->getParent();
+ if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+ return static_cast<void *>(RD);
- SetBaseOrMemberInitializers(Constructor,
- reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits),
- NumMemInits, false, AnyErrors);
+ return static_cast<void *>(Field);
+}
+static void
+DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
+ const CXXConstructorDecl *Constructor,
+ CXXBaseOrMemberInitializer **MemInits,
+ unsigned NumMemInits) {
if (Constructor->isDependentContext())
return;
- if (Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) ==
Diagnostic::Ignored &&
- Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
+ SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) ==
Diagnostic::Ignored)
return;
-
+
// Also issue warning if order of ctor-initializer list does not match order
// of 1) base class declarations and 2) order of non-static data members.
llvm::SmallVector<const void*, 32> AllBaseOrMembers;
- CXXRecordDecl *ClassDecl
- = cast<CXXRecordDecl>(Constructor->getDeclContext());
+ const CXXRecordDecl *ClassDecl = Constructor->getParent();
+
// Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase =
+ for (CXXRecordDecl::base_class_const_iterator VBase =
ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType()));
+ AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
+ VBase->getType()));
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
+ for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
// Virtuals are alread in the virtual base list and are constructed
// first.
if (Base->isVirtual())
continue;
- AllBaseOrMembers.push_back(GetKeyForBase(Base->getType()));
+ AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context,
+ Base->getType()));
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -1790,9 +1711,8 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
int curIndex = 0;
CXXBaseOrMemberInitializer *PrevMember = 0;
for (unsigned i = 0; i < NumMemInits; i++) {
- CXXBaseOrMemberInitializer *Member =
- static_cast<CXXBaseOrMemberInitializer*>(MemInits[i]);
- void *MemberInCtorList = GetKeyForMember(Member, true);
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+ void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true);
for (; curIndex < Last; curIndex++)
if (MemberInCtorList == AllBaseOrMembers[curIndex])
@@ -1804,23 +1724,23 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
if (PrevMember->isBaseInitializer()) {
// Diagnostics is for an initialized base class.
Type *BaseClass = PrevMember->getBaseClass();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_base_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_base_initialized)
<< QualType(BaseClass, 0);
} else {
FieldDecl *Field = PrevMember->getMember();
- Diag(PrevMember->getSourceLocation(),
- diag::warn_field_initialized)
+ SemaRef.Diag(PrevMember->getSourceLocation(),
+ diag::warn_field_initialized)
<< Field->getNameAsString();
}
// Also the note!
if (FieldDecl *Field = Member->getMember())
- Diag(Member->getSourceLocation(),
- diag::note_fieldorbase_initialized_here) << 0
+ SemaRef.Diag(Member->getSourceLocation(),
+ diag::note_fieldorbase_initialized_here) << 0
<< Field->getNameAsString();
else {
Type *BaseClass = Member->getBaseClass();
- Diag(Member->getSourceLocation(),
+ SemaRef.Diag(Member->getSourceLocation(),
diag::note_fieldorbase_initialized_here) << 1
<< QualType(BaseClass, 0);
}
@@ -1832,6 +1752,64 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
}
}
+/// ActOnMemInitializers - Handle the member initializers for a constructor.
+void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
+ SourceLocation ColonLoc,
+ MemInitTy **meminits, unsigned NumMemInits,
+ bool AnyErrors) {
+ if (!ConstructorDecl)
+ return;
+
+ AdjustDeclIfTemplate(ConstructorDecl);
+
+ CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>());
+
+ if (!Constructor) {
+ Diag(ColonLoc, diag::err_only_constructors_take_base_inits);
+ return;
+ }
+
+ CXXBaseOrMemberInitializer **MemInits =
+ reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
+
+ llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+ bool HadError = false;
+ for (unsigned i = 0; i < NumMemInits; i++) {
+ CXXBaseOrMemberInitializer *Member = MemInits[i];
+
+ void *KeyToMember = GetKeyForMember(Context, Member);
+ CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
+ if (!PrevMember) {
+ PrevMember = Member;
+ continue;
+ }
+ if (FieldDecl *Field = Member->getMember())
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_mem_initialization)
+ << Field->getNameAsString()
+ << Member->getSourceRange();
+ else {
+ Type *BaseClass = Member->getBaseClass();
+ assert(BaseClass && "ActOnMemInitializers - neither field or base");
+ Diag(Member->getSourceLocation(),
+ diag::error_multiple_base_initialization)
+ << QualType(BaseClass, 0)
+ << Member->getSourceRange();
+ }
+ Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
+ << 0;
+ HadError = true;
+ }
+
+ if (HadError)
+ return;
+
+ DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
+
+ SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
+}
+
void
Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXRecordDecl *ClassDecl) {
@@ -1861,7 +1839,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
CheckDestructorAccess(Field->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_field)
+ PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
<< FieldType);
@@ -1889,7 +1867,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_base)
+ PDiag(diag::err_access_dtor_base)
<< Base->getType()
<< Base->getSourceRange());
@@ -1914,7 +1892,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
- PartialDiagnostic(diag::err_access_dtor_vbase)
+ PDiag(diag::err_access_dtor_vbase)
<< VBase->getType());
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
@@ -1925,94 +1903,11 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) {
if (!CDtorDecl)
return;
- AdjustDeclIfTemplate(CDtorDecl);
-
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>()))
- SetBaseOrMemberInitializers(Constructor, 0, 0, false, false);
-}
-
-namespace {
- /// PureVirtualMethodCollector - traverses a class and its superclasses
- /// and determines if it has any pure virtual methods.
- class PureVirtualMethodCollector {
- ASTContext &Context;
-
- public:
- typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList;
-
- private:
- MethodList Methods;
-
- void Collect(const CXXRecordDecl* RD, MethodList& Methods);
-
- public:
- PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD)
- : Context(Ctx) {
-
- MethodList List;
- Collect(RD, List);
-
- // Copy the temporary list to methods, and make sure to ignore any
- // null entries.
- for (size_t i = 0, e = List.size(); i != e; ++i) {
- if (List[i])
- Methods.push_back(List[i]);
- }
- }
-
- bool empty() const { return Methods.empty(); }
-
- MethodList::const_iterator methods_begin() { return Methods.begin(); }
- MethodList::const_iterator methods_end() { return Methods.end(); }
- };
-
- void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD,
- MethodList& Methods) {
- // First, collect the pure virtual methods for the base classes.
- for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
- BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseDecl && BaseDecl->isAbstract())
- Collect(BaseDecl, Methods);
- }
- }
-
- // Next, zero out any pure virtual methods that this class overrides.
- typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy;
-
- MethodSetTy OverriddenMethods;
- size_t MethodsSize = Methods.size();
-
- for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end();
- i != e; ++i) {
- // Traverse the record, looking for methods.
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) {
- // If the method is pure virtual, add it to the methods vector.
- if (MD->isPure())
- Methods.push_back(MD);
-
- // Record all the overridden methods in our set.
- for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
- E = MD->end_overridden_methods(); I != E; ++I) {
- // Keep track of the overridden methods.
- OverriddenMethods.insert(*I);
- }
- }
- }
-
- // Now go through the methods and zero out all the ones we know are
- // overridden.
- for (size_t i = 0, e = MethodsSize; i != e; ++i) {
- if (OverriddenMethods.count(Methods[i]))
- Methods[i] = 0;
- }
-
- }
+ SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false);
}
-
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
unsigned DiagID, AbstractDiagSelID SelID,
const CXXRecordDecl *CurrentRD) {
@@ -2066,14 +1961,32 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD))
return true;
- PureVirtualMethodCollector Collector(Context, RD);
+ CXXFinalOverriderMap FinalOverriders;
+ RD->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd;
+ ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+
+ //
+ if (SO->second.size() != 1)
+ continue;
- for (PureVirtualMethodCollector::MethodList::const_iterator I =
- Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
+ if (!SO->second.front().Method->isPure())
+ continue;
- Diag(MD->getLocation(), diag::note_pure_virtual_function) <<
- MD->getDeclName();
+ Diag(SO->second.front().Method->getLocation(),
+ diag::note_pure_virtual_function)
+ << SO->second.front().Method->getDeclName();
+ }
}
if (!PureVirtualClassDiagSet)
@@ -2162,22 +2075,79 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I)
Convs->setAccess(I, (*I)->getAccess());
- if (!Record->isAbstract()) {
- // Collect all the pure virtual methods and see if this is an abstract
- // class after all.
- PureVirtualMethodCollector Collector(Context, Record);
- if (!Collector.empty())
- Record->setAbstract(true);
+ // Determine whether we need to check for final overriders. We do
+ // this either when there are virtual base classes (in which case we
+ // may end up finding multiple final overriders for a given virtual
+ // function) or any of the base classes is abstract (in which case
+ // we might detect that this class is abstract).
+ bool CheckFinalOverriders = false;
+ if (Record->isPolymorphic() && !Record->isInvalidDecl() &&
+ !Record->isDependentType()) {
+ if (Record->getNumVBases())
+ CheckFinalOverriders = true;
+ else if (!Record->isAbstract()) {
+ for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(),
+ BEnd = Record->bases_end();
+ B != BEnd; ++B) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+ if (BaseDecl->isAbstract()) {
+ CheckFinalOverriders = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (CheckFinalOverriders) {
+ CXXFinalOverriderMap FinalOverriders;
+ Record->getFinalOverriders(FinalOverriders);
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+ MEnd = FinalOverriders.end();
+ M != MEnd; ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd; ++SO) {
+ assert(SO->second.size() > 0 &&
+ "All virtual functions have overridding virtual functions");
+ if (SO->second.size() == 1) {
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+ if (SO->second.front().Method->isPure())
+ Record->setAbstract(true);
+ continue;
+ }
+
+ // C++ [class.virtual]p2:
+ // In a derived class, if a virtual member function of a base
+ // class subobject has more than one final overrider the
+ // program is ill-formed.
+ Diag(Record->getLocation(), diag::err_multiple_final_overriders)
+ << (NamedDecl *)M->first << Record;
+ Diag(M->first->getLocation(), diag::note_overridden_virtual_function);
+ for (OverridingMethods::overriding_iterator OM = SO->second.begin(),
+ OMEnd = SO->second.end();
+ OM != OMEnd; ++OM)
+ Diag(OM->Method->getLocation(), diag::note_final_overrider)
+ << (NamedDecl *)M->first << OM->Method->getParent();
+
+ Record->setInvalidDecl();
+ }
+ }
}
- if (Record->isAbstract())
+ if (Record->isAbstract() && !Record->isInvalidDecl())
(void)AbstractClassUsageDiagnoser(*this, Record);
}
void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclPtrTy TagDecl,
SourceLocation LBrac,
- SourceLocation RBrac) {
+ SourceLocation RBrac,
+ AttributeList *AttrList) {
if (!TagDecl)
return;
@@ -2185,7 +2155,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
ActOnFields(S, RLoc, TagDecl,
(DeclPtrTy*)FieldCollector->getCurFields(),
- FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+ FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList);
CheckCompletedCXXClass(
dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>()));
@@ -2218,8 +2188,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME*/false, false,
- 0, 0, false,
- CC_Default),
+ 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2293,8 +2263,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
&ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0,
/*isExplicit=*/false,
/*isInline=*/true,
@@ -2382,8 +2352,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
Context.getFunctionType(RetType, &ArgType, 1,
false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default),
+ false, 0, 0,
+ FunctionType::ExtInfo()),
/*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true);
CopyAssignment->setAccess(AS_public);
CopyAssignment->setImplicit();
@@ -2412,8 +2382,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
QualType Ty = Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
/*FIXME:*/false,
- false, 0, 0, false,
- CC_Default);
+ false, 0, 0, FunctionType::ExtInfo());
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
@@ -2586,8 +2555,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -2615,7 +2583,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation();
Diag(ParamLoc, diag::err_constructor_byvalue_arg)
- << CodeModificationHint::CreateInsertion(ParamLoc, " const &");
+ << FixItHint::CreateInsertion(ParamLoc, " const &");
// FIXME: Rather that making the constructor invalid, we should endeavor
// to fix the type.
@@ -2746,7 +2714,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D,
// will put in a result type of "int" when none was specified.
// FIXME: Exceptions!
return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0, FunctionType::ExtInfo());
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -2822,8 +2790,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
Proto->hasAnyExceptionSpec(),
Proto->getNumExceptions(),
Proto->exception_begin(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv());
+ Proto->getExtInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x)
@@ -2962,7 +2929,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
} else {
// Anonymous namespaces.
assert(Namespc->isAnonymousNamespace());
- CurContext->addDecl(Namespc);
// Link the anonymous namespace into its parent.
NamespaceDecl *PrevDecl;
@@ -2984,6 +2950,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
PrevDecl->setNextNamespace(Namespc);
}
+ CurContext->addDecl(Namespc);
+
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
// behaves as if it were replaced by
// namespace unique { /* empty body */ }
@@ -3160,8 +3128,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
UsingLoc = Name.getSourceRange().getBegin();
Diag(UsingLoc, diag::warn_access_decl_deprecated)
- << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
- "using ");
+ << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using ");
}
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
@@ -3330,6 +3297,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
CurContext->addDecl(Shadow);
Shadow->setAccess(UD->getAccess());
+ // Register it as a conversion if appropriate.
+ if (Shadow->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(CurContext)->addConversionFunction(Shadow);
+
if (Orig->isInvalidDecl() || UD->isInvalidDecl())
Shadow->setInvalidDecl();
@@ -3364,6 +3336,10 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
/// decl structures are (very reasonably) not designed for removal.
/// (2) avoids this but is very fiddly and phase-dependent.
void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
+ if (Shadow->getDeclName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName)
+ cast<CXXRecordDecl>(Shadow->getDeclContext())->removeConversion(Shadow);
+
// Remove it from the DeclContext...
Shadow->getDeclContext()->removeDecl(Shadow);
@@ -3377,7 +3353,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
Shadow->getUsingDecl()->removeShadowDecl(Shadow);
// TODO: complain somehow if Shadow was used. It shouldn't
- // be possible for this to happen, because
+ // be possible for this to happen, because...?
}
/// Builds a using declaration.
@@ -3738,8 +3714,10 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S,
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
// We already have an alias with the same name that points to the same
// namespace, so don't create a new one.
+ // FIXME: At some point, we'll want to create the (redundant)
+ // declaration to maintain better source information.
if (!R.isAmbiguous() && !R.empty() &&
- AD->getNamespace() == getNamespaceDecl(R.getFoundDecl()))
+ AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
return DeclPtrTy();
}
@@ -3780,7 +3758,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
DeclContext *PreviousContext = CurContext;
CurContext = Constructor;
- if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) {
+ if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
@@ -3847,7 +3825,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
BaseClassDecl)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_base)
+ PDiag(diag::err_access_assign_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
@@ -3866,7 +3844,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
FieldClassDecl)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldAssignOpMethod,
- PartialDiagnostic(diag::err_access_assign_field)
+ PDiag(diag::err_access_assign_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
@@ -3948,7 +3926,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
BaseCopyCtor,
- PartialDiagnostic(diag::err_access_copy_base)
+ PDiag(diag::err_access_copy_base)
<< Base->getType());
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
@@ -3967,7 +3945,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
CheckDirectMemberAccess(Field->getLocation(),
FieldCopyCtor,
- PartialDiagnostic(diag::err_access_copy_field)
+ PDiag(diag::err_access_copy_field)
<< Field->getDeclName() << Field->getType());
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
@@ -4062,7 +4040,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
- PartialDiagnostic(diag::err_access_dtor_var)
+ PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
}
@@ -4408,16 +4386,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
+ DeclAccessPair Found;
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
- ICS != 0);
+ ICS != 0, Found);
if (Fn) {
// Since we're performing this reference-initialization for
// real, update the initializer with the resulting function.
if (!ICS) {
if (DiagnoseUseOfDecl(Fn, DeclLoc))
- return true;
+ return true;
- Init = FixOverloadedFunctionReference(Init, Fn);
+ CheckAddressOfMemberAccess(Init, Found);
+ Init = FixOverloadedFunctionReference(Init, Found, Fn);
}
T2 = Fn->getType();
@@ -5378,7 +5358,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend templates because ActOnTag never produces a ClassTemplateDecl
// for a TUK_Friend.
Declarator TheDeclarator(DS, Declarator::MemberContext);
- QualType T = GetTypeForDeclarator(TheDeclarator, S);
+ TypeSourceInfo *TSI;
+ QualType T = GetTypeForDeclarator(TheDeclarator, S, &TSI);
if (TheDeclarator.isInvalidType())
return DeclPtrTy();
@@ -5396,7 +5377,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
//
// FIXME: handle "template <> friend class A<T>;", which
// is possibly well-formed? Who even knows?
- if (TempParams.size() && !isa<ElaboratedType>(T)) {
+ if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
return DeclPtrTy();
@@ -5408,7 +5389,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// * The class-key of the elaborated-type-specifier is required.
// This is one of the rare places in Clang where it's legitimate to
// ask about the "spelling" of the type.
- if (!getLangOptions().CPlusPlus0x && !isa<ElaboratedType>(T)) {
+ if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
@@ -5420,8 +5401,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
<< (unsigned) RD->getTagKind()
<< T
<< SourceRange(DS.getFriendSpecLoc())
- << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
- InsertionText);
+ << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText);
return DeclPtrTy();
}else {
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
@@ -5443,16 +5423,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// deadline. It's also a very silly restriction that seriously
// affects inner classes and which nobody else seems to implement;
// thus we never diagnose it, not even in -pedantic.
+ //
+ // But note that we could warn about it: it's always useless to
+ // friend one of your own members (it's not, however, worthless to
+ // friend a member of an arbitrary specialization of your template).
Decl *D;
if (TempParams.size())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
TempParams.size(),
(TemplateParameterList**) TempParams.release(),
- T.getTypePtr(),
+ TSI,
DS.getFriendSpecLoc());
else
- D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(),
+ D = FriendDecl::Create(Context, CurContext, Loc, TSI,
DS.getFriendSpecLoc());
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -5889,7 +5873,7 @@ static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) {
break;
case TSK_ExplicitInstantiationDeclaration:
- return true; //FIXME: This looks wrong.
+ return false;
case TSK_ExplicitInstantiationDefinition:
// This is method of a explicit instantiation; mark all of the virtual
@@ -5945,7 +5929,8 @@ bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() {
return true;
}
-void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
+void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
+ const CXXRecordDecl *RD) {
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end(); i != e; ++i) {
CXXMethodDecl *MD = *i;
@@ -5955,4 +5940,19 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) {
if (MD->isVirtual() && !MD->isPure())
MarkDeclarationReferenced(Loc, MD);
}
+
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual())
+ continue;
+ if (Base->getNumVBases() == 0)
+ continue;
+ MarkVirtualMembersReferenced(Loc, Base);
+ }
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index b2f6717..9bc0846 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -559,8 +559,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
<< ClassName << R.getLookupName();
Diag(IDecl->getLocation(), diag::note_previous_decl)
<< R.getLookupName()
- << CodeModificationHint::CreateReplacement(ClassLoc,
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(ClassLoc,
+ R.getLookupName().getAsString());
IDecl = 0;
} else {
Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
@@ -667,8 +667,6 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- if (ImplIvar->getAccessControl() != ObjCIvarDecl::Private)
- Diag(ImplIvar->getLocation(), diag::err_non_private_ivar_declaration);
// Instance ivar to Implementation's DeclContext.
ImplIvar->setLexicalDeclContext(ImpDecl);
IDecl->makeDeclVisibleInContext(ImplIvar, false);
@@ -721,12 +719,13 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
- bool &IncompleteImpl) {
+ bool &IncompleteImpl, unsigned DiagID) {
if (!IncompleteImpl) {
Diag(ImpLoc, diag::warn_incomplete_impl);
IncompleteImpl = true;
}
- Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName();
+ Diag(method->getLocation(), DiagID)
+ << method->getDeclName();
}
void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
@@ -770,7 +769,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
bool& IncompleteImpl,
const llvm::DenseSet<Selector> &InsMap,
const llvm::DenseSet<Selector> &ClsMap,
- ObjCInterfaceDecl *IDecl) {
+ ObjCContainerDecl *CDecl) {
+ ObjCInterfaceDecl *IDecl;
+ if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl))
+ IDecl = C->getClassInterface();
+ else
+ IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+ assert (IDecl && "CheckProtocolMethodDefs - IDecl is null");
+
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
ObjCInterfaceDecl *NSIDecl = 0;
if (getLangOptions().NeXTRuntime) {
@@ -808,8 +814,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// uses the protocol.
ObjCMethodDecl *MethodInClass =
IDecl->lookupInstanceMethod(method->getSelector());
- if (!MethodInClass || !MethodInClass->isSynthesized())
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ if (!MethodInClass || !MethodInClass->isSynthesized()) {
+ unsigned DIAG = diag::warn_unimplemented_protocol_method;
+ if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
+ Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
+ << PDecl->getDeclName();
+ }
+ }
}
}
// check unimplemented class methods
@@ -819,8 +831,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
ObjCMethodDecl *method = *I;
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!ClsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupClassMethod(method->getSelector())))
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ (!Super || !Super->lookupClassMethod(method->getSelector()))) {
+ unsigned DIAG = diag::warn_unimplemented_protocol_method;
+ if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
+ Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
+ PDecl->getDeclName();
+ }
+ }
}
// Check on this protocols's referenced protocols, recursively.
for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
@@ -849,7 +867,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
if (!(*I)->isSynthesized() &&
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ diag::note_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -873,7 +892,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
ClsMapSeen.insert((*I)->getSelector());
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ diag::note_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
@@ -950,7 +970,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, C->getClassInterface());
+ InsMap, ClsMap, CDecl);
// Report unimplemented properties in the category as well.
// When reporting on missing setter/getters, do not report when
// setter/getter is implemented in category's primary class
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 4ce1ce9..53e9385 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -15,6 +15,8 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -94,19 +96,21 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
}
bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+ bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
- if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
- diag::note_previous_declaration,
+ if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec),
+ PDiag(diag::note_previous_declaration),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
New->getLocation(),
+ &MissingExceptionSpecification,
&MissingEmptyExceptionSpecification))
return false;
// The failure was something other than an empty exception
// specification; return an error.
- if (!MissingEmptyExceptionSpecification)
+ if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification)
return true;
// The new function declaration is only missing an empty exception
@@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// to many libc functions as an optimization. Unfortunately, that
// optimization isn't permitted by the C++ standard, so we're forced
// to work around it here.
- if (isa<FunctionProtoType>(New->getType()) &&
- Context.getSourceManager().isInSystemHeader(Old->getLocation()) &&
+ if (MissingEmptyExceptionSpecification &&
+ isa<FunctionProtoType>(New->getType()) &&
+ (Old->getLocation().isInvalid() ||
+ Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
Old->isExternC()) {
const FunctionProtoType *NewProto
= cast<FunctionProtoType>(New->getType());
@@ -128,12 +134,91 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
NewProto->isVariadic(),
NewProto->getTypeQuals(),
true, false, 0, 0,
- NewProto->getNoReturnAttr(),
- NewProto->getCallConv());
+ NewProto->getExtInfo());
New->setType(NewType);
return false;
}
+ if (MissingExceptionSpecification && isa<FunctionProtoType>(New->getType())) {
+ const FunctionProtoType *NewProto
+ = cast<FunctionProtoType>(New->getType());
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAs<FunctionProtoType>();
+
+ // Update the type of the function with the appropriate exception
+ // specification.
+ QualType NewType = Context.getFunctionType(NewProto->getResultType(),
+ NewProto->arg_type_begin(),
+ NewProto->getNumArgs(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals(),
+ OldProto->hasExceptionSpec(),
+ OldProto->hasAnyExceptionSpec(),
+ OldProto->getNumExceptions(),
+ OldProto->exception_begin(),
+ NewProto->getExtInfo());
+ New->setType(NewType);
+
+ // If exceptions are disabled, suppress the warning about missing
+ // exception specifications for new and delete operators.
+ if (!getLangOptions().Exceptions) {
+ switch (New->getDeclName().getCXXOverloadedOperator()) {
+ case OO_New:
+ case OO_Array_New:
+ case OO_Delete:
+ case OO_Array_Delete:
+ if (New->getDeclContext()->isTranslationUnit())
+ return false;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Warn about the lack of exception specification.
+ llvm::SmallString<128> ExceptionSpecString;
+ llvm::raw_svector_ostream OS(ExceptionSpecString);
+ OS << "throw(";
+ bool OnFirstException = true;
+ for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
+ EEnd = OldProto->exception_end();
+ E != EEnd;
+ ++E) {
+ if (OnFirstException)
+ OnFirstException = false;
+ else
+ OS << ", ";
+
+ OS << E->getAsString(Context.PrintingPolicy);
+ }
+ OS << ")";
+ OS.flush();
+
+ SourceLocation AfterParenLoc;
+ if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
+ TypeLoc TL = TSInfo->getTypeLoc();
+ if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
+ AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc());
+ }
+
+ if (AfterParenLoc.isInvalid())
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str();
+ else {
+ // FIXME: This will get more complicated with C++0x
+ // late-specified return types.
+ Diag(New->getLocation(), diag::warn_missing_exception_specification)
+ << New << OS.str()
+ << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str());
+ }
+
+ if (!Old->getLocation().isInvalid())
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+
+ return false;
+ }
+
Diag(New->getLocation(), diag::err_mismatched_exception_spec);
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
@@ -146,8 +231,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
- return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
- diag::note_previous_declaration,
+ return CheckEquivalentExceptionSpec(
+ PDiag(diag::err_mismatched_exception_spec),
+ PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
}
@@ -155,11 +241,17 @@ bool Sema::CheckEquivalentExceptionSpec(
/// exception specifications. Exception specifications are equivalent if
/// they allow exactly the same set of exception types. It does not matter how
/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(
- const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
- const FunctionProtoType *Old, SourceLocation OldLoc,
- const FunctionProtoType *New, SourceLocation NewLoc,
- bool *MissingEmptyExceptionSpecification) {
+bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+ const PartialDiagnostic & NoteID,
+ const FunctionProtoType *Old,
+ SourceLocation OldLoc,
+ const FunctionProtoType *New,
+ SourceLocation NewLoc,
+ bool *MissingExceptionSpecification,
+ bool *MissingEmptyExceptionSpecification) {
+ if (MissingExceptionSpecification)
+ *MissingExceptionSpecification = false;
+
if (MissingEmptyExceptionSpecification)
*MissingEmptyExceptionSpecification = false;
@@ -168,13 +260,20 @@ bool Sema::CheckEquivalentExceptionSpec(
if (OldAny && NewAny)
return false;
if (OldAny || NewAny) {
- if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() &&
- !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 &&
+ if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
!New->hasExceptionSpec()) {
- // The old type has a throw() exception specification and the
- // new type has no exception specification, and the caller asked
- // to handle this itself.
- *MissingEmptyExceptionSpecification = true;
+ // The old type has an exception specification of some sort, but
+ // the new type does not.
+ *MissingExceptionSpecification = true;
+
+ if (MissingEmptyExceptionSpecification &&
+ !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) {
+ // The old type has a throw() exception specification and the
+ // new type has no exception specification, and the caller asked
+ // to handle this itself.
+ *MissingEmptyExceptionSpecification = true;
+ }
+
return true;
}
@@ -350,7 +449,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
const FunctionProtoType *Source, SourceLocation SourceLoc)
{
if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
+ PDiag(diag::err_deep_exception_specs_differ) << 0,
+ PDiag(),
Target->getResultType(), TargetLoc,
Source->getResultType(), SourceLoc))
return true;
@@ -361,7 +461,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
"Functions have different argument counts.");
for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
+ PDiag(diag::err_deep_exception_specs_differ) << 1,
+ PDiag(),
Target->getArgType(i), TargetLoc,
Source->getArgType(i), SourceLoc))
return true;
@@ -386,15 +487,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
// This means that the source of the conversion can only throw a subset of
// the exceptions of the target, and any exception specs on arguments or
// return types must be equivalent.
- return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
- 0, ToFunc, From->getSourceRange().getBegin(),
+ return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
+ PDiag(), ToFunc,
+ From->getSourceRange().getBegin(),
FromFunc, SourceLocation());
}
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- return CheckExceptionSpecSubset(diag::err_override_exception_spec,
- diag::note_overridden_virtual_function,
+ return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec),
+ PDiag(diag::note_overridden_virtual_function),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index fe6f3b9..fbdf080 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -635,7 +635,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
MemberType = Context.getQualifiedType(MemberType, NewQuals);
MarkDeclarationReferenced(Loc, *FI);
- PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI);
+ PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI);
// FIXME: Might this end up being a qualified name?
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
@@ -949,8 +949,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
// Actually quite difficult!
if (isInstance)
Diag(R.getNameLoc(), diagnostic) << Name
- << CodeModificationHint::CreateInsertion(R.getNameLoc(),
- "this->");
+ << FixItHint::CreateInsertion(R.getNameLoc(), "this->");
else
Diag(R.getNameLoc(), diagnostic) << Name;
@@ -969,14 +968,14 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS,
if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
if (SS.isEmpty())
Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
else
Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << computeDeclContext(SS, false) << R.getLookupName()
<< SS.getRange()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
@@ -1355,10 +1354,27 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
return Owned((Expr*) 0);
}
-/// \brief Cast member's object to its own class if necessary.
+/// \brief Cast a base object to a member's actual type.
+///
+/// Logically this happens in three phases:
+///
+/// * First we cast from the base type to the naming class.
+/// The naming class is the class into which we were looking
+/// when we found the member; it's the qualifier type if a
+/// qualifier was provided, and otherwise it's the base type.
+///
+/// * Next we cast from the naming class to the declaring class.
+/// If the member we found was brought into a class's scope by
+/// a using declaration, this is that class; otherwise it's
+/// the class declaring the member.
+///
+/// * Finally we cast from the declaring class to the "true"
+/// declaring class of the member. This conversion does not
+/// obey access control.
bool
Sema::PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
NamedDecl *Member) {
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
if (!RD)
@@ -1406,6 +1422,9 @@ Sema::PerformObjectMemberConversion(Expr *&From,
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
return false;
+ SourceRange FromRange = From->getSourceRange();
+ SourceLocation FromLoc = FromRange.getBegin();
+
// C++ [class.member.lookup]p8:
// [...] Ambiguities can often be resolved by qualifying a name with its
// class name.
@@ -1424,51 +1443,87 @@ Sema::PerformObjectMemberConversion(Expr *&From,
// x = 17; // error: ambiguous base subobjects
// Derived1::x = 17; // okay, pick the Base subobject of Derived1
// }
- QualType IntermediateRecordType;
- QualType IntermediateType;
if (Qualifier) {
- if (const RecordType *IntermediateRecord
- = Qualifier->getAsType()->getAs<RecordType>()) {
- IntermediateRecordType = QualType(IntermediateRecord, 0);
- IntermediateType = IntermediateRecordType;
+ QualType QType = QualType(Qualifier->getAsType(), 0);
+ assert(!QType.isNull() && "lookup done with dependent qualifier?");
+ assert(QType->isRecordType() && "lookup done with non-record type");
+
+ QualType QRecordType = QualType(QType->getAs<RecordType>(), 0);
+
+ // In C++98, the qualifier type doesn't actually have to be a base
+ // type of the object type, in which case we just ignore it.
+ // Otherwise build the appropriate casts.
+ if (IsDerivedFrom(FromRecordType, QRecordType)) {
+ if (CheckDerivedToBaseConversion(FromRecordType, QRecordType,
+ FromLoc, FromRange))
+ return true;
+
if (PointerConversions)
- IntermediateType = Context.getPointerType(IntermediateType);
+ QType = Context.getPointerType(QType);
+ ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue*/ !PointerConversions);
+
+ FromType = QType;
+ FromRecordType = QRecordType;
+
+ // If the qualifier type was the same as the destination type,
+ // we're done.
+ if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
+ return false;
}
}
- if (!IntermediateType.isNull() &&
- IsDerivedFrom(FromRecordType, IntermediateRecordType) &&
- IsDerivedFrom(IntermediateRecordType, DestRecordType)) {
- if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()) ||
- CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()))
- return true;
+ bool IgnoreAccess = false;
- ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/!PointerConversions);
- ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/!PointerConversions);
- return false;
+ // If we actually found the member through a using declaration, cast
+ // down to the using declaration's type.
+ //
+ // Pointer equality is fine here because only one declaration of a
+ // class ever has member declarations.
+ if (FoundDecl->getDeclContext() != Member->getDeclContext()) {
+ assert(isa<UsingShadowDecl>(FoundDecl));
+ QualType URecordType = Context.getTypeDeclType(
+ cast<CXXRecordDecl>(FoundDecl->getDeclContext()));
+
+ // We only need to do this if the naming-class to declaring-class
+ // conversion is non-trivial.
+ if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) {
+ assert(IsDerivedFrom(FromRecordType, URecordType));
+ if (CheckDerivedToBaseConversion(FromRecordType, URecordType,
+ FromLoc, FromRange))
+ return true;
+
+ QualType UType = URecordType;
+ if (PointerConversions)
+ UType = Context.getPointerType(UType);
+ ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue*/ !PointerConversions);
+ FromType = UType;
+ FromRecordType = URecordType;
+ }
+
+ // We don't do access control for the conversion from the
+ // declaring class to the true declaring class.
+ IgnoreAccess = true;
}
if (CheckDerivedToBaseConversion(FromRecordType,
DestRecordType,
- From->getSourceRange().getBegin(),
- From->getSourceRange()))
+ FromLoc,
+ FromRange,
+ IgnoreAccess))
return true;
- ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
- /*isLvalue=*/true);
+ ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase,
+ /*isLvalue=*/ !PointerConversions);
return false;
}
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
const CXXScopeSpec &SS, ValueDecl *Member,
- SourceLocation Loc, QualType Ty,
+ NamedDecl *FoundDecl, SourceLocation Loc,
+ QualType Ty,
const TemplateArgumentListInfo *TemplateArgs = 0) {
NestedNameSpecifier *Qualifier = 0;
SourceRange QualifierRange;
@@ -1478,7 +1533,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
}
return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange,
- Member, Loc, TemplateArgs, Ty);
+ Member, FoundDecl, Loc, TemplateArgs, Ty);
}
/// Builds an implicit member access expression. The current context
@@ -2520,7 +2575,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceLocation OpLoc, const CXXScopeSpec &SS) {
RecordDecl *RDecl = RTy->getDecl();
if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
- PDiag(diag::err_typecheck_incomplete_tag)
+ SemaRef.PDiag(diag::err_typecheck_incomplete_tag)
<< BaseRange))
return true;
@@ -2558,8 +2613,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
(isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
<< Name << DC << R.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ R.getLookupName().getAsString());
if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
<< ND->getDeclName();
@@ -2692,6 +2747,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
assert(R.isSingleResult());
+ NamedDecl *FoundDecl = *R.begin();
NamedDecl *MemberDecl = R.getFoundDecl();
// FIXME: diagnose the presence of template arguments now.
@@ -2754,30 +2810,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
}
MarkDeclarationReferenced(MemberLoc, FD);
- if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD))
+ if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD))
return ExprError();
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- FD, MemberLoc, MemberType));
+ FD, FoundDecl, MemberLoc, MemberType));
}
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, Var);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Var, MemberLoc,
+ Var, FoundDecl, MemberLoc,
Var->getType().getNonReferenceType()));
}
if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- MemberFn, MemberLoc,
+ MemberFn, FoundDecl, MemberLoc,
MemberFn->getType()));
}
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
- Enum, MemberLoc, Enum->getType()));
+ Enum, FoundDecl, MemberLoc, Enum->getType()));
}
Owned(BaseExpr);
@@ -2836,7 +2892,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::err_member_reference_needs_call)
<< QualType(Fun, 0)
- << CodeModificationHint::CreateInsertion(Loc, "()");
+ << FixItHint::CreateInsertion(Loc, "()");
OwningExprResult NewBase
= ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc,
@@ -2955,7 +3011,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
// by now.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
IsArrow = false;
} else {
Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
@@ -2975,7 +3031,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (PT && PT->getPointeeType()->isRecordType()) {
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << CodeModificationHint::CreateReplacement(OpLoc, "->");
+ << FixItHint::CreateReplacement(OpLoc, "->");
BaseType = PT->getPointeeType();
IsArrow = true;
}
@@ -3014,8 +3070,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- IV->getNameAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ IV->getNameAsString());
Diag(IV->getLocation(), diag::note_previous_decl)
<< IV->getDeclName();
}
@@ -3189,8 +3245,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
Res.getAsSingle<ObjCPropertyDecl>()) {
Diag(R.getNameLoc(), diag::err_property_not_found_suggest)
<< MemberName << BaseType << Res.getLookupName()
- << CodeModificationHint::CreateReplacement(R.getNameLoc(),
- Res.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(R.getNameLoc(),
+ Res.getLookupName().getAsString());
ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
Diag(Property->getLocation(), diag::note_previous_decl)
<< Property->getDeclName();
@@ -3519,7 +3575,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (NumArgs > 0) {
// Pseudo-destructor calls should not have any arguments.
Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
- << CodeModificationHint::CreateRemoval(
+ << FixItHint::CreateRemoval(
SourceRange(Args[0]->getLocStart(),
Args[NumArgs-1]->getLocEnd()));
@@ -4594,13 +4650,15 @@ Sema::AssignConvertType
Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
if (lhsType->isObjCBuiltinType()) {
// Class is not compatible with ObjC object pointers.
- if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType())
+ if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() &&
+ !rhsType->isObjCQualifiedClassType())
return IncompatiblePointer;
return Compatible;
}
if (rhsType->isObjCBuiltinType()) {
// Class is not compatible with ObjC object pointers.
- if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType())
+ if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() &&
+ !lhsType->isObjCQualifiedClassType())
return IncompatiblePointer;
return Compatible;
}
@@ -5367,12 +5425,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation 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));
+ << FixItHint::CreateReplacement(SourceRange(Loc), ", ")
+ << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(")
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()),
+ resultComparison));
}
}
@@ -5783,7 +5839,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
case Expr::MLV_IncompleteType:
case Expr::MLV_IncompleteVoidType:
return S.RequireCompleteType(Loc, E->getType(),
- PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
+ S.PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue)
<< E->getSourceRange());
case Expr::MLV_DuplicateVectorComponents:
Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue;
@@ -6345,8 +6401,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
static void SuggestParentheses(Sema &Self, SourceLocation Loc,
const PartialDiagnostic &PD,
SourceRange ParenRange,
- const PartialDiagnostic &SecondPD = PartialDiagnostic(0),
- SourceRange SecondParenRange = SourceRange()) {
+ const PartialDiagnostic &SecondPD,
+ SourceRange SecondParenRange) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd());
if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
// We can't display the parentheses, so just dig the
@@ -6356,8 +6412,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
}
Self.Diag(Loc, PD)
- << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(")
- << CodeModificationHint::CreateInsertion(EndLoc, ")");
+ << FixItHint::CreateInsertion(ParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
if (!SecondPD.getDiagID())
return;
@@ -6371,8 +6427,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
}
Self.Diag(Loc, SecondPD)
- << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << CodeModificationHint::CreateInsertion(EndLoc, ")");
+ << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -6401,20 +6457,20 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc,
if (BinOp::isComparisonOp(lhsopc))
SuggestParentheses(Self, OpLoc,
- PDiag(diag::warn_precedence_bitwise_rel)
+ Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(lhs->getLocStart(), OpLoc)
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc),
lhs->getSourceRange(),
- PDiag(diag::note_precedence_bitwise_first)
+ Self.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)
+ Self.PDiag(diag::warn_precedence_bitwise_rel)
<< SourceRange(OpLoc, rhs->getLocEnd())
<< BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc),
rhs->getSourceRange(),
- PDiag(diag::note_precedence_bitwise_first)
+ Self.PDiag(diag::note_precedence_bitwise_first)
<< BinOp::getOpcodeStr(Opc),
SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()));
}
@@ -6750,7 +6806,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
Res = BuildAnonymousStructUnionMemberReference(
OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
} else {
- PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl);
+ PerformObjectMemberConversion(Res, /*Qualifier=*/0,
+ *R.begin(), MemberDecl);
// MemberDecl->getType() doesn't get the right qualifiers, but it
// doesn't matter here.
Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
@@ -6849,8 +6906,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// The parameter list is optional, if there was none, assume ().
if (!T->isFunctionType())
- T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false,
- CC_Default);
+ T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
CurBlock->hasPrototype = true;
CurBlock->isVariadic = false;
@@ -6905,13 +6962,21 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->Params.size());
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
+
+ bool ShouldCheckShadow =
+ Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
+
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
(*AI)->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
- if ((*AI)->getIdentifier())
+ if ((*AI)->getIdentifier()) {
+ if (ShouldCheckShadow)
+ CheckShadow(CurBlock->TheScope, *AI);
+
PushOnScopeChains(*AI, CurBlock->TheScope);
+ }
}
// Check for a valid sentinel attribute on this block.
@@ -6967,11 +7032,11 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
QualType BlockTy;
if (!BSI->hasPrototype)
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
- NoReturn, CC_Default);
+ FunctionType::ExtInfo(NoReturn, 0, CC_Default));
else
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
BSI->isVariadic, 0, false, false, 0, 0,
- NoReturn, CC_Default);
+ FunctionType::ExtInfo(NoReturn, 0, CC_Default));
// FIXME: Check that return/parameter types are complete/non-abstract
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
@@ -7004,8 +7069,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
}
// Issue any analysis-based warnings.
- sema::AnalysisBasedWarnings W(*this);
- W.IssueWarnings(BSI->TheDecl, BlockTy);
+ const sema::AnalysisBasedWarnings::Policy &WP =
+ AnalysisWarnings.getDefaultPolicy();
+ AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy);
Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs);
@@ -7066,11 +7132,8 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
}
-static void
-MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
- QualType DstType,
- Expr *SrcExpr,
- CodeModificationHint &Hint) {
+static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
+ Expr *SrcExpr, FixItHint &Hint) {
if (!SemaRef.getLangOptions().ObjC1)
return;
@@ -7091,7 +7154,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef,
if (!SL || SL->isWide())
return;
- Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@");
+ Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@");
}
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
@@ -7101,7 +7164,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
// Decode the result (notice that AST's are still created for extensions).
bool isInvalid = false;
unsigned DiagKind;
- CodeModificationHint Hint;
+ FixItHint Hint;
switch (ConvTy) {
default: assert(0 && "Unknown conversion type");
@@ -7113,7 +7176,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
DiagKind = diag::ext_typecheck_convert_int_pointer;
break;
case IncompatiblePointer:
- MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint);
+ MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
break;
case IncompatiblePointerSign:
@@ -7480,10 +7543,10 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) {
Diag(Loc, diagnostic)
<< E->getSourceRange()
- << CodeModificationHint::CreateInsertion(Open, "(")
- << CodeModificationHint::CreateInsertion(Close, ")");
+ << FixItHint::CreateInsertion(Open, "(")
+ << FixItHint::CreateInsertion(Close, ")");
Diag(Loc, diag::note_condition_assign_to_comparison)
- << CodeModificationHint::CreateReplacement(Loc, "==");
+ << FixItHint::CreateReplacement(Loc, "==");
}
bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 366089f..501c877 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -948,7 +948,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
= Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
ArgTypes.size(),
Proto->isVariadic(),
- 0, false, false, 0, 0, false, CC_Default);
+ 0, false, false, 0, 0,
+ FunctionType::ExtInfo());
}
for (LookupResult::iterator D = FoundDelete.begin(),
@@ -1062,10 +1063,15 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
- if (PerformCopyInitialization(Args[i],
- FnDecl->getParamDecl(i)->getType(),
- AA_Passing))
+ OwningExprResult Result
+ = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ FnDecl->getParamDecl(i)),
+ SourceLocation(),
+ Owned(Args[i]->Retain()));
+ if (Result.isInvalid())
return true;
+
+ Args[i] = Result.takeAs<Expr>();
}
Operator = FnDecl;
CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl);
@@ -1204,7 +1210,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0,
true, false,
HasBadAllocExceptionSpec? 1 : 0,
- &BadAllocType, false, CC_Default);
+ &BadAllocType,
+ FunctionType::ExtInfo());
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name,
FnType, /*TInfo=*/0, FunctionDecl::None, false, true);
@@ -1295,17 +1302,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
QualType Type = Ex->getType();
if (const RecordType *Record = Type->getAs<RecordType>()) {
- llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
+ llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
+
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
-
+ const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
// Skip over templated conversion functions; they aren't considered.
- if (isa<FunctionTemplateDecl>(*I))
+ if (isa<FunctionTemplateDecl>(D))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -1315,9 +1326,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (ObjectPtrConversions.size() == 1) {
// We have a single conversion to a pointer-to-object type. Perform
// that conversion.
+ // TODO: don't redo the conversion calculation.
Operand.release();
- if (!PerformImplicitConversion(Ex,
- ObjectPtrConversions.front()->getConversionType(),
+ if (!PerformImplicitConversion(Ex,
+ ObjectPtrConversions.front()->getConversionType(),
AA_Converting)) {
Operand = Owned(Ex);
Type = Ex->getType();
@@ -1326,10 +1338,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
else if (ObjectPtrConversions.size() > 1) {
Diag(StartLoc, diag::err_ambiguous_delete_operand)
<< Type << Ex->getSourceRange();
- for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) {
- CXXConversionDecl *Conv = ObjectPtrConversions[i];
- NoteOverloadCandidate(Conv);
- }
+ for (unsigned i= 0; i < ObjectPtrConversions.size(); i++)
+ NoteOverloadCandidate(ObjectPtrConversions[i]);
return ExprError();
}
}
@@ -1643,14 +1653,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
case ICK_Function_To_Pointer:
if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
+ DeclAccessPair Found;
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
+ true, Found);
if (!Fn)
return true;
if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
return true;
- From = FixOverloadedFunctionReference(From, Fn);
+ From = FixOverloadedFunctionReference(From, Found, Fn);
FromType = From->getType();
// If there's already an address-of operator in the expression, we have
@@ -1846,7 +1858,7 @@ QualType Sema::CheckPointerToMemberOperands(
else {
Diag(Loc, diag::err_bad_memptr_lhs)
<< OpSpelling << 1 << LType
- << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*");
+ << FixItHint::CreateReplacement(SourceRange(Loc), ".*");
return QualType();
}
}
@@ -1891,58 +1903,44 @@ QualType Sema::CheckPointerToMemberOperands(
return Result;
}
-/// \brief Get the target type of a standard or user-defined conversion.
-static QualType TargetType(const ImplicitConversionSequence &ICS) {
- switch (ICS.getKind()) {
- case ImplicitConversionSequence::StandardConversion:
- return ICS.Standard.getToType(2);
- case ImplicitConversionSequence::UserDefinedConversion:
- return ICS.UserDefined.After.getToType(2);
- 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.
///
/// This is part of the parameter validation for the ? operator. If either
/// value operand is a class type, the two operands are attempted to be
/// converted to each other. This function does the conversion in one direction.
-/// It emits a diagnostic and returns true only if it finds an ambiguous
-/// conversion.
+/// It returns true if the program is ill-formed and has already been diagnosed
+/// as such.
static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
SourceLocation QuestionLoc,
- ImplicitConversionSequence &ICS) {
+ bool &HaveConversion,
+ QualType &ToType) {
+ HaveConversion = false;
+ ToType = To->getType();
+
+ InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(),
+ SourceLocation());
// C++0x 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
// as follows:
// -- If E2 is an lvalue:
- if (To->isLvalue(Self.Context) == Expr::LV_Valid) {
+ bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid);
+ if (ToIsLvalue) {
// E1 can be converted to match E2 if E1 can be implicitly converted to
// type "lvalue reference to T2", subject to the constraint that in the
// conversion the reference must bind directly to E1.
- if (!Self.CheckReferenceInit(From,
- Self.Context.getLValueReferenceType(To->getType()),
- To->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- &ICS))
- {
- assert((ICS.isStandard() || ICS.isUserDefined()) &&
- "expected a definite conversion");
- bool DirectBinding =
- ICS.isStandard() ? ICS.Standard.DirectBinding
- : ICS.UserDefined.After.DirectBinding;
- if (DirectBinding)
- return false;
+ QualType T = Self.Context.getLValueReferenceType(ToType);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.isDirectReferenceBinding()) {
+ ToType = T;
+ HaveConversion = true;
+ return false;
}
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
}
// -- If E2 is an rvalue, or if the conversion above cannot be done:
@@ -1952,47 +1950,47 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
QualType TTy = To->getType();
const RecordType *FRec = FTy->getAs<RecordType>();
const RecordType *TRec = TTy->getAs<RecordType>();
- bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy);
- if (FRec && TRec && (FRec == TRec ||
- FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
+ bool FDerivedFromT = FRec && TRec && FRec != TRec &&
+ Self.IsDerivedFrom(FTy, TTy);
+ if (FRec && TRec &&
+ (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) {
// E1 can be converted to match E2 if the class of T2 is the
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
if (FRec == TRec || FDerivedFromT) {
if (TTy.isAtLeastAsQualifiedAs(FTy)) {
- // Could still fail if there's no copy constructor.
- // FIXME: Is this a hard error then, or just a conversion failure? The
- // standard doesn't say.
- ICS = Self.TryCopyInitialization(From, TTy,
- /*SuppressUserConversions=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
- } else {
- ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy);
- }
- } else {
- // Can't implicitly convert FTy to a derived class TTy.
- // TODO: more specific error for this.
- ICS.setBad(BadConversionSequence::no_conversion, From, TTy);
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ if (InitSeq.getKind() != InitializationSequence::FailedSequence) {
+ HaveConversion = true;
+ return false;
+ }
+
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+ }
}
- } else {
- // -- Otherwise: E1 can be converted to match E2 if E1 can be
- // implicitly converted to the type that expression E2 would have
- // if E2 were converted to an rvalue.
- // First find the decayed type.
- if (TTy->isFunctionType())
- TTy = Self.Context.getPointerType(TTy);
- else if (TTy->isArrayType())
- TTy = Self.Context.getArrayDecayedType(TTy);
-
- // Now try the implicit conversion.
- // FIXME: This doesn't detect ambiguities.
- ICS = Self.TryImplicitConversion(From, TTy,
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false,
- /*InOverloadResolution=*/false);
+
+ return false;
}
+
+ // -- Otherwise: E1 can be converted to match E2 if E1 can be
+ // implicitly converted to the type that expression E2 would have
+ // if E2 were converted to an rvalue (or the type it has, if E2 is
+ // an rvalue).
+ //
+ // This actually refers very narrowly to the lvalue-to-rvalue conversion, not
+ // to the array-to-pointer or function-to-pointer conversions.
+ if (!TTy->getAs<TagType>())
+ TTy = TTy.getUnqualifiedType();
+
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
+ InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
+ HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence;
+ ToType = TTy;
+ if (InitSeq.isAmbiguous())
+ return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
+
return false;
}
@@ -2041,37 +2039,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
/// \brief Perform an "extended" implicit conversion as returned by
/// TryClassUnification.
-///
-/// TryClassUnification generates ICSs that include reference bindings.
-/// PerformImplicitConversion is not suitable for this; it chokes if the
-/// second part of a standard conversion is ICK_DerivedToBase. This function
-/// handles the reference binding specially.
-static bool ConvertForConditional(Sema &Self, Expr *&E,
- const ImplicitConversionSequence &ICS) {
- 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
- // redoing all the work.
- return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType(
- TargetType(ICS)),
- /*FIXME:*/E->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
- }
- 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(
- TargetType(ICS)),
- /*FIXME:*/E->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
- }
- if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting))
+static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
+ InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(),
+ SourceLocation());
+ InitializationSequence InitSeq(Self, Entity, Kind, &E, 1);
+ Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind,
+ Sema::MultiExprArg(Self, (void **)&E, 1));
+ if (Result.isInvalid())
return true;
+
+ E = Result.takeAs<Expr>();
return false;
}
@@ -2139,17 +2117,17 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type, and attempt is made to convert each of those
// operands to the other.
- if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) &&
+ if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
// These return true if a single direction is already ambiguous.
- if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight))
+ QualType L2RType, R2LType;
+ bool HaveL2R, HaveR2L;
+ if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType))
return QualType();
- if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft))
+ if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType))
return QualType();
-
- 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)
@@ -2161,11 +2139,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (ConvertForConditional(*this, LHS, ICSLeftToRight))
+ if (ConvertForConditional(*this, LHS, L2RType))
return QualType();
LTy = LHS->getType();
} else if (HaveR2L) {
- if (ConvertForConditional(*this, RHS, ICSRightToLeft))
+ if (ConvertForConditional(*this, RHS, R2LType))
return QualType();
RTy = RHS->getType();
}
@@ -2174,7 +2152,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// C++0x 5.16p4
// If the second and third operands are lvalues and have the same type,
// the result is of that type [...]
- bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy);
+ bool Same = Context.hasSameType(LTy, RTy);
if (Same && LHS->isLvalue(Context) == Expr::LV_Valid &&
RHS->isLvalue(Context) == Expr::LV_Valid)
return LTy;
@@ -2235,7 +2213,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
return Composite;
}
- // Similarly, attempt to find composite type of twp objective-c pointers.
+ // Similarly, attempt to find composite type of two objective-c pointers.
Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
if (!Composite.isNull())
return Composite;
@@ -2611,7 +2589,7 @@ Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
<< isa<CXXPseudoDestructorExpr>(E)
- << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+ << FixItHint::CreateInsertion(ExpectedLParenLoc, "()");
return ActOnCallExpr(/*Scope*/ 0,
move(MemExpr),
@@ -2645,7 +2623,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
// The user wrote "p->" when she probably meant "p."; fix it.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
if (isSFINAEContext())
return ExprError();
@@ -2750,7 +2728,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
// The user wrote "p->" when she probably meant "p."; fix it.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
- << CodeModificationHint::CreateReplacement(OpLoc, ".");
+ << FixItHint::CreateReplacement(OpLoc, ".");
if (isSFINAEContext())
return ExprError();
@@ -2874,8 +2852,10 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
}
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
- if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0,
+ FoundDecl, Method))
assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?");
MemberExpr *ME =
@@ -2919,7 +2899,8 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc,
assert(!From->getType()->isPointerType() && "Arg can't have pointer type!");
// Create an implicit call expr that calls it.
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method);
+ // FIXME: pass the FoundDecl for the user-defined conversion here
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method);
return MaybeBindToTemporary(CE);
}
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index c98ba43..d5a22ca 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -289,7 +289,10 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
IdentifierInfo *receiverNamePtr = &receiverName;
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr);
-
+ if (!IFace) {
+ Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+ return ExprError();
+ }
// Search for a declared property first.
Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index f86ae51..648e43b 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -504,13 +504,11 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
diag::warn_missing_braces)
<< StructuredSubobjectInitList->getSourceRange()
- << CodeModificationHint::CreateInsertion(
- StructuredSubobjectInitList->getLocStart(),
- "{")
- << CodeModificationHint::CreateInsertion(
- SemaRef.PP.getLocForEndOfToken(
+ << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(),
+ "{")
+ << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken(
StructuredSubobjectInitList->getLocEnd()),
- "}");
+ "}");
}
}
@@ -571,8 +569,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (T->isScalarType() && !TopLevelObject)
SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init)
<< IList->getSourceRange()
- << CodeModificationHint::CreateRemoval(IList->getLocStart())
- << CodeModificationHint::CreateRemoval(IList->getLocEnd());
+ << FixItHint::CreateRemoval(IList->getLocStart())
+ << FixItHint::CreateRemoval(IList->getLocEnd());
}
void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
@@ -1363,8 +1361,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SemaRef.Diag(D->getFieldLoc(),
diag::err_field_designator_unknown_suggest)
<< FieldName << CurrentObjectType << R.getLookupName()
- << CodeModificationHint::CreateReplacement(D->getFieldLoc(),
- R.getLookupName().getAsString());
+ << FixItHint::CreateReplacement(D->getFieldLoc(),
+ R.getLookupName().getAsString());
SemaRef.Diag(ReplacementField->getLocation(),
diag::note_previous_decl)
<< ReplacementField->getDeclName();
@@ -2001,14 +1999,48 @@ void InitializationSequence::Step::Destroy() {
}
}
+bool InitializationSequence::isDirectReferenceBinding() const {
+ return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference;
+}
+
+bool InitializationSequence::isAmbiguous() const {
+ if (getKind() != FailedSequence)
+ return false;
+
+ switch (getFailureKind()) {
+ case FK_TooManyInitsForReference:
+ case FK_ArrayNeedsInitList:
+ case FK_ArrayNeedsInitListOrStringLiteral:
+ case FK_AddressOfOverloadFailed: // FIXME: Could do better
+ case FK_NonConstLValueReferenceBindingToTemporary:
+ case FK_NonConstLValueReferenceBindingToUnrelated:
+ case FK_RValueReferenceBindingToLValue:
+ case FK_ReferenceInitDropsQualifiers:
+ case FK_ReferenceInitFailed:
+ case FK_ConversionFailed:
+ case FK_TooManyInitsForScalar:
+ case FK_ReferenceBindingToInitList:
+ case FK_InitListBadDestinationType:
+ case FK_DefaultInitOfConst:
+ return false;
+
+ case FK_ReferenceInitOverloadFailed:
+ case FK_UserConversionOverloadFailed:
+ case FK_ConstructorOverloadFailed:
+ return FailedOverloadResult == OR_Ambiguous;
+ }
+
+ return false;
+}
+
void InitializationSequence::AddAddressOverloadResolutionStep(
- FunctionDecl *Function) {
+ FunctionDecl *Function,
+ DeclAccessPair Found) {
Step S;
S.Kind = SK_ResolveAddressOfOverloadedFunction;
S.Type = Function->getType();
- // Access is currently ignored for these.
S.Function.Function = Function;
- S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none);
+ S.Function.FoundDecl = Found;
Steps.push_back(S);
}
@@ -2341,15 +2373,17 @@ static void TryReferenceInitialization(Sema &S,
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
+ DeclAccessPair Found;
FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer,
T1,
- false);
+ false,
+ Found);
if (!Fn) {
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
return;
}
- Sequence.AddAddressOverloadResolutionStep(Fn);
+ Sequence.AddAddressOverloadResolutionStep(Fn, Found);
cv2T2 = Fn->getType();
T2 = cv2T2.getUnqualifiedType();
}
@@ -2802,7 +2836,7 @@ static void TryUserDefinedConversion(Sema &S,
if (ConvTemplate)
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(D);
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
@@ -3314,8 +3348,9 @@ InitializationSequence::Perform(Sema &S,
case SK_ResolveAddressOfOverloadedFunction:
// Overload resolution determined which function invoke; update the
// initializer to reflect that choice.
- // Access control was done in overload resolution.
+ S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl);
CurInit = S.FixOverloadedFunctionReference(move(CurInit),
+ Step->Function.FoundDecl,
Step->Function.Function);
break;
@@ -3382,6 +3417,7 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl;
+ bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
@@ -3414,7 +3450,7 @@ InitializationSequence::Perform(Sema &S,
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
-
+ IsLvalue = Conversion->getResultType()->isLValueReferenceType();
S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
FoundFn);
@@ -3422,7 +3458,7 @@ InitializationSequence::Perform(Sema &S,
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0,
- Conversion))
+ FoundFn, Conversion))
return S.ExprError();
// Do a little dance to make sure that CurInit has the proper
@@ -3430,7 +3466,8 @@ InitializationSequence::Perform(Sema &S,
CurInit.release();
// Build the actual call to the conversion function.
- CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion));
+ CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn,
+ Conversion));
if (CurInit.isInvalid() || !CurInit.get())
return S.ExprError();
@@ -3444,7 +3481,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind,
CurInitExpr,
- false));
+ IsLvalue));
if (!IsCopy)
CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
@@ -3614,11 +3651,14 @@ bool InitializationSequence::Diagnose(Sema &S,
<< (Failure == FK_ArrayNeedsInitListOrStringLiteral);
break;
- case FK_AddressOfOverloadFailed:
+ case FK_AddressOfOverloadFailed: {
+ DeclAccessPair Found;
S.ResolveAddressOfOverloadedFunction(Args[0],
DestType.getNonReferenceType(),
- true);
+ true,
+ Found);
break;
+ }
case FK_ReferenceInitOverloadFailed:
case FK_UserConversionOverloadFailed:
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 18a0938..7c6327f 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -599,12 +599,20 @@ public:
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
+ /// \brief Determine whether this initialization is a direct reference
+ /// binding (C++ [dcl.init.ref]).
+ bool isDirectReferenceBinding() const;
+
+ /// \brief Determine whether this initialization failed due to an ambiguity.
+ bool isAmbiguous() const;
+
/// \brief Add a new step in the initialization that resolves the address
/// of an overloaded function to a specific function declaration.
///
/// \param Function the function to which the overloaded function reference
/// resolves.
- void AddAddressOverloadResolutionStep(FunctionDecl *Function);
+ void AddAddressOverloadResolutionStep(FunctionDecl *Function,
+ DeclAccessPair Found);
/// \brief Add a new step in the initialization that performs a derived-to-
/// base cast.
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 9ae520d..a29c4d4 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -304,6 +304,23 @@ void LookupResult::configure() {
SemaRef.getLangOptions().CPlusPlus,
isForRedeclaration());
IsAcceptableFn = getResultFilter(LookupKind);
+
+ // If we're looking for one of the allocation or deallocation
+ // operators, make sure that the implicitly-declared new and delete
+ // operators can be found.
+ if (!isForRedeclaration()) {
+ switch (Name.getCXXOverloadedOperator()) {
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ SemaRef.DeclareGlobalNewDelete();
+ break;
+
+ default:
+ break;
+ }
+ }
}
// Necessary because CXXBasePaths is not complete in Sema.h
@@ -539,13 +556,13 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// 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!
+ FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo();
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
0, 0, ConvProto->isVariadic(),
ConvProto->getTypeQuals(),
false, false, 0, 0,
- ConvProto->getNoReturnAttr(),
- CC_Default);
+ ConvProtoInfo.withCallingConv(CC_Default));
// Perform template argument deduction against the type that we would
// expect the function to have.
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 41ed6c6..f815068 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -44,9 +44,6 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
Diag(AtLoc, diag::error_reference_property);
return DeclPtrTy();
}
- // Validate the attributes on the @property.
- CheckObjCPropertyAttributes(T, AtLoc, Attributes);
-
// Proceed with constructing the ObjCPropertDecls.
ObjCContainerDecl *ClassDecl =
cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>());
@@ -60,10 +57,13 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
isOverridingProperty, T,
MethodImplKind);
- return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+ DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes, T, MethodImplKind));
+ // Validate the attributes on the @property.
+ CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+ return Res;
}
Sema::DeclPtrTy
@@ -93,6 +93,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl,
ObjCPropertyDecl *PDecl =
ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
PropertyId, AtLoc, T);
+ if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+ if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
DC->addDecl(PDecl);
// We need to look in the @interface to see if the @property was
@@ -378,7 +383,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (PropType != IvarType) {
if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) {
Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
+ << property->getDeclName() << PropType
+ << Ivar->getDeclName() << IvarType;
+ Diag(Ivar->getLocation(), diag::note_ivar_decl);
// Note! I deliberately want it to fall thru so, we have a
// a property implementation and to avoid future warnings.
}
@@ -391,7 +398,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
if (lhsType != rhsType &&
lhsType->isArithmeticType()) {
Diag(PropertyLoc, diag::error_property_ivar_type)
- << property->getDeclName() << Ivar->getDeclName();
+ << property->getDeclName() << PropType
+ << Ivar->getDeclName() << IvarType;
+ Diag(Ivar->getLocation(), diag::note_ivar_decl);
// Fall thru - see previous comment
}
// __weak is explicit. So it works on Canonical type.
@@ -973,10 +982,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
AddInstanceMethodToGlobalPool(SetterMethod);
}
-void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
+void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy,
SourceLocation Loc,
unsigned &Attributes) {
// FIXME: Improve the reported location.
+ Decl *PDecl = PropertyPtrTy.getAs<Decl>();
+ ObjCPropertyDecl *PropertyDecl = dyn_cast_or_null<ObjCPropertyDecl>(PDecl);
+ QualType PropertyTy = PropertyDecl->getType();
// readonly and readwrite/assign/retain/copy conflict.
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
@@ -1001,7 +1013,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy,
if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
!PropertyTy->isObjCObjectPointerType() &&
!PropertyTy->isBlockPointerType() &&
- !Context.isObjCNSObjectType(PropertyTy)) {
+ !Context.isObjCNSObjectType(PropertyTy) &&
+ !PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
<< (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 410bf9a..bc10a58 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -567,6 +567,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
+ DeclAccessPair AccessPair;
+
// Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
@@ -612,7 +614,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
} else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ = ResolveAddressOfOverloadedFunction(From, ToType, false,
+ AccessPair)) {
// Address of overloaded function (C++ [over.over]).
SCS.First = ICK_Function_To_Pointer;
@@ -1579,10 +1582,10 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
CXXConversionDecl *Conv;
FunctionTemplateDecl *ConvTemplate;
- if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I)))
- Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+ if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(D)))
+ Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
else
- Conv = dyn_cast<CXXConversionDecl>(*I);
+ Conv = cast<CXXConversionDecl>(D);
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
@@ -2201,44 +2204,6 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
}
}
-/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with
-/// the expression @p From. Returns true (and emits a diagnostic) if there was
-/// an error, returns false if the initialization succeeded. Elidable should
-/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works
-/// differently in C++0x for this case.
-bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
- AssignmentAction Action, bool Elidable) {
- if (!getLangOptions().CPlusPlus) {
- // In C, argument passing is the same as performing an assignment.
- QualType FromType = From->getType();
-
- AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(ToType, From);
- if (ConvTy != Compatible &&
- CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible)
- ConvTy = Compatible;
-
- return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
- FromType, From, Action);
- }
-
- if (ToType->isReferenceType())
- return CheckReferenceInit(From, ToType,
- /*FIXME:*/From->getLocStart(),
- /*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
- /*ForceRValue=*/false);
-
- if (!PerformImplicitConversion(From, ToType, Action,
- /*AllowExplicit=*/false, Elidable))
- return false;
- if (!DiagnoseMultipleUserDefinedConversion(From, ToType))
- return Diag(From->getSourceRange().getBegin(),
- diag::err_typecheck_convert_incompatible)
- << ToType << From->getType() << Action << From->getSourceRange();
- return true;
-}
-
/// TryObjectArgumentInitialization - Try to initialize the object
/// parameter of the given member function (@c Method) from the
/// expression @p From.
@@ -2316,6 +2281,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType,
bool
Sema::PerformObjectArgumentInitialization(Expr *&From,
NestedNameSpecifier *Qualifier,
+ NamedDecl *FoundDecl,
CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
QualType ImplicitParamRecordType =
@@ -2340,7 +2306,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From,
<< ImplicitParamRecordType << FromRecordType << From->getSourceRange();
if (ICS.Standard.Second == ICK_Derived_To_Base)
- return PerformObjectMemberConversion(From, Qualifier, Method);
+ return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
if (!Context.hasSameType(From->getType(), DestType))
ImpCastExprToType(From, DestType, CastExpr::CK_NoOp,
@@ -3344,13 +3310,16 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
= ClassDecl->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
// Skip conversion function templates; they don't tell us anything
// about which builtin types we can convert to.
- if (isa<FunctionTemplateDecl>(*I))
+ if (isa<FunctionTemplateDecl>(D))
continue;
- CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I);
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
if (AllowExplicitConversions || !Conv->isExplicit()) {
AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false,
VisibleQuals);
@@ -3412,7 +3381,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
- if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
+ NamedDecl *D = I.getDecl();
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+ if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
if (const ReferenceType *ResTypeRef = CanTy->getAs<ReferenceType>())
CanTy = ResTypeRef->getPointeeType();
@@ -4733,7 +4705,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
if (!ICS.isAmbiguous()) continue;
S.DiagnoseAmbiguousConversion(ICS, OpLoc,
- PDiag(diag::note_ambiguous_type_conversion));
+ S.PDiag(diag::note_ambiguous_type_conversion));
}
}
@@ -4980,7 +4952,8 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) {
/// routine will emit diagnostics if there is an error.
FunctionDecl *
Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
- bool Complain) {
+ bool Complain,
+ DeclAccessPair &FoundResult) {
QualType FunctionType = ToType;
bool IsMember = false;
if (const PointerType *ToTypePtr = ToType->getAs<PointerType>())
@@ -5018,6 +4991,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+ llvm::SmallVector<FunctionDecl *, 4> NonMatches;
+
bool FoundNonTemplateFunction = false;
for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
E = OvlExpr->decls_end(); I != E; ++I) {
@@ -5097,9 +5072,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
return 0;
else if (Matches.size() == 1) {
FunctionDecl *Result = Matches[0].second;
+ FoundResult = Matches[0].first;
MarkDeclarationReferenced(From->getLocStart(), Result);
if (Complain)
- CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
+ CheckAddressOfMemberAccess(OvlExpr, Matches[0].first);
return Result;
}
@@ -5131,10 +5107,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
<< (unsigned) oc_function_template);
assert(Result != MatchesCopy.end() && "no most-specialized template");
MarkDeclarationReferenced(From->getLocStart(), *Result);
- if (Complain) {
- DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first;
- CheckUnresolvedAccess(*this, OvlExpr, FoundDecl);
- }
+ FoundResult = Matches[Result - MatchesCopy.begin()].first;
+ if (Complain)
+ CheckUnresolvedAccess(*this, OvlExpr, FoundResult);
return cast<FunctionDecl>(*Result);
}
@@ -5153,6 +5128,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
// selected function.
if (Matches.size() == 1) {
MarkDeclarationReferenced(From->getLocStart(), Matches[0].second);
+ FoundResult = Matches[0].first;
if (Complain)
CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first);
return cast<FunctionDecl>(Matches[0].second);
@@ -5433,7 +5409,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE,
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
- Fn = FixOverloadedFunctionReference(Fn, FDecl);
+ Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc);
}
@@ -5560,7 +5536,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
- if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0,
+ Best->FoundDecl, Method))
return ExprError();
} else {
// Convert the arguments.
@@ -5754,7 +5731,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Method))
+ Best->FoundDecl, Method))
return ExprError();
Args[1] = RHS = Arg1.takeAs<Expr>();
@@ -5921,7 +5898,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
- Method))
+ Best->FoundDecl, Method))
return ExprError();
// Convert the arguments.
@@ -6026,10 +6003,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
+ NamedDecl *FoundDecl = 0;
NestedNameSpecifier *Qualifier = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ FoundDecl = MemExpr->getFoundDecl();
Qualifier = MemExpr->getQualifier();
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
@@ -6079,6 +6058,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
+ FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
break;
@@ -6106,7 +6086,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return ExprError();
}
- MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+ MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method);
// If overload resolution picked a static member, build a
// non-member call based on that function.
@@ -6131,9 +6111,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return ExprError();
// Convert the object argument (for a non-static member function call).
+ // We only need to do this if there was actually an overload; otherwise
+ // it was done at lookup.
Expr *ObjectArg = MemExpr->getBase();
if (!Method->isStatic() &&
- PerformObjectArgumentInitialization(ObjectArg, Qualifier, Method))
+ PerformObjectArgumentInitialization(ObjectArg, Qualifier,
+ FoundDecl, Method))
return ExprError();
MemExpr->setBase(ObjectArg);
@@ -6173,7 +6156,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object->getType(),
- PartialDiagnostic(diag::err_incomplete_object_call)
+ PDiag(diag::err_incomplete_object_call)
<< Object->getSourceRange()))
return true;
@@ -6293,7 +6276,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Create an implicit member expr to refer to the conversion operator.
// and then call it.
- CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv);
+ CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl,
+ Conv);
return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc,
MultiExprArg(*this, (ExprTy**)Args, NumArgs),
@@ -6353,7 +6337,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// Initialize the implicit object parameter.
IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0,
- Method);
+ Best->FoundDecl, Method);
TheCall->setArg(0, Object);
@@ -6474,7 +6458,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method))
+ if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0,
+ Best->FoundDecl, Method))
return ExprError();
// No concerns about early exits now.
@@ -6501,9 +6486,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
/// perhaps a '&' around it). We have resolved the overloaded function
/// to the function declaration Fn, so patch up the expression E to
/// refer (possibly indirectly) to Fn. Returns the new expr.
-Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
+Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found,
+ FunctionDecl *Fn) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(),
+ Found, Fn);
if (SubExpr == PE->getSubExpr())
return PE->Retain();
@@ -6511,7 +6498,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
}
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(),
+ Found, Fn);
assert(Context.hasSameType(ICE->getSubExpr()->getType(),
SubExpr->getType()) &&
"Implicit cast type cannot be determined from overload");
@@ -6535,7 +6523,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
// Fix the sub expression, which really has to be an
// UnresolvedLookupExpr holding an overloaded member function
// or template.
- Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
+ Found, Fn);
if (SubExpr == UnOp->getSubExpr())
return UnOp->Retain();
@@ -6556,7 +6545,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemPtrType, UnOp->getOperatorLoc());
}
}
- Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
+ Found, Fn);
if (SubExpr == UnOp->getSubExpr())
return UnOp->Retain();
@@ -6618,6 +6608,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
MemExpr->getQualifier(),
MemExpr->getQualifierRange(),
Fn,
+ Found,
MemExpr->getMemberLoc(),
TemplateArgs,
Fn->getType());
@@ -6628,8 +6619,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
}
Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E,
+ NamedDecl *Found,
FunctionDecl *Fn) {
- return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn));
+ return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn));
}
} // end namespace clang
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index fd65c32..791de8c 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -119,7 +119,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
}
-
+ else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ const ObjCMethodDecl *MD = ME->getMethodDecl();
+ if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
+ return;
+ }
+ }
Diag(Loc, DiagID) << R1 << R2;
}
@@ -427,48 +433,50 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
// Make sure that the condition expression has a complete type,
// otherwise we'll never find any conversions.
if (S.RequireCompleteType(SwitchLoc, CondType,
- PDiag(diag::err_switch_incomplete_class_type)
+ S.PDiag(diag::err_switch_incomplete_class_type)
<< CondExpr->getSourceRange()))
return true;
- llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
- llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
+ UnresolvedSet<4> ViableConversions;
+ UnresolvedSet<4> ExplicitConversions;
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())
->getVisibleConversionFunctions();
for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
- if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
+ if (CXXConversionDecl *Conversion
+ = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl()))
if (Conversion->getConversionType().getNonReferenceType()
->isIntegralType()) {
if (Conversion->isExplicit())
- ExplicitConversions.push_back(Conversion);
+ ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
else
- ViableConversions.push_back(Conversion);
+ ViableConversions.addDecl(I.getDecl(), I.getAccess());
}
}
switch (ViableConversions.size()) {
case 0:
if (ExplicitConversions.size() == 1) {
+ DeclAccessPair Found = ExplicitConversions[0];
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl());
// The user probably meant to invoke the given explicit
// conversion; use it.
QualType ConvTy
- = ExplicitConversions[0]->getConversionType()
- .getNonReferenceType();
+ = Conversion->getConversionType().getNonReferenceType();
std::string TypeStr;
ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy);
S.Diag(SwitchLoc, diag::err_switch_explicit_conversion)
<< CondType << ConvTy << CondExpr->getSourceRange()
- << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(),
- "static_cast<" + TypeStr + ">(")
- << CodeModificationHint::CreateInsertion(
+ << FixItHint::CreateInsertion(CondExpr->getLocStart(),
+ "static_cast<" + TypeStr + ">(")
+ << FixItHint::CreateInsertion(
S.PP.getLocForEndOfToken(CondExpr->getLocEnd()),
")");
- S.Diag(ExplicitConversions[0]->getLocation(),
- diag::note_switch_conversion)
+ S.Diag(Conversion->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
// If we aren't in a SFINAE context, build a call to the
@@ -476,25 +484,32 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
if (S.isSFINAEContext())
return true;
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]);
+ S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
+ CondExpr, 0, Found);
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion);
}
// We'll complain below about a non-integral condition type.
break;
- case 1:
+ case 1: {
// Apply this conversion.
- CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]);
+ DeclAccessPair Found = ViableConversions[0];
+ S.CheckMemberOperatorAccess(CondExpr->getExprLoc(),
+ CondExpr, 0, Found);
+ CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found,
+ cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
break;
+ }
default:
S.Diag(SwitchLoc, diag::err_switch_multiple_conversions)
<< CondType << CondExpr->getSourceRange();
for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
- QualType ConvTy
- = ViableConversions[I]->getConversionType().getNonReferenceType();
- S.Diag(ViableConversions[I]->getLocation(),
- diag::note_switch_conversion)
+ CXXConversionDecl *Conv
+ = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
+ QualType ConvTy = Conv->getConversionType().getNonReferenceType();
+ S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
return true;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 434d556..40ec4bcb 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -161,7 +161,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
Diag(IILoc, diag::err_template_kw_missing)
<< Qualifier << II.getName()
- << CodeModificationHint::CreateInsertion(IILoc, "template ");
+ << FixItHint::CreateInsertion(IILoc, "template ");
SuggestedTemplate
= TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
SuggestedKind = TNK_Dependent_template_name;
@@ -240,12 +240,12 @@ void Sema::LookupTemplateName(LookupResult &Found,
if (LookupCtx)
Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
<< Name << LookupCtx << Found.getLookupName() << SS.getRange()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
else
Diag(Found.getNameLoc(), diag::err_no_template_suggest)
<< Name << Found.getLookupName()
- << CodeModificationHint::CreateReplacement(Found.getNameLoc(),
+ << FixItHint::CreateReplacement(Found.getNameLoc(),
Found.getLookupName().getAsString());
if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
Diag(Template->getLocation(), diag::note_previous_decl)
@@ -822,8 +822,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
- << CodeModificationHint::CreateReplacement(KWLoc,
- PrevRecordDecl->getKindName());
+ << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
Kind = PrevRecordDecl->getTagKind();
}
@@ -1295,8 +1294,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
} else {
Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
<< SS.getRange()
- << CodeModificationHint::CreateInsertion(FirstTemplateLoc,
- "template<> ");
+ << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> ");
IsExplicitSpecialization = true;
}
return 0;
@@ -1499,8 +1497,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult,
if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Type
- << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
- D->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
Diag(D->getLocation(), diag::note_previous_use);
}
}
@@ -1897,7 +1894,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
- TemplateArgumentListBuilder &Converted) {
+ TemplateArgumentListBuilder &Converted,
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, Converted);
@@ -1937,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Expression: {
Expr *E = Arg.getArgument().getAsExpr();
TemplateArgument Result;
- if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+ if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK))
return true;
Converted.Append(Result);
@@ -2268,18 +2266,20 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
- NamedDecl *&Entity) {
+static bool
+CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
+ NonTypeTemplateParmDecl *Param,
+ QualType ParamType,
+ Expr *ArgIn,
+ TemplateArgument &Converted) {
bool Invalid = false;
+ Expr *Arg = ArgIn;
+ QualType ArgType = Arg->getType();
// See through any implicit casts we added to fix the type.
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
- // C++0x allows nullptr, and there's no further checking to be done for that.
- if (Arg->getType()->isNullPtrType())
- return false;
-
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -2296,8 +2296,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
// Ignore (and complain about) any excess parentheses.
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_extra_parens)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_extra_parens)
<< Arg->getSourceRange();
Invalid = true;
}
@@ -2305,77 +2305,227 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
Arg = Parens->getSubExpr();
}
+ bool AddressTaken = false;
+ SourceLocation AddrOpLoc;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
- if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+ AddressTaken = true;
+ AddrOpLoc = UnOp->getOperatorLoc();
+ }
} else
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE)
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_decl_ref)
- << Arg->getSourceRange();
+ if (!DRE) {
+ if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) {
+ S.Diag(Arg->getLocStart(),
+ diag::err_template_arg_unresolved_overloaded_function)
+ << ParamType << Arg->getSourceRange();
+ } else {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+ << Arg->getSourceRange();
+ }
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
- if (Arg->isValueDependent())
+ if (Arg->isValueDependent()) {
+ Converted = TemplateArgument(ArgIn->Retain());
return false;
+ }
- if (!isa<ValueDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_object_or_func_form)
+ if (!isa<ValueDecl>(DRE->getDecl())) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func_form)
<< Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ NamedDecl *Entity = 0;
// Cannot refer to non-static data members
- if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl()))
- return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) {
+ S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
<< Field << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Cannot refer to non-static member functions
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
- if (!Method->isStatic())
- return Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_method)
+ if (!Method->isStatic()) {
+ S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method)
<< Method << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
// Functions must have external linkage.
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
if (!isExternalLinkage(Func->getLinkage())) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_function_not_extern)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_function_not_extern)
<< Func << Arg->getSourceRange();
- Diag(Func->getLocation(), diag::note_template_arg_internal_object)
+ S.Diag(Func->getLocation(), diag::note_template_arg_internal_object)
<< true;
return true;
}
// Okay: we've named a function with external linkage.
Entity = Func;
- return Invalid;
- }
- if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // If the template parameter has pointer type, the function decays.
+ if (ParamType->isPointerType() && !AddressTaken)
+ ArgType = S.Context.getPointerType(Func->getType());
+ else if (AddressTaken && ParamType->isReferenceType()) {
+ // If we originally had an address-of operator, but the
+ // parameter has reference type, complain and (if things look
+ // like they will work) drop the address-of operator.
+ if (!S.Context.hasSameUnqualifiedType(Func->getType(),
+ ParamType.getNonReferenceType())) {
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType
+ << FixItHint::CreateRemoval(AddrOpLoc);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+ ArgType = Func->getType();
+ }
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (!isExternalLinkage(Var->getLinkage())) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_object_not_extern)
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_object_not_extern)
<< Var << Arg->getSourceRange();
- Diag(Var->getLocation(), diag::note_template_arg_internal_object)
+ S.Diag(Var->getLocation(), diag::note_template_arg_internal_object)
<< true;
return true;
}
+ // A value of reference type is not an object.
+ if (Var->getType()->isReferenceType()) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_reference_var)
+ << Var->getType() << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
// Okay: we've named an object with external linkage
Entity = Var;
- return Invalid;
- }
- // We found something else, but we don't know specifically what it is.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_object_or_func)
+ // If the template parameter has pointer type, we must have taken
+ // the address of this object.
+ if (ParamType->isReferenceType()) {
+ if (AddressTaken) {
+ // If we originally had an address-of operator, but the
+ // parameter has reference type, complain and (if things look
+ // like they will work) drop the address-of operator.
+ if (!S.Context.hasSameUnqualifiedType(Var->getType(),
+ ParamType.getNonReferenceType())) {
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType
+ << FixItHint::CreateRemoval(AddrOpLoc);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+ ArgType = Var->getType();
+ }
+ } else if (!AddressTaken && ParamType->isPointerType()) {
+ if (Var->getType()->isArrayType()) {
+ // Array-to-pointer decay.
+ ArgType = S.Context.getArrayDecayedType(Var->getType());
+ } else {
+ // If the template parameter has pointer type but the address of
+ // this object was not taken, complain and (possibly) recover by
+ // taking the address of the entity.
+ ArgType = S.Context.getPointerType(Var->getType());
+ if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+ << ParamType
+ << FixItHint::CreateInsertion(Arg->getLocStart(), "&");
+
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ }
+ }
+ } else {
+ // We found something else, but we don't know specifically what it is.
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_object_or_func)
<< Arg->getSourceRange();
- Diag(DRE->getDecl()->getLocation(),
- diag::note_template_arg_refers_here);
- return true;
+ S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
+ return true;
+ }
+
+ if (ParamType->isPointerType() &&
+ !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ S.IsQualificationConversion(ArgType, ParamType)) {
+ // For pointer-to-object types, qualification conversions are
+ // permitted.
+ } else {
+ if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) {
+ if (!ParamRef->getPointeeType()->isFunctionType()) {
+ // C++ [temp.arg.nontype]p5b3:
+ // For a non-type template-parameter of type reference to
+ // object, no conversions apply. The type referred to by the
+ // reference may be more cv-qualified than the (otherwise
+ // identical) type of the template- argument. The
+ // template-parameter is bound directly to the
+ // template-argument, which shall be an lvalue.
+
+ // FIXME: Other qualifiers?
+ unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers();
+ unsigned ArgQuals = ArgType.getCVRQualifiers();
+
+ if ((ParamQuals | ArgQuals) != ParamQuals) {
+ S.Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_ref_bind_ignores_quals)
+ << ParamType << Arg->getType()
+ << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+ }
+
+ // At this point, the template argument refers to an object or
+ // function with external linkage. We now need to check whether the
+ // argument and parameter types are compatible.
+ if (!S.Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
+ // We can't perform this conversion or binding.
+ if (ParamType->isReferenceType())
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
+ << ParamType << Arg->getType() << Arg->getSourceRange();
+ else
+ S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible)
+ << Arg->getType() << ParamType << Arg->getSourceRange();
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+
+ // Create the template argument.
+ Converted = TemplateArgument(Entity->getCanonicalDecl());
+ return false;
}
/// \brief Checks whether the given template argument is a pointer to
@@ -2388,10 +2538,6 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
- // C++0x allows nullptr, and there's no further checking to be done for that.
- if (Arg->getType()->isNullPtrType())
- return false;
-
// C++ [temp.arg.nontype]p1:
//
// A template-argument for a non-type, non-template
@@ -2478,12 +2624,12 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg,
/// If no error was detected, Converted receives the converted template argument.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType InstantiatedParamType, Expr *&Arg,
- TemplateArgument &Converted) {
+ TemplateArgument &Converted,
+ CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
- // FIXME: Add template argument to Converted!
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
@@ -2525,17 +2671,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- // FIXME: We need some way to more easily get the unqualified form
- // of the types without going all the way to the
- // canonical type.
- if (Context.getCanonicalType(ParamType).getCVRQualifiers())
- ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType();
- if (Context.getCanonicalType(ArgType).getCVRQualifiers())
- ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType();
+ // From here on out, all we care about are the unqualified forms
+ // of the parameter and argument types.
+ ParamType = ParamType.getUnqualifiedType();
+ ArgType = ArgType.getUnqualifiedType();
// Try to convert the argument to the parameter's type.
if (Context.hasSameType(ParamType, ArgType)) {
// Okay: no conversion necessary
+ } else if (CTAK == CTAK_Deduced) {
+ // C++ [temp.deduct.type]p17:
+ // If, in the declaration of a function template with a non-type
+ // template-parameter, the non-type template- parameter is used
+ // in an expression in the function parameter-list and, if the
+ // corresponding template-argument is deduced, the
+ // template-argument type shall match the type of the
+ // template-parameter exactly, except that a template-argument
+ // deduced from an array bound may be of any integral type.
+ Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+ << ArgType << ParamType;
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
} else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
!ParamType->isEnumeralType()) {
// This is an integral promotion or conversion.
@@ -2554,38 +2710,39 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
if (!Arg->isValueDependent()) {
- // Check that an unsigned parameter does not receive a negative
- // value.
+ llvm::APSInt OldValue = Value;
+
+ // Coerce the template argument's value to the value it will have
+ // based on the template parameter's type.
+ unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ if (Value.getBitWidth() != AllowedBits)
+ Value.extOrTrunc(AllowedBits);
+ Value.setIsSigned(IntegerType->isSignedIntegerType());
+
+ // Complain if an unsigned parameter received a negative value.
if (IntegerType->isUnsignedIntegerType()
- && (Value.isSigned() && Value.isNegative())) {
- Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative)
- << Value.toString(10) << Param->getType()
+ && (OldValue.isSigned() && OldValue.isNegative())) {
+ Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative)
+ << OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
}
- // Check that we don't overflow the template parameter type.
- unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ // Complain if we overflowed the template parameter's type.
unsigned RequiredBits;
if (IntegerType->isUnsignedIntegerType())
- RequiredBits = Value.getActiveBits();
- else if (Value.isUnsigned())
- RequiredBits = Value.getActiveBits() + 1;
+ RequiredBits = OldValue.getActiveBits();
+ else if (OldValue.isUnsigned())
+ RequiredBits = OldValue.getActiveBits() + 1;
else
- RequiredBits = Value.getMinSignedBits();
+ RequiredBits = OldValue.getMinSignedBits();
if (RequiredBits > AllowedBits) {
Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_too_large)
- << Value.toString(10) << Param->getType()
+ diag::warn_template_arg_too_large)
+ << OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
}
-
- if (Value.getBitWidth() != AllowedBits)
- Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(IntegerType->isSignedIntegerType());
}
// Add the value of this argument to the list of converted
@@ -2604,6 +2761,18 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return false;
}
+ DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
+
+ // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion
+ // from a template argument of type std::nullptr_t to a non-type
+ // template parameter of type pointer to object, pointer to
+ // function, or pointer-to-member, respectively.
+ if (ArgType->isNullPtrType() &&
+ (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
+ Converted = TemplateArgument((NamedDecl *)0);
+ return false;
+ }
+
// Handle pointer-to-function, reference-to-function, and
// pointer-to-member-function all in (roughly) the same way.
if (// -- For a non-type template-parameter of type pointer to
@@ -2611,7 +2780,6 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// applied. If the template-argument represents a set of
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
- // In C++0x, any std::nullptr_t value can be converted.
(ParamType->isPointerType() &&
ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
@@ -2625,38 +2793,30 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
- // Again, C++0x allows a std::nullptr_t value.
(ParamType->isMemberPointerType() &&
ParamType->getAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
- if (Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
- // We don't have to do anything: the types already match.
- } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
- ParamType->isMemberPointerType())) {
- ArgType = ParamType;
- if (ParamType->isMemberPointerType())
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
- else
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
- } else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
- ArgType = Context.getPointerType(ArgType);
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
- } else if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
+
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
+ true,
+ FoundResult)) {
if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
return true;
- Arg = FixOverloadedFunctionReference(Arg, Fn);
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
ArgType = Arg->getType();
- if (ArgType->isFunctionType() && ParamType->isPointerType()) {
- ArgType = Context.getPointerType(Arg->getType());
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
- }
}
- if (!Context.hasSameUnqualifiedType(ArgType,
- ParamType.getNonReferenceType())) {
+ if (!ParamType->isMemberPointerType())
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
+
+ if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) {
+ ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+ Arg->isLvalue(Context) == Expr::LV_Valid);
+ } else if (!Context.hasSameUnqualifiedType(ArgType,
+ ParamType.getNonReferenceType())) {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_convertible)
@@ -2665,21 +2825,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
- if (ParamType->isMemberPointerType())
- return CheckTemplateArgumentPointerToMember(Arg, Converted);
-
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentPointerToMember(Arg, Converted);
}
if (ParamType->isPointerType()) {
@@ -2690,40 +2836,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() &&
"Only object pointers allowed here");
- if (ArgType->isNullPtrType()) {
- ArgType = ParamType;
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
- } else if (ArgType->isArrayType()) {
- ArgType = Context.getArrayDecayedType(ArgType);
- ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay);
- }
-
- if (IsQualificationConversion(ArgType, ParamType)) {
- ArgType = ParamType;
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
- }
-
- if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
- // We can't perform this conversion.
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_not_convertible)
- << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- if (Entity)
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
}
if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
@@ -2736,53 +2851,31 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamRefType->getPointeeType()->isObjectType() &&
"Only object references allowed here");
- QualType ReferredType = ParamRefType->getPointeeType();
- if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_no_ref_bind)
- << InstantiatedParamType << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- unsigned ParamQuals
- = Context.getCanonicalType(ReferredType).getCVRQualifiers();
- unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
+ if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
+ ParamRefType->getPointeeType(),
+ true,
+ FoundResult)) {
+ if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+ return true;
- if ((ParamQuals | ArgQuals) != ParamQuals) {
- Diag(Arg->getSourceRange().getBegin(),
- diag::err_template_arg_ref_bind_ignores_quals)
- << InstantiatedParamType << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+ Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+ ArgType = Arg->getType();
}
- NamedDecl *Entity = 0;
- if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
- return true;
-
- if (Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
- Converted = TemplateArgument(Entity);
- }
- return false;
+ return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+ ParamType,
+ Arg, Converted);
}
// -- For a non-type template-parameter of type pointer to data
// member, qualification conversions (4.4) are applied.
- // C++0x allows std::nullptr_t values.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
// Types match exactly: nothing more to do here.
- } else if (ArgType->isNullPtrType()) {
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
} else if (IsQualificationConversion(ArgType, ParamType)) {
- ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
+ ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+ Arg->isLvalue(Context) == Expr::LV_Valid);
} else {
// We can't perform this conversion.
Diag(Arg->getSourceRange().getBegin(),
@@ -2837,6 +2930,109 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
Arg.getLocation());
}
+/// \brief Given a non-type template argument that refers to a
+/// declaration and the type of its corresponding non-type template
+/// parameter, produce an expression that properly refers to that
+/// declaration.
+Sema::OwningExprResult
+Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+ QualType ParamType,
+ SourceLocation Loc) {
+ assert(Arg.getKind() == TemplateArgument::Declaration &&
+ "Only declaration template arguments permitted here");
+ ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+
+ if (VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+ // If the value is a class member, we might have a pointer-to-member.
+ // Determine whether the non-type template template parameter is of
+ // pointer-to-member type. If so, we need to build an appropriate
+ // expression for a pointer-to-member, since a "normal" DeclRefExpr
+ // would refer to the member itself.
+ if (ParamType->isMemberPointerType()) {
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr());
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ OwningExprResult RefExpr = BuildDeclRefExpr(VD,
+ VD->getType().getNonReferenceType(),
+ Loc,
+ &SS);
+ if (RefExpr.isInvalid())
+ return ExprError();
+
+ RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+ assert(!RefExpr.isInvalid() &&
+ Context.hasSameType(((Expr*) RefExpr.get())->getType(),
+ ParamType));
+ return move(RefExpr);
+ }
+ }
+
+ QualType T = VD->getType().getNonReferenceType();
+ if (ParamType->isPointerType()) {
+ // When the non-type template parameter is a pointer, take the
+ // address of the declaration.
+ OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc);
+ if (RefExpr.isInvalid())
+ return ExprError();
+
+ if (T->isFunctionType() || T->isArrayType()) {
+ // Decay functions and arrays.
+ Expr *RefE = (Expr *)RefExpr.get();
+ DefaultFunctionArrayConversion(RefE);
+ if (RefE != RefExpr.get()) {
+ RefExpr.release();
+ RefExpr = Owned(RefE);
+ }
+
+ return move(RefExpr);
+ }
+
+ // Take the address of everything else
+ return CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+ }
+
+ // If the non-type template parameter has reference type, qualify the
+ // resulting declaration reference with the extra qualifiers on the
+ // type that the reference refers to.
+ if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>())
+ T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers());
+
+ return BuildDeclRefExpr(VD, T, Loc);
+}
+
+/// \brief Construct a new expression that refers to the given
+/// integral template argument with the given source-location
+/// information.
+///
+/// This routine takes care of the mapping from an integral template
+/// argument (which may have any integral type) to the appropriate
+/// literal value.
+Sema::OwningExprResult
+Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc) {
+ assert(Arg.getKind() == TemplateArgument::Integral &&
+ "Operation is only value for integral template arguments");
+ QualType T = Arg.getIntegralType();
+ if (T->isCharType() || T->isWideCharType())
+ return Owned(new (Context) CharacterLiteral(
+ Arg.getAsIntegral()->getZExtValue(),
+ T->isWideCharType(),
+ T,
+ Loc));
+ if (T->isBooleanType())
+ return Owned(new (Context) CXXBoolLiteralExpr(
+ Arg.getAsIntegral()->getBoolValue(),
+ T,
+ Loc));
+
+ return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc));
+}
+
+
/// \brief Determine whether the given template parameter lists are
/// equivalent.
///
@@ -3341,7 +3537,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
} else if (TemplateParams) {
if (TUK == TUK_Friend)
Diag(KWLoc, diag::err_template_spec_friend)
- << CodeModificationHint::CreateRemoval(
+ << FixItHint::CreateRemoval(
SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc()))
<< SourceRange(LAngleLoc, RAngleLoc);
@@ -3349,7 +3545,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
isExplicitSpecialization = true;
} else if (TUK != TUK_Friend) {
Diag(KWLoc, diag::err_template_spec_needs_header)
- << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
+ << FixItHint::CreateInsertion(KWLoc, "template<> ");
isExplicitSpecialization = true;
}
@@ -3367,7 +3563,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << FixItHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
@@ -3409,8 +3605,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
<< (TUK == TUK_Definition)
- << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
- RAngleLoc));
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
@@ -3644,7 +3839,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (TUK == TUK_Friend) {
FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
TemplateNameLoc,
- WrittenTy->getType().getTypePtr(),
+ WrittenTy,
/*FIXME:*/KWLoc);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
@@ -3948,11 +4143,11 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
UnresolvedSetIterator Result
= getMostSpecialized(Candidates.begin(), Candidates.end(),
TPOC_Other, FD->getLocation(),
- PartialDiagnostic(diag::err_function_template_spec_no_match)
+ PDiag(diag::err_function_template_spec_no_match)
<< FD->getDeclName(),
- PartialDiagnostic(diag::err_function_template_spec_ambiguous)
+ PDiag(diag::err_function_template_spec_ambiguous)
<< FD->getDeclName() << (ExplicitTemplateArgs != 0),
- PartialDiagnostic(diag::note_function_template_spec_matched));
+ PDiag(diag::note_function_template_spec_matched));
if (Result == Candidates.end())
return true;
@@ -3961,9 +4156,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// FIXME: Check if the prior specialization has a point of instantiation.
// If so, we have run afoul of .
+
+ // If this is a friend declaration, then we're not really declaring
+ // an explicit specialization.
+ bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None);
// Check the scope of this explicit specialization.
- if (CheckTemplateSpecializationScope(*this,
+ if (!isFriend &&
+ CheckTemplateSpecializationScope(*this,
Specialization->getPrimaryTemplate(),
Specialization, FD->getLocation(),
false))
@@ -3980,7 +4180,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
assert(SpecInfo && "Function template specialization info missing?");
bool SuppressNew = false;
- if (CheckSpecializationInstantiationRedecl(FD->getLocation(),
+ if (!isFriend &&
+ CheckSpecializationInstantiationRedecl(FD->getLocation(),
TSK_ExplicitSpecialization,
Specialization,
SpecInfo->getTemplateSpecializationKind(),
@@ -3990,7 +4191,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
- SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
+ if (!isFriend)
+ SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
// Turn the given function declaration into a function template
// specialization, with the template arguments from the previous
@@ -3999,7 +4201,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
new (Context) TemplateArgumentList(
*Specialization->getTemplateSpecializationArgs()),
/*InsertPos=*/0,
- TSK_ExplicitSpecialization);
+ SpecInfo->getTemplateSpecializationKind());
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
@@ -4250,7 +4452,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
- << CodeModificationHint::CreateReplacement(KWLoc,
+ << FixItHint::CreateReplacement(KWLoc,
ClassTemplate->getTemplatedDecl()->getKindName());
Diag(ClassTemplate->getTemplatedDecl()->getLocation(),
diag::note_previous_use);
@@ -4388,8 +4590,17 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
- if (Def)
+ if (Def) {
+ TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
+
+ // Fix a TSK_ExplicitInstantiationDeclaration followed by a
+ // TSK_ExplicitInstantiationDefinition
+ if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
+ TSK == TSK_ExplicitInstantiationDefinition)
+ Def->setTemplateSpecializationKind(TSK);
+
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
+ }
return DeclPtrTy::make(Specialization);
}
@@ -4559,7 +4770,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x)
Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_explicit_instantiation_inline)
- <<CodeModificationHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
+ <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
// FIXME: check for constexpr specifier.
@@ -4699,9 +4910,9 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
UnresolvedSetIterator Result
= getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other,
D.getIdentifierLoc(),
- PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
- PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
- PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+ PDiag(diag::err_explicit_instantiation_not_known) << Name,
+ PDiag(diag::err_explicit_instantiation_ambiguous) << Name,
+ PDiag(diag::note_explicit_instantiation_candidate));
if (Result == Matches.end())
return true;
@@ -4781,14 +4992,16 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!NNS)
return true;
- QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
- if (T.isNull())
- return true;
-
- TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
- QualType ElabType = Context.getElaboratedType(T, TagKind);
+ ElaboratedTypeKeyword Keyword = ETK_None;
+ switch (TagDecl::getTagKindForTypeSpec(TagSpec)) {
+ case TagDecl::TK_struct: Keyword = ETK_Struct; break;
+ case TagDecl::TK_class: Keyword = ETK_Class; break;
+ case TagDecl::TK_union: Keyword = ETK_Union; break;
+ case TagDecl::TK_enum: Keyword = ETK_Enum; break;
+ }
+ assert(Keyword != ETK_None && "Invalid tag kind!");
- return ElabType.getAsOpaquePtr();
+ return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
}
Sema::TypeResult
@@ -4824,7 +5037,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
}
- return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+ return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
+ .getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
@@ -4839,7 +5053,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// If the nested-name-specifier does not refer to the current
// instantiation, then build a typename type.
if (!CurrentInstantiation)
- return Context.getTypenameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
// The nested-name-specifier refers to the current instantiation, so the
// "typename" keyword itself is superfluous. In C++03, the program is
@@ -4875,7 +5089,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getTypenameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -4960,16 +5174,16 @@ namespace {
/// \brief Transforms a typename type by determining whether the type now
/// refers to a member of the current instantiation, and then
/// type-checking and building a QualifiedNameType (when possible).
- QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL,
+ QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL,
QualType ObjectType);
};
}
QualType
-CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL,
+CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
QualType ObjectType) {
- TypenameType *T = TL.getTypePtr();
+ DependentNameType *T = TL.getTypePtr();
NestedNameSpecifier *NNS
= TransformNestedNameSpecifier(T->getQualifier(),
@@ -5001,15 +5215,17 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
Result = QualType(T, 0);
else
- Result = getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, NewTemplateId);
} else
- Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(),
- SourceRange(TL.getNameLoc()));
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, T->getIdentifier(),
+ SourceRange(TL.getNameLoc()));
if (Result.isNull())
return QualType();
- TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result);
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
@@ -5034,7 +5250,7 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
/// typename X<T>::pointer X<T>::data() { ... }
/// \endcode
///
-/// Here, the type "typename X<T>::pointer" will be created as a TypenameType,
+/// Here, the type "typename X<T>::pointer" will be created as a DependentNameType,
/// since we do not know that we can look into X<T> when we parsed the type.
/// This function will rebuild the type, performing the lookup of "pointer"
/// in X<T> and returning a QualifiedNameType whose canonical type is the same
diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h
index 2bfb25a..ca59e27 100644
--- a/lib/Sema/SemaTemplate.h
+++ b/lib/Sema/SemaTemplate.h
@@ -99,6 +99,40 @@ namespace clang {
/// template specialization to a function template.
TPOC_Other
};
+
+ /// \brief Captures a template argument whose value has been deduced
+ /// via c++ template argument deduction.
+ class DeducedTemplateArgument : public TemplateArgument {
+ /// \brief For a non-type template argument, whether the value was
+ /// deduced from an array bound.
+ bool DeducedFromArrayBound;
+
+ public:
+ DeducedTemplateArgument()
+ : TemplateArgument(), DeducedFromArrayBound(false) { }
+
+ DeducedTemplateArgument(const TemplateArgument &Arg,
+ bool DeducedFromArrayBound = false)
+ : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+ /// \brief Construct an integral non-type template argument that
+ /// has been deduced, possible from an array bound.
+ DeducedTemplateArgument(const llvm::APSInt &Value,
+ QualType ValueType,
+ bool DeducedFromArrayBound)
+ : TemplateArgument(Value, ValueType),
+ DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+ /// \brief For a non-type template argument, determine whether the
+ /// template argument was deduced from an array bound.
+ bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; }
+
+ /// \brief Specify whether the given non-type template argument
+ /// was deduced from an array bound.
+ void setDeducedFromArrayBound(bool Deduced) {
+ DeducedFromArrayBound = Deduced;
+ }
+ };
}
#endif // LLVM_CLANG_SEMA_TEMPLATE_H
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 326519d..d61a767 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -48,13 +48,34 @@ namespace clang {
using namespace clang;
+/// \brief Compare two APSInts, extending and switching the sign as
+/// necessary to compare their values regardless of underlying type.
+static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
+ if (Y.getBitWidth() > X.getBitWidth())
+ X.extend(Y.getBitWidth());
+ else if (Y.getBitWidth() < X.getBitWidth())
+ Y.extend(X.getBitWidth());
+
+ // If there is a signedness mismatch, correct it.
+ if (X.isSigned() != Y.isSigned()) {
+ // If the signed value is negative, then the values cannot be the same.
+ if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative()))
+ return false;
+
+ Y.setIsSigned(true);
+ X.setIsSigned(true);
+ }
+
+ return X == Y;
+}
+
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const TemplateArgument &Param,
const TemplateArgument &Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
@@ -74,50 +95,38 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
static Sema::TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
- llvm::APSInt Value,
+ llvm::APSInt Value, QualType ValueType,
+ bool DeducedFromArrayBound,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
if (Deduced[NTTP->getIndex()].isNull()) {
- QualType T = NTTP->getType();
-
- // FIXME: Make sure we didn't overflow our data type!
- unsigned AllowedBits = S.Context.getTypeSize(T);
- if (Value.getBitWidth() != AllowedBits)
- Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(T->isSignedIntegerType());
-
- Deduced[NTTP->getIndex()] = TemplateArgument(Value, T);
+ Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType,
+ DeducedFromArrayBound);
return Sema::TDK_Success;
}
- assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
-
- // If the template argument was previously deduced to a negative value,
- // then our deduction fails.
- const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
- if (PrevValuePtr->isNegative()) {
+ if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
- Info.SecondArg = TemplateArgument(Value, NTTP->getType());
- return Sema::TDK_Inconsistent;
+ Info.SecondArg = TemplateArgument(Value, ValueType);
+ return Sema::TDK_Inconsistent;
}
- llvm::APSInt PrevValue = *PrevValuePtr;
- if (Value.getBitWidth() > PrevValue.getBitWidth())
- PrevValue.zext(Value.getBitWidth());
- else if (Value.getBitWidth() < PrevValue.getBitWidth())
- Value.zext(PrevValue.getBitWidth());
-
- if (Value != PrevValue) {
+ // Extent the smaller of the two values.
+ llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral();
+ if (!hasSameExtendedValue(PrevValue, Value)) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
- Info.SecondArg = TemplateArgument(Value, NTTP->getType());
+ Info.SecondArg = TemplateArgument(Value, ValueType);
return Sema::TDK_Inconsistent;
}
+ if (!DeducedFromArrayBound)
+ Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false);
+
return Sema::TDK_Success;
}
@@ -130,15 +139,14 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Expr *Value,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
"Expression template argument must be type- or value-dependent.");
if (Deduced[NTTP->getIndex()].isNull()) {
- // FIXME: Clone the Value?
- Deduced[NTTP->getIndex()] = TemplateArgument(Value);
+ Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain());
return Sema::TDK_Success;
}
@@ -173,7 +181,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
NonTypeTemplateParmDecl *NTTP,
Decl *D,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -207,7 +215,7 @@ DeduceTemplateArguments(Sema &S,
TemplateName Param,
TemplateName Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -271,7 +279,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateSpecializationType *Param,
QualType Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(Arg.isCanonical() && "Argument type must be canonical");
// Check whether the template argument is a dependent template-id.
@@ -363,7 +371,7 @@ DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
@@ -569,7 +577,9 @@ DeduceTemplateArguments(Sema &S,
if (const ConstantArrayType *ConstantArrayArg
= dyn_cast<ConstantArrayType>(ArrayArg)) {
llvm::APSInt Size(ConstantArrayArg->getSize());
- return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+ return DeduceNonTypeTemplateArgument(S, NTTP, Size,
+ S.Context.getSizeType(),
+ /*ArrayBound=*/true,
Info, Deduced);
}
if (const DependentSizedArrayType *DependentArrayArg
@@ -763,7 +773,7 @@ DeduceTemplateArguments(Sema &S,
case Type::TypeOfExpr:
case Type::TypeOf:
- case Type::Typename:
+ case Type::DependentName:
// No template argument deduction for these types
return Sema::TDK_Success;
@@ -781,7 +791,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument &Param,
const TemplateArgument &Arg,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
switch (Param.getKind()) {
case TemplateArgument::Null:
assert(false && "Null template argument in parameter list");
@@ -816,8 +826,7 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
- // FIXME: Zero extension + sign checking here?
- if (*Param.getAsIntegral() == *Arg.getAsIntegral())
+ if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral()))
return Sema::TDK_Success;
Info.FirstArg = Param;
@@ -840,9 +849,10 @@ DeduceTemplateArguments(Sema &S,
if (NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(Param.getAsExpr())) {
if (Arg.getKind() == TemplateArgument::Integral)
- // FIXME: Sign problems here
return DeduceNonTypeTemplateArgument(S, NTTP,
*Arg.getAsIntegral(),
+ Arg.getIntegralType(),
+ /*ArrayBound=*/false,
Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
@@ -874,7 +884,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (Sema::TemplateDeductionResult Result
@@ -963,7 +973,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// specialization can be deduced from the actual template argument
// list (14.8.2).
SFINAETrap Trap(*this);
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this,
@@ -987,13 +997,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
Decl *Param
= const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(I));
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- Info.Param = TTP;
- else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param))
- Info.Param = NTTP;
- else
- Info.Param = cast<TemplateTemplateParmDecl>(Param);
+ Info.Param = makeTemplateParameter(Param);
return TDK_Incomplete;
}
@@ -1010,6 +1014,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
// verify that the instantiated template arguments are both valid
// and are equivalent to the template arguments originally provided
// to the class template.
+ // FIXME: Do we have to correct the types of deduced non-type template
+ // arguments (in particular, integral non-type template arguments?).
+ Sema::LocalInstantiationScope InstScope(*this);
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentLoc *PartialTemplateArgs
= Partial->getTemplateArgsAsWritten();
@@ -1112,7 +1119,7 @@ Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
llvm::SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info) {
@@ -1225,12 +1232,67 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_Success;
}
+/// \brief Allocate a TemplateArgumentLoc where all locations have
+/// been initialized to the given location.
+///
+/// \param S The semantic analysis object.
+///
+/// \param The template argument we are producing template argument
+/// location information for.
+///
+/// \param NTTPType For a declaration template argument, the type of
+/// the non-type template parameter that corresponds to this template
+/// argument.
+///
+/// \param Loc The source location to use for the resulting template
+/// argument.
+static TemplateArgumentLoc
+getTrivialTemplateArgumentLoc(Sema &S,
+ const TemplateArgument &Arg,
+ QualType NTTPType,
+ SourceLocation Loc) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't get a NULL template argument here");
+ break;
+
+ case TemplateArgument::Type:
+ return TemplateArgumentLoc(Arg,
+ S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+
+ case TemplateArgument::Declaration: {
+ Expr *E
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Integral: {
+ Expr *E
+ = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Template:
+ return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+
+ case TemplateArgument::Expression:
+ return TemplateArgumentLoc(Arg, Arg.getAsExpr());
+
+ case TemplateArgument::Pack:
+ llvm_unreachable("Template parameter packs are not yet supported");
+ }
+
+ return TemplateArgumentLoc();
+}
+
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
Sema::TemplateDeductionResult
Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified,
FunctionDecl *&Specialization,
TemplateDeductionInfo &Info) {
TemplateParameterList *TemplateParams
@@ -1253,13 +1315,71 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
if (!Deduced[I].isNull()) {
- Builder.Append(Deduced[I]);
+ if (I < NumExplicitlySpecified ||
+ Deduced[I].getKind() == TemplateArgument::Type) {
+ // We have already fully type-checked and converted this
+ // argument (because it was explicitly-specified) or no
+ // additional checking is necessary (because it's a template
+ // type parameter). Just record the presence of this
+ // parameter.
+ Builder.Append(Deduced[I]);
+ continue;
+ }
+
+ // We have deduced this argument, so it still needs to be
+ // checked and converted.
+
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Deduced[I].getKind() == TemplateArgument::Declaration) {
+ NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ TemplateArgumentList TemplateArgs(Context, Builder,
+ /*TakeArgs=*/false);
+ NTTPType = SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ if (NTTPType.isNull()) {
+ Info.Param = makeTemplateParameter(Param);
+ return TDK_SubstitutionFailure;
+ }
+ }
+ }
+ }
+
+ // Convert the deduced template argument into a template
+ // argument that we can check, almost as if the user had written
+ // the template argument explicitly.
+ TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this,
+ Deduced[I],
+ NTTPType,
+ SourceLocation());
+
+ // Check the template argument, converting it as necessary.
+ if (CheckTemplateArgument(Param, Arg,
+ FunctionTemplate,
+ FunctionTemplate->getLocation(),
+ FunctionTemplate->getSourceRange().getEnd(),
+ Builder,
+ Deduced[I].wasDeducedFromArrayBound()
+ ? CTAK_DeducedFromArrayBound
+ : CTAK_Deduced)) {
+ Info.Param = makeTemplateParameter(
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+ return TDK_SubstitutionFailure;
+ }
+
continue;
}
// Substitute into the default template argument, if available.
- NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
TemplateArgumentLoc DefArg
= SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
FunctionTemplate->getLocation(),
@@ -1279,7 +1399,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
- Builder)) {
+ Builder,
+ CTAK_Deduced)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
return TDK_SubstitutionFailure;
@@ -1390,7 +1511,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
// Type deduction is done independently for each P/A pair, and
// the deduced template argument values are then combined.
// So we do not reject deductions which were made elsewhere.
- llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size());
+ llvm::SmallVector<DeducedTemplateArgument, 8>
+ Deduced(TemplateParams->size());
Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
unsigned TDF = 0;
@@ -1458,10 +1580,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// The types of the parameters from which we will perform template argument
// deduction.
+ Sema::LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
llvm::SmallVector<QualType, 4> ParamTypes;
+ unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result =
SubstituteExplicitTemplateArguments(FunctionTemplate,
@@ -1472,6 +1596,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Info);
if (Result)
return Result;
+
+ NumExplicitlySpecified = Deduced.size();
} else {
// Just fill in the parameter types from the function declaration.
for (unsigned I = 0; I != CheckArgs; ++I)
@@ -1574,6 +1700,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ NumExplicitlySpecified,
Specialization, Info);
}
@@ -1612,7 +1739,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
QualType FunctionType = Function->getType();
// Substitute any explicit template arguments.
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Sema::LocalInstantiationScope InstScope(*this);
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+ unsigned NumExplicitlySpecified = 0;
llvm::SmallVector<QualType, 4> ParamTypes;
if (ExplicitTemplateArgs) {
if (TemplateDeductionResult Result
@@ -1621,6 +1750,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Deduced, ParamTypes,
&FunctionType, Info))
return Result;
+
+ NumExplicitlySpecified = Deduced.size();
}
// Template argument deduction for function templates in a SFINAE context.
@@ -1639,6 +1770,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ NumExplicitlySpecified,
Specialization, Info);
}
@@ -1707,7 +1839,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// A) as described in 14.8.2.4.
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.conv]p4:
@@ -1739,9 +1871,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// modulo the various allowed differences.
// Finish template argument deduction.
+ Sema::LocalInstantiationScope InstScope(*this);
FunctionDecl *Spec = 0;
TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+ = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,
+ Info);
Specialization = cast_or_null<CXXConversionDecl>(Spec);
return Result;
}
@@ -1799,11 +1933,11 @@ enum DeductionQualifierComparison {
/// but it may still fail, later, for other reasons.
static Sema::TemplateDeductionResult
DeduceTemplateArgumentsDuringPartialOrdering(Sema &S,
- TemplateParameterList *TemplateParams,
+ TemplateParameterList *TemplateParams,
QualType ParamIn, QualType ArgIn,
Sema::TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced,
- llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
CanQualType Param = S.Context.getCanonicalType(ParamIn);
CanQualType Arg = S.Context.getCanonicalType(ArgIn);
@@ -1877,7 +2011,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
assert(Proto1 && Proto2 && "Function templates must have prototypes");
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
// C++0x [temp.deduct.partial]p3:
@@ -2204,7 +2338,7 @@ Sema::getMoreSpecializedPartialSpecialization(
// computation is slightly simpler than the general problem of function
// template partial ordering, because class template partial specializations
// are more constrained. We know that every template parameter is deduc
- llvm::SmallVector<TemplateArgument, 4> Deduced;
+ llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
Sema::TemplateDeductionInfo Info(Context, Loc);
// Determine whether PS1 is at least as specialized as PS2
@@ -2421,10 +2555,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
- case Type::Typename:
+ case Type::DependentName:
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
- cast<TypenameType>(T)->getQualifier(),
+ cast<DependentNameType>(T)->getQualifier(),
OnlyDeduced, Depth, Used);
break;
@@ -2525,8 +2659,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// \brief Marks all of the template parameters that will be deduced by a
/// call to the given function template.
-void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallVectorImpl<bool> &Deduced) {
+void
+Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallVectorImpl<bool> &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 0d6acd0..d21862b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -394,7 +394,11 @@ void Sema::PrintInstantiationStack() {
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_explicit_template_arg_substitution_here)
- << FnTmpl << Active->InstantiationRange;
+ << FnTmpl
+ << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
break;
}
@@ -405,13 +409,21 @@ void Sema::PrintInstantiationStack() {
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_partial_spec_deduct_instantiation_here)
<< Context.getTypeDeclType(PartialSpec)
+ << getTemplateArgumentBindingsText(
+ PartialSpec->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
<< Active->InstantiationRange;
} else {
FunctionTemplateDecl *FnTmpl
= cast<FunctionTemplateDecl>((Decl *)Active->Entity);
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_function_template_deduction_instantiation_here)
- << FnTmpl << Active->InstantiationRange;
+ << FnTmpl
+ << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
+ Active->TemplateArgs,
+ Active->NumTemplateArgs)
+ << Active->InstantiationRange;
}
break;
@@ -677,8 +689,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T,
if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
<< Id
- << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
- TD->getKindName());
+ << FixItHint::CreateReplacement(SourceRange(TagLocation),
+ TD->getKindName());
SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
}
}
@@ -745,101 +757,13 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
DeclarationName());
assert(!TargetType.isNull() && "type substitution failed for param type");
assert(!TargetType->isDependentType() && "param type still dependent");
-
- if (VD->getDeclContext()->isRecord() &&
- (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
- // If the value is a class member, we might have a pointer-to-member.
- // Determine whether the non-type template template parameter is of
- // pointer-to-member type. If so, we need to build an appropriate
- // expression for a pointer-to-member, since a "normal" DeclRefExpr
- // would refer to the member itself.
- if (TargetType->isMemberPointerType()) {
- QualType ClassType
- = SemaRef.Context.getTypeDeclType(
- cast<RecordDecl>(VD->getDeclContext()));
- NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
- ClassType.getTypePtr());
- CXXScopeSpec SS;
- SS.setScopeRep(Qualifier);
- OwningExprResult RefExpr
- = SemaRef.BuildDeclRefExpr(VD,
- VD->getType().getNonReferenceType(),
- E->getLocation(),
- &SS);
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
- UnaryOperator::AddrOf,
- move(RefExpr));
- assert(!RefExpr.isInvalid() &&
- SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- TargetType));
- return move(RefExpr);
- }
- }
-
- QualType T = VD->getType().getNonReferenceType();
-
- if (TargetType->isPointerType()) {
- // C++03 [temp.arg.nontype]p5:
- // - For a non-type template-parameter of type pointer to
- // object, qualification conversions and the array-to-pointer
- // conversion are applied.
- // - For a non-type template-parameter of type pointer to
- // function, only the function-to-pointer conversion is
- // applied.
-
- OwningExprResult RefExpr
- = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
- if (RefExpr.isInvalid())
- return SemaRef.ExprError();
-
- // Decay functions and arrays.
- Expr *RefE = (Expr *)RefExpr.get();
- SemaRef.DefaultFunctionArrayConversion(RefE);
- if (RefE != RefExpr.get()) {
- RefExpr.release();
- RefExpr = SemaRef.Owned(RefE);
- }
-
- // Qualification conversions.
- RefExpr.release();
- SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
- CastExpr::CK_NoOp);
- return SemaRef.Owned(RefE);
- }
-
- // If the non-type template parameter has reference type, qualify the
- // resulting declaration reference with the extra qualifiers on the
- // type that the reference refers to.
- if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>())
- T = SemaRef.Context.getQualifiedType(T,
- TargetRef->getPointeeType().getQualifiers());
-
- return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+ return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
+ TargetType,
+ E->getLocation());
}
- assert(Arg.getKind() == TemplateArgument::Integral);
- QualType T = Arg.getIntegralType();
- if (T->isCharType() || T->isWideCharType())
- return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
- Arg.getAsIntegral()->getZExtValue(),
- T->isWideCharType(),
- T,
- E->getSourceRange().getBegin()));
- if (T->isBooleanType())
- return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral()->getBoolValue(),
- T,
- E->getSourceRange().getBegin()));
-
- assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
- return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
- *Arg.getAsIntegral(),
- T,
- E->getSourceRange().getBegin()));
+ return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg,
+ E->getSourceRange().getBegin());
}
@@ -873,8 +797,11 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
llvm::SmallVectorImpl<QualType> &PTypes,
llvm::SmallVectorImpl<ParmVarDecl*> &PVars) {
// Create a local instantiation scope for the parameters.
- Sema::LocalInstantiationScope
- Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0);
+ // FIXME: When we implement the C++0x late-specified return type,
+ // we will need to move this scope out to the function type itself.
+ bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0);
+ Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope,
+ IsTemporaryScope);
if (TreeTransform<TemplateInstantiator>::
TransformFunctionTypeParams(TL, PTypes, PVars))
@@ -1159,6 +1086,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
DeclContext *PreviousContext = CurContext;
CurContext = Instantiation;
+ // If this is an instantiation of a local class, merge this local
+ // instantiation scope with the enclosing scope. Otherwise, every
+ // instantiation of a class has its own local instantiation scope.
+ bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
+ Sema::LocalInstantiationScope Scope(*this, MergeWithParentScope);
+
// Start the definition of this instantiation.
Instantiation->startDefinition();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index dbe041c..3375ccc 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
@@ -285,17 +286,19 @@ static bool InstantiateInitializer(Sema &S, Expr *Init,
}
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) {
- if (InstantiateInitializationArguments(S,
- Construct->getArgs(),
- Construct->getNumArgs(),
- TemplateArgs,
- CommaLocs, NewArgs))
- return true;
-
- // FIXME: Fake locations!
- LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
- RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back();
- return false;
+ if (!isa<CXXTemporaryObjectExpr>(Construct)) {
+ if (InstantiateInitializationArguments(S,
+ Construct->getArgs(),
+ Construct->getNumArgs(),
+ TemplateArgs,
+ CommaLocs, NewArgs))
+ return true;
+
+ // FIXME: Fake locations!
+ LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart());
+ RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back();
+ return false;
+ }
}
Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs);
@@ -477,13 +480,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// Handle friend type expressions by simply substituting template
// parameters into the pattern type.
- if (Type *Ty = D->getFriendType()) {
- QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
- D->getLocation(), DeclarationName());
- if (T.isNull()) return 0;
+ if (TypeSourceInfo *Ty = D->getFriendType()) {
+ TypeSourceInfo *InstTy =
+ SemaRef.SubstType(Ty, TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (!InstTy) return 0;
+
+ // This assertion is valid because the source type was necessarily
+ // an elaborated-type-specifier with a record tag.
+ assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType());
- assert(getLangOptions().CPlusPlus0x || T->isRecordType());
- FU = T.getTypePtr();
+ FU = InstTy;
// Handle everything else by appropriate substitution.
} else {
@@ -496,22 +503,12 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
Decl *NewND;
// Hack to make this work almost well pending a rewrite.
- if (ND->getDeclContext()->isRecord()) {
- if (!ND->getDeclContext()->isDependentContext()) {
- NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND,
- TemplateArgs);
- } else {
- // FIXME: Hack to avoid crashing when incorrectly trying to instantiate
- // templated friend declarations. This doesn't produce a correct AST;
- // however this is sufficient for some AST analysis. The real solution
- // must be put in place during the pending rewrite. See PR5848.
- return 0;
- }
- } else if (D->wasSpecialization()) {
+ if (D->wasSpecialization()) {
// Totally egregious hack to work around PR5866
return 0;
- } else
+ } else {
NewND = Visit(ND);
+ }
if (!NewND) return 0;
FU = cast<NamedDecl>(NewND);
@@ -638,6 +635,8 @@ namespace {
}
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
// Create a local instantiation scope for this class template, which
// will contain the instantiations of the template parameters.
Sema::LocalInstantiationScope Scope(SemaRef);
@@ -647,32 +646,106 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return NULL;
CXXRecordDecl *Pattern = D->getTemplatedDecl();
+
+ // Instantiate the qualifier. We have to do this first in case
+ // we're a friend declaration, because if we are then we need to put
+ // the new declaration in the appropriate context.
+ NestedNameSpecifier *Qualifier = Pattern->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ Pattern->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
+ CXXRecordDecl *PrevDecl = 0;
+ ClassTemplateDecl *PrevClassTemplate = 0;
+
+ // If this isn't a friend, then it's a member template, in which
+ // case we just want to build the instantiation in the
+ // specialization. If it is a friend, we want to build it in
+ // the appropriate context.
+ DeclContext *DC = Owner;
+ if (isFriend) {
+ if (Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(Pattern->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ if (!DC) return 0;
+ } else {
+ DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(),
+ Pattern->getDeclContext(),
+ TemplateArgs);
+ }
+
+ // Look for a previous declaration of the template in the owning
+ // context.
+ LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
+ Sema::LookupOrdinaryName, Sema::ForRedeclaration);
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (R.isSingleResult()) {
+ PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>();
+ if (PrevClassTemplate)
+ PrevDecl = PrevClassTemplate->getTemplatedDecl();
+ }
+
+ if (!PrevClassTemplate && Qualifier) {
+ SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
+ << D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC
+ << Pattern->getQualifierRange();
+ return 0;
+ }
+
+ if (PrevClassTemplate) {
+ TemplateParameterList *PrevParams
+ = PrevClassTemplate->getTemplateParameters();
+
+ // Make sure the parameter lists match.
+ if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams,
+ /*Complain=*/true,
+ Sema::TPL_TemplateMatch))
+ return 0;
+
+ // Do some additional validation, then merge default arguments
+ // from the existing declarations.
+ if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
+ Sema::TPC_ClassTemplate))
+ return 0;
+ }
+ }
+
CXXRecordDecl *RecordInst
- = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+ = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC,
Pattern->getLocation(), Pattern->getIdentifier(),
- Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
+ Pattern->getTagKeywordLoc(), PrevDecl,
/*DelayTypeCreation=*/true);
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(Pattern, RecordInst))
- return 0;
+ if (Qualifier)
+ RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange());
ClassTemplateDecl *Inst
- = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getIdentifier(), InstParams, RecordInst, 0);
+ = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst,
+ PrevClassTemplate);
RecordInst->setDescribedClassTemplate(Inst);
- if (D->getFriendObjectKind())
- Inst->setObjectOfFriendDecl(true);
- else
+ if (isFriend) {
+ Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
+ // TODO: do we want to track the instantiation progeny of this
+ // friend target decl?
+ } else {
Inst->setAccess(D->getAccess());
- Inst->setInstantiatedFromMemberTemplate(D);
+ Inst->setInstantiatedFromMemberTemplate(D);
+ }
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(RecordInst,
Inst->getInjectedClassNameSpecialization(SemaRef.Context));
// Finish handling of friends.
- if (Inst->getFriendObjectKind()) {
+ if (isFriend) {
+ DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false);
return Inst;
}
@@ -762,16 +835,18 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
assert(InstTemplate &&
"VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None);
+
// Link the instantiation back to the pattern *unless* this is a
// non-definition friend declaration.
if (!InstTemplate->getInstantiatedFromMemberTemplate() &&
- !(InstTemplate->getFriendObjectKind() &&
- !D->getTemplatedDecl()->isThisDeclarationADefinition()))
+ !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition()))
InstTemplate->setInstantiatedFromMemberTemplate(D);
- // Add non-friends into the owner.
- if (!InstTemplate->getFriendObjectKind())
+ // Make declarations visible in the appropriate context.
+ if (!isFriend)
Owner->addDecl(InstTemplate);
+
return InstTemplate;
}
@@ -843,6 +918,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -855,14 +936,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
// If we're instantiating a local function declaration, put the result
// in the owner; otherwise we need to find the instantiated context.
DeclContext *DC;
if (D->getDeclContext()->isFunctionOrMethod())
DC = Owner;
- else
+ else if (isFriend && Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ if (!DC) return 0;
+ } else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
+ }
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -870,11 +966,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype());
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Function))
- return 0;
+ if (Qualifier)
+ Function->setQualifierInfo(Qualifier, D->getQualifierRange());
- Function->setLexicalDeclContext(Owner);
+ DeclContext *LexicalDC = Owner;
+ if (!isFriend && D->isOutOfLine()) {
+ assert(D->getDeclContext()->isFileContext());
+ LexicalDC = D->getDeclContext();
+ }
+
+ Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
@@ -896,17 +997,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// which means substituting int for T, but leaving "f" as a friend function
// template.
// Build the function template itself.
- FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC,
Function->getLocation(),
Function->getDeclName(),
TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate);
- FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+
+ FunctionTemplate->setLexicalDeclContext(LexicalDC);
+
+ if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ FunctionTemplate->setInstantiatedFromMemberTemplate(
+ D->getDescribedFunctionTemplate());
+ }
} else if (FunctionTemplate) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
+ } else if (isFriend && D->isThisDeclarationADefinition()) {
+ // TODO: should we remember this connection regardless of whether
+ // the friend declaration provided a body?
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
if (InitFunctionInstantiation(Function, D))
@@ -938,9 +1051,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
- NamedDecl *FromFriendD
- = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
- if (FromFriendD->getFriendObjectKind()) {
+ if (isFriend) {
NamedDecl *ToFriendD = 0;
NamedDecl *PrevDecl;
if (TemplateParams) {
@@ -951,11 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrevDecl = Function->getPreviousDeclaration();
}
ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
- if (!Owner->isDependentContext() && !PrevDecl)
- DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
-
- if (!TemplateParams)
- Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
}
return Function;
@@ -985,6 +1092,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return Info->Function;
}
+ bool isFriend;
+ if (FunctionTemplate)
+ isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+ else
+ isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
bool MergeWithParentScope = (TemplateParams != 0) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -997,8 +1110,31 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return 0;
QualType T = TInfo->getType();
+ NestedNameSpecifier *Qualifier = D->getQualifier();
+ if (Qualifier) {
+ Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+ D->getQualifierRange(),
+ TemplateArgs);
+ if (!Qualifier) return 0;
+ }
+
+ DeclContext *DC = Owner;
+ if (isFriend) {
+ if (Qualifier) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(Qualifier);
+ SS.setRange(D->getQualifierRange());
+ DC = SemaRef.computeDeclContext(SS);
+ } else {
+ DC = SemaRef.FindInstantiatedContext(D->getLocation(),
+ D->getDeclContext(),
+ TemplateArgs);
+ }
+ if (!DC) return 0;
+ }
+
// Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = 0;
DeclarationName Name = D->getDeclName();
@@ -1035,9 +1171,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isStatic(), D->isInlineSpecified());
}
- // Substitute the nested name specifier, if any.
- if (SubstQualifier(D, Method))
- return 0;
+ if (Qualifier)
+ Method->setQualifierInfo(Qualifier, D->getQualifierRange());
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
@@ -1057,7 +1192,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->getLocation(),
Method->getDeclName(),
TemplateParams, Method);
- if (D->isOutOfLine())
+ if (isFriend) {
+ FunctionTemplate->setLexicalDeclContext(Owner);
+ FunctionTemplate->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
@@ -1065,7 +1203,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setFunctionTemplateSpecialization(FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
- } else {
+ } else if (!isFriend) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
@@ -1073,7 +1211,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
- if (D->isOutOfLine())
+ if (isFriend) {
+ Method->setLexicalDeclContext(Owner);
+ Method->setObjectOfFriendDecl(true);
+ } else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
@@ -1087,8 +1228,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
LookupResult Previous(SemaRef, Name, SourceLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- if (!FunctionTemplate || TemplateParams) {
- SemaRef.LookupQualifiedName(Previous, Owner);
+ if (!FunctionTemplate || TemplateParams || isFriend) {
+ SemaRef.LookupQualifiedName(Previous, Record);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
@@ -1108,9 +1249,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Method->setAccess(D->getAccess());
- if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
- !Method->getFriendObjectKind())
- Owner->addDecl(Method);
+ if (FunctionTemplate) {
+ // If there's a function template, let our caller handle it.
+ } else if (Method->isInvalidDecl() && !Previous.empty()) {
+ // Don't hide a (potentially) valid declaration with an invalid one.
+ } else {
+ NamedDecl *DeclToAdd = (TemplateParams
+ ? cast<NamedDecl>(FunctionTemplate)
+ : Method);
+ if (isFriend)
+ Record->makeDeclVisibleInContext(DeclToAdd);
+ else
+ Owner->addDecl(DeclToAdd);
+ }
return Method;
}
@@ -1694,8 +1845,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
- Proto->getNoReturnAttr(),
- Proto->getCallConv()));
+ Proto->getExtInfo()));
}
return false;
@@ -1839,6 +1989,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
+ PerformDependentDiagnostics(PatternDecl, TemplateArgs);
+
CurContext = PreviousContext;
DeclGroupRef DG(Function);
@@ -2475,3 +2627,17 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}
+
+void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ for (DeclContext::ddiag_iterator I = Pattern->ddiag_begin(),
+ E = Pattern->ddiag_end(); I != E; ++I) {
+ DependentDiagnostic *DD = *I;
+
+ switch (DD->getKind()) {
+ case DependentDiagnostic::Access:
+ HandleDependentAccessCheck(*DD, TemplateArgs);
+ break;
+ }
+ }
+}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index a79853a..8278691 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -183,8 +183,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema,
if (DS.isEmpty()) {
TheSema.Diag(DeclLoc, diag::ext_missing_declspec)
<< DS.getSourceRange()
- << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(),
- "int");
+ << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int");
}
} else if (!DS.hasTypeSpecifier()) {
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
@@ -680,8 +679,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
if (ConstVal == 0) {
- // GCC accepts zero sized static arrays.
- Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
+ // GCC accepts zero sized static arrays. We allow them when
+ // we're not in a SFINAE context.
+ Diag(ArraySize->getLocStart(),
+ isSFINAEContext()? diag::err_typecheck_zero_array_size
+ : diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
}
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
@@ -798,7 +800,8 @@ QualType Sema::BuildFunctionType(QualType T,
return QualType();
return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- Quals, false, false, 0, 0, false, CC_Default);
+ Quals, false, false, 0, 0,
+ FunctionType::ExtInfo());
}
/// \brief Build a member pointer type \c T Class::*.
@@ -1135,7 +1138,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data(),
- false, CC_Default);
+ FunctionType::ExtInfo());
} else if (FTI.isVariadic) {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable"
@@ -1152,7 +1155,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (!Overloadable)
Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0,
+ FunctionType::ExtInfo());
} else {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
@@ -1228,7 +1232,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasExceptionSpec,
FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data(),
- false, CC_Default);
+ FunctionType::ExtInfo());
}
// For GCC compatibility, we allow attributes that apply only to
@@ -1257,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
- ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier());
+ ClsType = Context.getDependentNameType(ETK_None, NNSPrefix,
+ NNS->getAsIdentifier());
break;
case NestedNameSpecifier::Namespace:
@@ -1326,7 +1331,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Strip the cv-quals from the type.
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
FnTy->getNumArgs(), FnTy->isVariadic(), 0,
- false, false, 0, 0, false, CC_Default);
+ false, false, 0, 0, FunctionType::ExtInfo());
}
}
@@ -1734,6 +1739,30 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
return false;
}
+ if (Attr.getKind() == AttributeList::AT_regparm) {
+ // The warning is emitted elsewhere
+ if (Attr.getNumArgs() != 1) {
+ return false;
+ }
+
+ // Delay if this is not a function or pointer to block.
+ if (!Type->isFunctionPointerType()
+ && !Type->isBlockPointerType()
+ && !Type->isFunctionType())
+ return true;
+
+ // Otherwise we can process right away.
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt NumParams(32);
+
+ // The warning is emitted elsewhere
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context))
+ return false;
+
+ Type = S.Context.getRegParmType(Type, NumParams.getZExtValue());
+ return false;
+ }
+
// Otherwise, a calling convention.
if (Attr.getNumArgs() != 0) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -1863,6 +1892,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result,
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
case AttributeList::AT_stdcall:
+ case AttributeList::AT_regparm:
// Don't process these on the DeclSpec.
if (IsDeclSpec ||
ProcessFnAttr(S, Result, *AL))
@@ -1942,6 +1972,16 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
if (diag == 0)
return true;
+ const TagType *Tag = 0;
+ if (const RecordType *Record = T->getAs<RecordType>())
+ Tag = Record;
+ else if (const EnumType *Enum = T->getAs<EnumType>())
+ Tag = Enum;
+
+ // Avoid diagnosing invalid decls as incomplete.
+ if (Tag && Tag->getDecl()->isInvalidDecl())
+ return true;
+
// We have an incomplete type. Produce a diagnostic.
Diag(Loc, PD) << T;
@@ -1950,13 +1990,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
Diag(Note.first, Note.second);
// If the type was a forward declaration of a class/struct/union
- // type, produce
- const TagType *Tag = 0;
- if (const RecordType *Record = T->getAs<RecordType>())
- Tag = Record;
- else if (const EnumType *Enum = T->getAs<EnumType>())
- Tag = Enum;
-
+ // type, produce a note.
if (Tag && !Tag->getDecl()->isInvalidDecl())
Diag(Tag->getDecl()->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
@@ -1966,6 +2000,18 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return true;
}
+bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+ const PartialDiagnostic &PD) {
+ return RequireCompleteType(Loc, T, PD,
+ std::make_pair(SourceLocation(), PDiag(0)));
+}
+
+bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+ unsigned DiagID) {
+ return RequireCompleteType(Loc, T, PDiag(DiagID),
+ std::make_pair(SourceLocation(), PDiag(0)));
+}
+
/// \brief Retrieve a version of the type 'T' that is qualified by the
/// nested-name-specifier contained in SS.
QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
@@ -1983,7 +2029,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization);
+ E = FixOverloadedFunctionReference(E, Specialization, Specialization);
if (!E)
return QualType();
} else {
@@ -2003,7 +2049,7 @@ QualType Sema::BuildDecltypeType(Expr *E) {
// function template specialization wherever deduction cannot occur.
if (FunctionDecl *Specialization
= ResolveSingleFunctionTemplateSpecialization(E)) {
- E = FixOverloadedFunctionReference(E, Specialization);
+ E = FixOverloadedFunctionReference(E, Specialization, Specialization);
if (!E)
return QualType();
} else {
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index d6f3352..f9ffd3f 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -537,18 +537,22 @@ public:
/// \brief Build a new typename type that refers to a template-id.
///
- /// By default, builds a new TypenameType type from the nested-name-specifier
+ /// By default, builds a new DependentNameType type from the
+ /// nested-name-specifier
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) {
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
CXXScopeSpec SS;
SS.setScopeRep(NNS);
if (!SemaRef.computeDeclContext(SS))
- return SemaRef.Context.getTypenameType(NNS,
+ return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
-
+
+ // FIXME: Handle elaborated-type-specifiers separately.
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -557,10 +561,80 @@ public:
/// By default, performs semantic analysis when building the typename type
/// (or qualified name type). Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildTypenameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Id,
- SourceRange SR) {
- return SemaRef.CheckTypenameType(NNS, *Id, SR);
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Id,
+ SourceRange SR) {
+ CXXScopeSpec SS;
+ SS.setScopeRep(NNS);
+
+ if (NNS->isDependent()) {
+ // If the name is still dependent, just build a new dependent name type.
+ if (!SemaRef.computeDeclContext(SS))
+ return SemaRef.Context.getDependentNameType(Keyword, NNS, Id);
+ }
+
+ TagDecl::TagKind Kind = TagDecl::TK_enum;
+ switch (Keyword) {
+ case ETK_None:
+ // FIXME: Note the lack of the "typename" specifier!
+ // Fall through
+ case ETK_Typename:
+ return SemaRef.CheckTypenameType(NNS, *Id, SR);
+
+ case ETK_Class: Kind = TagDecl::TK_class; break;
+ case ETK_Struct: Kind = TagDecl::TK_struct; break;
+ case ETK_Union: Kind = TagDecl::TK_union; break;
+ case ETK_Enum: Kind = TagDecl::TK_enum; break;
+ }
+
+ // We had a dependent elaborated-type-specifier that as been transformed
+ // into a non-dependent elaborated-type-specifier. Find the tag we're
+ // referring to.
+ LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName);
+ DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+ if (!DC)
+ return QualType();
+
+ TagDecl *Tag = 0;
+ SemaRef.LookupQualifiedName(Result, DC);
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ break;
+
+ case LookupResult::Found:
+ Tag = Result.getAsSingle<TagDecl>();
+ break;
+
+ case LookupResult::FoundOverloaded:
+ case LookupResult::FoundUnresolvedValue:
+ llvm_unreachable("Tag lookup cannot find non-tags");
+ return QualType();
+
+ case LookupResult::Ambiguous:
+ // Let the LookupResult structure handle ambiguities.
+ return QualType();
+ }
+
+ if (!Tag) {
+ // FIXME: Would be nice to highlight just the source range.
+ SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope)
+ << Kind << Id << DC;
+ return QualType();
+ }
+
+ // FIXME: Terrible location information
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) {
+ SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id;
+ SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
+ return QualType();
+ }
+
+ // Build the elaborated-type-specifier type.
+ QualType T = SemaRef.Context.getTypeDeclType(Tag);
+ T = SemaRef.Context.getQualifiedNameType(NNS, T);
+ return SemaRef.Context.getElaboratedType(T, Kind);
}
/// \brief Build a new nested-name-specifier given the prefix and an
@@ -977,6 +1051,7 @@ public:
SourceRange QualifierRange,
SourceLocation MemberLoc,
ValueDecl *Member,
+ NamedDecl *FoundDecl,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
NamedDecl *FirstQualifierInScope) {
if (!Member->getDeclName()) {
@@ -984,7 +1059,8 @@ public:
assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
Expr *BaseExpr = Base.takeAs<Expr>();
- if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, Member))
+ if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier,
+ FoundDecl, Member))
return getSema().ExprError();
MemberExpr *ME =
@@ -1002,9 +1078,11 @@ public:
QualType BaseType = ((Expr*) Base.get())->getType();
+ // FIXME: this involves duplicating earlier analysis in a lot of
+ // cases; we should avoid this when possible.
LookupResult R(getSema(), Member->getDeclName(), MemberLoc,
Sema::LookupMemberName);
- R.addDecl(Member);
+ R.addDecl(FoundDecl);
R.resolveKind();
return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
@@ -2992,10 +3070,10 @@ TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
- TypenameTypeLoc TL,
+QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
+ DependentNameTypeLoc TL,
QualType ObjectType) {
- TypenameType *T = TL.getTypePtr();
+ DependentNameType *T = TL.getTypePtr();
/* FIXME: preserve source information better than this */
SourceRange SR(TL.getNameLoc());
@@ -3019,14 +3097,16 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
- Result = getDerived().RebuildTypenameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ NewTemplateId);
} else {
- Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(), SR);
}
if (Result.isNull())
return QualType();
- TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result);
+ DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
@@ -3868,10 +3948,21 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
if (!Member)
return SemaRef.ExprError();
+ NamedDecl *FoundDecl = E->getFoundDecl();
+ if (FoundDecl == E->getMemberDecl()) {
+ FoundDecl = Member;
+ } else {
+ FoundDecl = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getMemberLoc(), FoundDecl));
+ if (!FoundDecl)
+ return SemaRef.ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase() &&
Qualifier == E->getQualifier() &&
Member == E->getMemberDecl() &&
+ FoundDecl == E->getFoundDecl() &&
!E->hasExplicitTemplateArgumentList()) {
// Mark it referenced in the new context regardless.
@@ -3908,6 +3999,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
E->getQualifierRange(),
E->getMemberLoc(),
Member,
+ FoundDecl,
(E->hasExplicitTemplateArgumentList()
? &TransArgs : 0),
FirstQualifierInScope);
@@ -5118,7 +5210,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
!ArgumentChanged) {
// FIXME: Instantiation-specific
SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor);
- return SemaRef.Owned(E->Retain());
+ return SemaRef.MaybeBindToTemporary(E->Retain());
}
// FIXME: Bogus location information
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 3fed57e..c1f238c 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -35,22 +35,16 @@ typedef struct _NSZone NSZone;
@protocol IHGoogleDocsAdapterDelegate - (void)googleDocsAdapter:(IHGoogleDocsAdapter*)inGoogleDocsAdapter accountVerifyIsValid:(BOOL)inIsValid error:(NSError *)inError;
@end @interface IHGoogleDocsAdapter : NSObject {
}
-- (NSArray *)entries;
+- (NSArray *)entries; // expected-note {{method definition for 'entries' not found}}
@end extern Class const kGDataUseRegisteredClass ;
-@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList;
-- (NSArray *)directoryPathComponents;
-- (unsigned int)currentPathComponentIndex;
-- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex;
-- (NSURL *)folderFeedURL;
+@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList; // expected-note {{method definition for 'feedDocList' not found}}
+- (NSArray *)directoryPathComponents; // expected-note {{method definition for 'directoryPathComponents' not found}}
+- (unsigned int)currentPathComponentIndex; // expected-note {{method definition for 'currentPathComponentIndex' not found}}
+- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex; // expected-note {{method definition for 'setCurrentPathComponentIndex:' not found}}
+- (NSURL *)folderFeedURL; // expected-note {{method definition for 'folderFeedURL' not found}}
@end
-@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { // expected-warning {{incomplete implementation}} \
-// expected-warning {{method definition for 'entries' not found}} \
-// expected-warning {{method definition for 'feedDocList' not found}} \
-// expected-warning {{method definition for 'directoryPathComponents' not found}} \
-// expected-warning {{method definition for 'currentPathComponentIndex' not found}} \
-// expected-warning {{method definition for 'setCurrentPathComponentIndex:' not found}} \
-// expected-warning {{method definition for 'folderFeedURL' not found}}
+@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { // expected-warning {{incomplete implementation}}
return 0;
}
diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c
index 13d4f7f..952de73 100644
--- a/test/Analysis/inline.c
+++ b/test/Analysis/inline.c
@@ -15,6 +15,6 @@ void f2() {
}
if (x == 2) {
int *p = 0;
- *p = 3; // expected-warning{{Dereference of null pointer loaded from variable}}
+ *p = 3; // expected-warning{{Dereference of null pointer (loaded from variable 'p')}}
}
}
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index 898a33e..d10b9fa 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -910,3 +910,48 @@ int rdar_7770737_pos(void)
struct rdar_7770737_s f = { .p = (intptr_t)&x };
return x; // expected-warning{{Undefined or garbage value returned to caller}}
}
+
+//===----------------------------------------------------------------------===//
+// Test handling of the implicit 'isa' field. For now we don't do anything
+// interesting.
+//===----------------------------------------------------------------------===//
+
+void pr6302(id x, Class y) {
+ // This previously crashed the analyzer (reported in PR 6302)
+ x->isa = y;
+}
+
+//===----------------------------------------------------------------------===//
+// Specially handle global variables that are declared constant. In the
+// example below, this forces the loop to take exactly 2 iterations.
+//===----------------------------------------------------------------------===//
+
+const int pr6288_L_N = 2;
+void pr6288_(void) {
+ int x[2];
+ int *px[2];
+ int i;
+ for (i = 0; i < pr6288_L_N; i++)
+ px[i] = &x[i];
+ *(px[0]) = 0; // no-warning
+}
+
+void pr6288_pos(int z) {
+ int x[2];
+ int *px[2];
+ int i;
+ for (i = 0; i < z; i++)
+ px[i] = &x[i]; // expected-warning{{Access out-of-bound array element (buffer overflow)}}
+ *(px[0]) = 0; // expected-warning{{Dereference of undefined pointer value}}
+}
+
+void pr6288_b(void) {
+ const int L_N = 2;
+ int x[2];
+ int *px[2];
+ int i;
+ for (i = 0; i < L_N; i++)
+ px[i] = &x[i];
+ *(px[0]) = 0; // no-warning
+}
+
diff --git a/test/Analysis/no-outofbounds.c b/test/Analysis/no-outofbounds.c
index f9ac589..771323b 100644
--- a/test/Analysis/no-outofbounds.c
+++ b/test/Analysis/no-outofbounds.c
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-experimental-internal-checks -analyzer-store=basic -verify %s
// RUN: %clang_cc1 -analyzer-check-objc-mem -analyze -analyzer-experimental-internal-checks -analyzer-store=region -verify %s
-// XFAIL: *
//===----------------------------------------------------------------------===//
// This file tests cases where we should not flag out-of-bounds warnings.
@@ -10,4 +9,6 @@ void f() {
long x = 0;
char *y = (char*) &x;
char c = y[0] + y[1] + y[2]; // no-warning
+ short *z = (short*) &x;
+ short s = z[0] + z[1]; // no-warning
}
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 704ad33..5376ca0 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -26,7 +26,7 @@ int f2(struct foo_struct* p) {
if (p)
p->x = 1;
- return p->x++; // expected-warning{{Dereference of null pointer}}
+ return p->x++; // expected-warning{{Field access results in a dereference of a null pointer (loaded from variable 'p')}}
}
int f3(char* x) {
@@ -57,7 +57,7 @@ int f4(int *p) {
return 1;
int *q = (int*) x;
- return *q; // expected-warning{{Dereference of null pointer loaded from variable 'q'}}
+ return *q; // expected-warning{{Dereference of null pointer (loaded from variable 'q')}}
}
int f4_b() {
diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c
index 45325e9..e1ff66c 100644
--- a/test/Analysis/outofbound.c
+++ b/test/Analysis/outofbound.c
@@ -13,3 +13,26 @@ void f2() {
int *p = malloc(12);
p[3] = 4; // expected-warning{{Access out-of-bound array element (buffer overflow)}}
}
+
+struct three_words {
+ int c[3];
+};
+
+struct seven_words {
+ int c[7];
+};
+
+void f3() {
+ struct three_words a, *p;
+ p = &a;
+ p[0] = a; // no-warning
+ p[1] = a; // expected-warning{{Access out-of-bound array element (buffer overflow)}}
+}
+
+void f4() {
+ struct seven_words c;
+ struct three_words a, *p = (struct three_words *)&c;
+ p[0] = a; // no-warning
+ p[1] = a; // no-warning
+ p[2] = a; // expected-warning{{Access out-of-bound array element (buffer overflow)}}
+}
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index f49fef5..aa866de 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -124,7 +124,7 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>5</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
@@ -135,12 +135,12 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
@@ -262,7 +262,7 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>11</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
@@ -273,12 +273,12 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
@@ -400,7 +400,7 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>18</integer>
-// CHECK: <key>col</key><integer>3</integer>
+// CHECK: <key>col</key><integer>4</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
@@ -411,12 +411,12 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;q&apos;</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;q&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
@@ -538,7 +538,7 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>23</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
@@ -549,12 +549,12 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
@@ -710,7 +710,7 @@ void test_null_field(void) {
// CHECK: <array>
// CHECK: <dict>
// CHECK: <key>line</key><integer>30</integer>
-// CHECK: <key>col</key><integer>5</integer>
+// CHECK: <key>col</key><integer>6</integer>
// CHECK: <key>file</key><integer>0</integer>
// CHECK: </dict>
// CHECK: <dict>
@@ -721,12 +721,12 @@ void test_null_field(void) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>message</key>
-// CHECK: <string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: </dict>
// CHECK: </array>
-// CHECK: <key>description</key><string>Dereference of null pointer loaded from variable &apos;p&apos;</string>
+// CHECK: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
// CHECK: <key>category</key><string>Logic error</string>
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>location</key>
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index eb01015..dc1ef7b 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -48,16 +48,14 @@ CMProfileLocation;
@interface GBCategoryChooserPanelController : NSWindowController {
GSEbayCategory *rootCategory;
}
-- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories;
--(NSString*) categoryID;
+- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; // expected-note {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}}
+-(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}}
@end @interface GSEbayCategory : NSObject <NSCoding> {
}
- (int) categoryID;
- (GSEbayCategory *) parent;
- (GSEbayCategory*) subcategoryWithID:(int) inID;
-@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}} \
-// expected-warning {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}} \
-// expected-warning {{method definition for 'categoryID' not found}}
+@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}}
return 0;
}
- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
diff --git a/test/Analysis/retain-release-region-store.m b/test/Analysis/retain-release-region-store.m
index 111d4b9..db49b91 100644
--- a/test/Analysis/retain-release-region-store.m
+++ b/test/Analysis/retain-release-region-store.m
@@ -207,3 +207,19 @@ void rdar7283470_2_positive(void) {
[numbers[i] release];
}
+void pr6699(int x) {
+ CFDateRef values[2];
+ values[0] = values[1] = 0;
+
+ if (x) {
+ CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+ values[1] = CFDateCreate(0, t);
+ }
+
+ if (values[1]) {
+ // A bug in RegionStore::RemoveDeadBindings caused 'values[1]' to get prematurely
+ // pruned from the store.
+ CFRelease(values[1]); // no-warning
+ }
+}
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 675e9a6..3f79c0c 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1268,6 +1268,7 @@ CFDateRef returnsRetainedCFDate() {
//===----------------------------------------------------------------------===//
void panic() __attribute__((noreturn));
+void panic_not_in_hardcoded_list() __attribute__((noreturn));
void test_panic_negative() {
signed z = 1;
@@ -1291,9 +1292,13 @@ void test_panic_pos_2(int x) {
signed z = 1;
CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
if (x)
- panic();
- if (!x)
panic();
+ if (!x) {
+ // This showed up in <rdar://problem/7796563>, where we silently missed checking
+ // the function type for noreturn. "panic()" is a hard-coded known panic function
+ // that isn't always noreturn.
+ panic_not_in_hardcoded_list();
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/uninit-vals-ps-region.m b/test/Analysis/uninit-vals-ps-region.m
index 7e2fff9..69c1ecd 100644
--- a/test/Analysis/uninit-vals-ps-region.m
+++ b/test/Analysis/uninit-vals-ps-region.m
@@ -59,4 +59,11 @@ void testFoo(Foo *o) {
[o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
}
+// Test case from <rdar://problem/7780304>. That shows an uninitialized value
+// being used in the LHS of a compound assignment.
+void rdar_7780304() {
+ typedef struct s_r7780304 { int x; } s_r7780304;
+ s_r7780304 b;
+ b.x |= 1; // expected-warning{{The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage}}
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
index b59e6ca..df3429e 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -40,3 +40,15 @@ namespace Test {
D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }}
}
}
+
+// PR6716
+namespace test1 {
+ template <class T> class A {
+ template <class U> friend void foo(A &, U); // expected-note {{not viable: 1st argument ('A<int> const') would lose const qualifier}}
+ };
+
+ void test() {
+ const A<int> a;
+ foo(a, 10); // expected-error {{no matching function for call to 'foo'}}
+ }
+}
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp
new file mode 100644
index 0000000..4567c46
--- /dev/null
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2-noexceptions.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+namespace std {
+ class bad_alloc { };
+
+ typedef __SIZE_TYPE__ size_t;
+}
+
+class foo { virtual ~foo(); };
+
+void* operator new(std::size_t);
+void* operator new[](std::size_t);
+void operator delete(void*);
+void operator delete[](void*);
diff --git a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
index f4860bb..37a4f97 100644
--- a/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
+++ b/test/CXX/basic/basic.stc/basic.stc.dynamic/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fexceptions -verify %s
int *use_new(int N) {
if (N == 1)
return new int;
@@ -19,7 +19,10 @@ namespace std {
typedef __SIZE_TYPE__ size_t;
}
-void* operator new(std::size_t) throw(std::bad_alloc);
+void* operator new(std::size_t) throw(std::bad_alloc); // expected-note{{previous declaration}}
void* operator new[](std::size_t) throw(std::bad_alloc);
-void operator delete(void*) throw();
+void operator delete(void*) throw(); // expected-note{{previous declaration}}
void operator delete[](void*) throw();
+
+void* operator new(std::size_t); // expected-warning{{'operator new' is missing exception specification 'throw(std::bad_alloc)'}}
+void operator delete(void*); // expected-warning{{'operator delete' is missing exception specification 'throw()'}}
diff --git a/test/CXX/class.access/class.access.base/p5.cpp b/test/CXX/class.access/class.access.base/p5.cpp
new file mode 100644
index 0000000..96037e7
--- /dev/null
+++ b/test/CXX/class.access/class.access.base/p5.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -faccess-control -verify %s
+
+namespace test0 {
+ struct A {
+ static int x;
+ };
+ struct B : A {};
+ struct C : B {};
+
+ int test() {
+ return A::x
+ + B::x
+ + C::x;
+ }
+}
+
+namespace test1 {
+ struct A {
+ private: static int x; // expected-note 5 {{declared private here}}
+ static int test() { return x; }
+ };
+ struct B : public A {
+ static int test() { return x; } // expected-error {{private member}}
+ };
+ struct C : private A {
+ static int test() { return x; } // expected-error {{private member}}
+ };
+
+ struct D {
+ public: static int x;
+ static int test() { return x; }
+ };
+ struct E : private D { // expected-note{{constrained by private inheritance}}
+ static int test() { return x; }
+ };
+
+ int test() {
+ return A::x // expected-error {{private member}}
+ + B::x // expected-error {{private member}}
+ + C::x // expected-error {{private member}}
+ + D::x
+ + E::x; // expected-error {{private member}}
+ }
+}
+
+namespace test2 {
+ class A {
+ protected: static int x;
+ };
+
+ class B : private A {}; // expected-note {{private inheritance}}
+ class C : private A {
+ int test(B *b) {
+ return b->x; // expected-error {{private member}}
+ }
+ };
+}
+
+namespace test3 {
+ class A {
+ protected: static int x;
+ };
+
+ class B : public A {};
+ class C : private A {
+ int test(B *b) {
+ // x is accessible at C when named in A.
+ // A is an accessible base of B at C.
+ // Therefore this succeeds.
+ return b->x;
+ }
+ };
+}
+
+// TODO: flesh out these cases
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 851cd3d..22266cd 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -149,3 +149,46 @@ namespace test2 {
// expected-error {{'getNext' is a private member of 'test2::ilist_node'}}
};
}
+
+namespace test3 {
+ class A { protected: int x; }; // expected-note {{declared protected here}}
+
+ class B : public A {
+ friend int foo(B*);
+ };
+
+ int foo(B *p) {
+ return p->x;
+ }
+
+ int foo(const B *p) {
+ return p->x; // expected-error {{'x' is a protected member of 'test3::A'}}
+ }
+}
+
+namespace test3a {
+ class A { protected: int x; };
+
+ class B : public A {
+ friend int foo(B*);
+ };
+
+ int foo(B * const p) {
+ return p->x;
+ }
+}
+
+namespace test4 {
+ template <class T> class Holder {
+ T object;
+ friend bool operator==(Holder &a, Holder &b) {
+ return a.object == b.object; // expected-error {{invalid operands to binary expression}}
+ }
+ };
+
+ struct Inequal {};
+ bool test() {
+ Holder<Inequal> a, b;
+ return a == b; // expected-note {{requested here}}
+ }
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index bc69bee..3bbdbab8 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -101,14 +101,14 @@ namespace test2 {
namespace test3 {
class A {
private:
- ~A(); // expected-note 3 {{declared private here}}
+ ~A(); // expected-note 2 {{declared private here}}
static A foo;
};
A a; // expected-error {{variable of type 'test3::A' has private destructor}}
A A::foo;
- void foo(A param) { // expected-error {{variable of type 'test3::A' has private destructor}}
+ void foo(A param) { // okay
A local; // expected-error {{variable of type 'test3::A' has private destructor}}
}
@@ -262,3 +262,68 @@ namespace test9 {
static int getX() { return x; } // expected-error {{'x' is a private member of 'test9::A'}}
};
}
+
+namespace test10 {
+ class A {
+ enum {
+ value = 10 // expected-note {{declared private here}}
+ };
+ friend class C;
+ };
+
+ class B {
+ enum {
+ value = A::value // expected-error {{'value' is a private member of 'test10::A'}}
+ };
+ };
+
+ class C {
+ enum {
+ value = A::value
+ };
+ };
+}
+
+namespace test11 {
+ class A {
+ protected: virtual ~A();
+ };
+
+ class B : public A {
+ ~B();
+ };
+
+ B::~B() {};
+}
+
+namespace test12 {
+ class A {
+ int x;
+
+ void foo() {
+ class Local {
+ int foo(A *a) {
+ return a->x;
+ }
+ };
+ }
+ };
+}
+
+namespace test13 {
+ struct A {
+ int x;
+ unsigned foo() const;
+ };
+
+ struct B : protected A {
+ using A::foo;
+ using A::x;
+ };
+
+ void test() {
+ A *d;
+ d->foo();
+ (void) d->x;
+ }
+}
diff --git a/test/CXX/class.derived/class.abstract/p4.cpp b/test/CXX/class.derived/class.abstract/p4.cpp
new file mode 100644
index 0000000..ca99bf7
--- /dev/null
+++ b/test/CXX/class.derived/class.abstract/p4.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR6631 {
+ struct A {
+ virtual void f() = 0;
+ };
+
+ struct B : virtual A { };
+
+ struct C : virtual A {
+ virtual void f();
+ };
+
+ struct D : public B, public C {
+ virtual void f();
+ };
+
+ void f() {
+ (void)new D; // okay
+ }
+}
+
+// Check cases where we have a virtual function that is pure in one
+// subobject but not pure in another subobject.
+namespace PartlyPure {
+ struct A {
+ virtual void f() = 0; // expected-note{{pure virtual function}}
+ };
+
+ struct B : A {
+ virtual void f();
+ };
+
+ struct C : virtual A { };
+
+ struct D : B, C { };
+
+ void f() {
+ (void) new D; // expected-error{{abstract type}}
+ }
+}
+
+namespace NonPureAlongOnePath {
+ struct A {
+ virtual void f() = 0;
+ };
+
+ struct B : virtual A {
+ virtual void f();
+ };
+
+ struct C : virtual A { };
+
+ struct D : B, C { };
+
+ void f() {
+ (void) new D; // okay
+ }
+}
+
+namespace NonPureAlongOnePath2 {
+ struct Aprime {
+ virtual void f() = 0;
+ };
+
+ struct A : Aprime {
+ };
+
+ struct B : virtual A {
+ virtual void f();
+ };
+
+ struct C : virtual A { };
+
+ struct D : B, C { };
+
+ void f() {
+ (void) new D; // okay
+ }
+}
diff --git a/test/CXX/class.derived/class.abstract/p5.cpp b/test/CXX/class.derived/class.abstract/p5.cpp
new file mode 100644
index 0000000..207519d
--- /dev/null
+++ b/test/CXX/class.derived/class.abstract/p5.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {
+ virtual void f() = 0; // expected-note{{pure virtual function}}
+};
+
+struct B : A {
+ virtual void f();
+};
+
+struct C : B {
+ virtual void f() = 0; // expected-note 2{{pure virtual function}}
+};
+
+struct D : C {
+};
+
+void test() {
+ (void)new A; // expected-error{{object of abstract type}}
+ (void)new B;
+ (void)new C; // expected-error{{object of abstract type}}
+ (void)new D; // expected-error{{object of abstract type}}
+}
diff --git a/test/CXX/class.derived/class.virtual/p2.cpp b/test/CXX/class.derived/class.virtual/p2.cpp
new file mode 100644
index 0000000..64d93c8
--- /dev/null
+++ b/test/CXX/class.derived/class.virtual/p2.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A {
+ virtual void f() = 0; // expected-note 2{{overridden virtual function}}
+};
+
+struct Aprime : virtual A {
+ virtual void f();
+};
+
+struct B : Aprime {
+ virtual void f(); // expected-note 3{{final overrider of 'A::f'}}
+};
+
+struct C : virtual A {
+ virtual void f(); // expected-note{{final overrider of 'A::f'}}
+};
+
+struct D : B, C { }; // expected-error{{virtual function 'A::f' has more than one final overrider in 'D'}}
+
+struct B2 : B { };
+
+struct E : B, B2 { }; //expected-error{{virtual function 'A::f' has more than one final overrider in 'E'}}
+
+struct F : B, B2 {
+ virtual void f(); // okay
+};
+
+struct G : F { }; // okay
+
+struct H : G, A { }; // okay
+
+namespace MultipleSubobjects {
+ struct A { virtual void f(); };
+ struct B : A { virtual void f(); };
+ struct C : A { virtual void f(); };
+ struct D : B, C { }; // okay
+}
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
index 935f576..89e9c89 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
// We have to avoid ADL for this test.
@@ -65,3 +65,44 @@ namespace Test1 {
b _2 = B::b();
}
}
+
+namespace test2 {
+ class A {
+ protected:
+ operator int();
+ operator bool();
+ };
+
+ class B : private A {
+ protected:
+ using A::operator int; // expected-note {{'declared protected here'}}
+ public:
+ using A::operator bool;
+ };
+
+ int test() {
+ bool b = B();
+ return B(); // expected-error {{'operator int' is a protected member of 'test2::B'}}
+ }
+}
+
+namespace test3 {
+ class A {
+ ~A();
+ };
+
+ class B {
+ friend class C;
+ private:
+ operator A*();
+ };
+
+ class C : public B {
+ public:
+ using B::operator A*;
+ };
+
+ void test() {
+ delete C();
+ }
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
index 392888e..c530311 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
@@ -25,8 +25,7 @@ template <> class B<int> {
};
template <> struct B<A> {
- // FIXME: the error here should be associated with the use at "void foo..."
- union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}}
+ union Member { // expected-note 4 {{previous use is here}}
void* a;
};
};
@@ -41,10 +40,10 @@ void c2(class B<float>::Member);
void c3(union B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
void c4(enum B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
-void d1(struct B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
-void d2(class B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
-void d3(union B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
-void d4(enum B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d1(struct B<int>::Member); // expected-error {{no struct named 'Member' in 'B<int>'}}
+void d2(class B<int>::Member); // expected-error {{no class named 'Member' in 'B<int>'}}
+void d3(union B<int>::Member); // expected-error {{no union named 'Member' in 'B<int>'}}
+void d4(enum B<int>::Member); // expected-error {{no enum named 'Member' in 'B<int>'}}
void e1(struct B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
void e2(class B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
@@ -52,7 +51,8 @@ void e3(union B<A>::Member);
void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
template <class T> struct C {
- void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}}
+ void foo(class B<T>::Member); // expected-error{{no class named 'Member' in 'B<int>'}} \
+ // expected-error{{use of 'Member' with tag type that does not match previous declaration}}
};
C<float> f1;
diff --git a/test/CXX/stmt.stmt/stmt.select/p3.cpp b/test/CXX/stmt.stmt/stmt.select/p3.cpp
new file mode 100644
index 0000000..e674f97
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.select/p3.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int f();
+
+void g() {
+ if (int x = f()) { // expected-note 2{{previous definition}}
+ int x; // expected-error{{redefinition of 'x'}}
+ } else {
+ int x; // expected-error{{redefinition of 'x'}}
+ }
+}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 83365a2..14dace8 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -49,9 +49,9 @@ namespace addr_of_obj_or_func {
// -- a pointer to member expressed as described in 5.3.1.
namespace bad_args {
- template <int* N> struct X0 { };
+ template <int* N> struct X0 { }; // expected-note 2{{template parameter is declared here}}
int i = 42;
X0<&i + 2> x0a; // expected-error{{non-type template argument does not refer to any declaration}}
int* iptr = &i;
- X0<iptr> x0b; // FIXME: This should not be accepted.
+ X0<iptr> x0b; // expected-error{{non-type template argument for template parameter of pointer type 'int *' must have its address taken}}
}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
index 458aff2..b0f1c46 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
@@ -7,6 +7,14 @@
// program is ill-formed.
// -- for a non-type template-parameter of integral or enumeration type,
// integral promotions (4.5) and integral conversions (4.7) are applied.
+namespace integral_parameters {
+ template<short s> struct X0 { };
+ X0<17> x0i;
+ X0<'a'> x0c;
+ template<char c> struct X1 { };
+ X1<100l> x1l;
+}
+
// -- for a non-type template-parameter of type pointer to object,
// qualification conversions (4.4) and the array-to-pointer conversion
// (4.2) are applied; if the template-argument is of type
@@ -37,12 +45,12 @@ namespace pointer_to_object_parameters {
operator int() const;
};
- template<X const *Ptr> struct A2;
+ template<X const *Ptr> struct A2; // expected-note{{template parameter is declared here}}
X *X_ptr;
X an_X;
X array_of_Xs[10];
- A2<X_ptr> *a12;
+ A2<X_ptr> *a12; // expected-error{{must have its address taken}}
A2<array_of_Xs> *a13;
A2<&an_X> *a13_2;
A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
@@ -52,6 +60,16 @@ namespace pointer_to_object_parameters {
template <X1*> struct X2 { };
template <X1* Value> struct X3 : X2<Value> { };
struct X4 : X3<&X1v> { };
+
+ // PR6563
+ int *bar;
+ template <int *> struct zed {}; // expected-note 2{{template parameter is declared here}}
+ void g(zed<bar>*); // expected-error{{must have its address taken}}
+
+ int baz;
+ void g2(zed<baz>*); // expected-error{{must have its address taken}}
+
+ void g3(zed<&baz>*); // okay
}
// -- For a non-type template-parameter of type reference to object, no
@@ -105,6 +123,12 @@ namespace reference_parameters {
bind<int, counter>(); // expected-note{{instantiation of}}
}
}
+
+ namespace PR6749 {
+ template <int& i> struct foo {}; // expected-note{{template parameter is declared here}}
+ int x, &y = x;
+ foo<y> f; // expected-error{{is not an object}}
+ }
}
// -- For a non-type template-parameter of type pointer to function, the
@@ -113,17 +137,69 @@ namespace reference_parameters {
// conversion (4.10) is applied. If the template-argument represents
// a set of overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
+namespace pointer_to_function {
+ template<int (*)(int)> struct X0 { }; // expected-note 3{{template parameter is declared here}}
+ int f(int);
+ int f(float);
+ int g(float);
+ int (*funcptr)(int);
+ void x0a(X0<f>);
+ void x0b(X0<&f>);
+ void x0c(X0<g>); // expected-error{{non-type template argument of type 'int (float)' cannot be converted to a value of type 'int (*)(int)'}}
+ void x0d(X0<&g>); // expected-error{{non-type template argument of type 'int (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
+ void x0e(X0<funcptr>); // expected-error{{must have its address taken}}
+}
+
// -- For a non-type template-parameter of type reference to function, no
// conversions apply. If the template-argument represents a set of
// overloaded functions, the matching function is selected from the set
// (13.4).
+namespace reference_to_function {
+ template<int (&)(int)> struct X0 { }; // expected-note 4{{template parameter is declared here}}
+ int f(int);
+ int f(float);
+ int g(float);
+ int (*funcptr)(int);
+ void x0a(X0<f>);
+ void x0b(X0<&f>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
+ void x0c(X0<g>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (float)'}}
+ void x0d(X0<&g>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
+ void x0e(X0<funcptr>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (*)(int)'}}
+}
// -- For a non-type template-parameter of type pointer to member function,
// if the template-argument is of type std::nullptr_t, the null member
// pointer conversion (4.11) is applied; otherwise, no conversions
// apply. If the template-argument represents a set of overloaded member
// functions, the matching member function is selected from the set
// (13.4).
+namespace pointer_to_member_function {
+ struct X { };
+ struct Y : X {
+ int f(int);
+ int g(int);
+ int g(float);
+ float h(float);
+ };
+
+ template<int (Y::*)(int)> struct X0 {}; // expected-note{{template parameter is declared here}}
+ X0<&Y::f> x0a;
+ X0<&Y::g> x0b;
+ X0<&Y::h> x0c; // expected-error{{non-type template argument of type 'float (pointer_to_member_function::Y::*)(float)' cannot be converted to a value of type 'int (pointer_to_member_function::Y::*)(int)'}}
+}
+
// -- For a non-type template-parameter of type pointer to data member,
// qualification conversions (4.4) are applied; if the template-argument
// is of type std::nullptr_t, the null member pointer conversion (4.11)
// is applied.
+namespace pointer_to_member_data {
+ struct X { int x; };
+ struct Y : X { int y; };
+
+ template<int Y::*> struct X0 {}; // expected-note{{template parameter is declared here}}
+ X0<&Y::y> x0a;
+ X0<&Y::x> x0b; // expected-error{{non-type template argument of type 'int pointer_to_member_data::X::*' cannot be converted to a value of type 'int pointer_to_member_data::Y::*'}}
+
+ // Test qualification conversions
+ template<const int Y::*> struct X1 {};
+ X1<&Y::y> x1a;
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
index f1b3c81..c9dc546 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -faccess-control -verify -emit-llvm-only %s
+namespace test0 {
template <typename T> struct Num {
T value_;
@@ -54,6 +55,7 @@ int calc2() {
Num<int> result = x * n;
return result.get();
}
+}
// Reduced from GNU <locale>
namespace test1 {
@@ -85,3 +87,132 @@ namespace test2 {
}
};
}
+
+namespace test3 {
+ class Bool;
+ template <class T> class User;
+ template <class T> T transform(class Bool, T);
+
+ class Bool {
+ friend class User<bool>;
+ friend bool transform<>(Bool, bool);
+
+ bool value; // expected-note 2 {{declared private here}}
+ };
+
+ template <class T> class User {
+ static T compute(Bool b) {
+ return b.value; // expected-error {{'value' is a private member of 'test3::Bool'}}
+ }
+ };
+
+ template <class T> T transform(Bool b, T value) {
+ if (b.value) // expected-error {{'value' is a private member of 'test3::Bool'}}
+ return value;
+ return value + 1;
+ }
+
+ template bool transform(Bool, bool);
+ template int transform(Bool, int); // expected-note {{requested here}}
+
+ template class User<bool>;
+ template class User<int>; // expected-note {{requested here}}
+}
+
+namespace test4 {
+ template <class T> class A {
+ template <class T0> friend class B;
+ bool foo(const A<T> *) const;
+ };
+
+ template <class T> class B {
+ bool bar(const A<T> *a, const A<T> *b) {
+ return a->foo(b);
+ }
+ };
+
+ template class B<int>;
+}
+
+namespace test5 {
+ template <class T, class U=int> class A {};
+ template <class T> class B {
+ template <class X, class Y> friend class A;
+ };
+ template class B<int>;
+ template class A<int>;
+}
+
+namespace Dependent {
+ template<typename T, typename Traits> class X;
+ template<typename T, typename Traits>
+ X<T, Traits> operator+(const X<T, Traits>&, const T*);
+
+ template<typename T, typename Traits> class X {
+ typedef typename Traits::value_type value_type;
+ friend X operator+<>(const X&, const value_type*);
+ };
+}
+
+namespace test7 {
+ template <class T> class A { // expected-note {{previous definition is here}}
+ friend class B;
+ int x; // expected-note {{declared private here}}
+ };
+
+ class B {
+ int foo(A<int> &a) {
+ return a.x;
+ }
+ };
+
+ class C {
+ int foo(A<int> &a) {
+ return a.x; // expected-error {{'x' is a private member of 'test7::A<int>'}}
+ }
+ };
+
+ // This shouldn't crash.
+ template <class T> class D {
+ friend class A; // expected-error {{redefinition of 'A' as different kind of symbol}}
+ };
+ template class D<int>;
+}
+
+namespace test8 {
+ template <class N> class A {
+ static int x;
+ template <class T> friend void foo();
+ };
+ template class A<int>;
+
+ template <class T> void foo() {
+ A<int>::x = 0;
+ }
+ template void foo<int>();
+}
+
+namespace test9 {
+ template <class T> class A {
+ class B; class C;
+
+ int foo(B *b) {
+ return b->x;
+ }
+
+ int foo(C *c) {
+ return c->x; // expected-error {{'x' is a private member}}
+ }
+
+ class B {
+ int x;
+ friend int A::foo(B*);
+ };
+
+ class C {
+ int x; // expected-note {{declared private here}}
+ };
+ };
+
+ template class A<int>; // expected-note {{in instantiation}}
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp
new file mode 100644
index 0000000..c27261c
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template <int> int f(int); // expected-note 2{{candidate}}
+template <signed char> int f(int); // expected-note 2{{candidate}}
+int i1 = f<1>(0); // expected-error{{ambiguous}}
+int i2 = f<1000>(0); // expected-error{{ambiguous}}
+
+namespace PR6707 {
+ template<typename T, T Value>
+ struct X { };
+
+ template<typename T, T Value>
+ void f(X<T, Value>);
+
+ void g(X<int, 10> x) {
+ f(x);
+ }
+
+ static const unsigned char ten = 10;
+ template<typename T, T Value, typename U>
+ void f2(X<T, Value>, X<U, Value>);
+
+ void g2() {
+ f2(X<int, 10>(), X<char, ten>());
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
new file mode 100644
index 0000000..2a7f16d
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<int i> class A { };
+template<short s> void f(A<s>); // expected-note{{failed template argument deduction}}
+
+void k1() {
+ A<1> a;
+ f(a); // expected-error{{no matching function for call}}
+ f<1>(a);
+}
+template<const short cs> class B { };
+template<short s> void g(B<s>);
+void k2() {
+ B<1> b;
+ g(b); // OK: cv-qualifiers are ignored on template parameter types
+}
+
+template<short s> void h(int (&)[s]); // expected-note{{failed template argument deduction}}
+void k3() {
+ int array[5];
+ h(array);
+ h<5>(array);
+}
+
+template<short s> void h(int (&)[s], A<s>); // expected-note{{failed template argument deduction}}
+void k4() {
+ A<5> a;
+ int array[5];
+ h(array, a); // expected-error{{no matching function for call}}
+ h<5>(array, a);
+}
diff --git a/test/CXX/temp/temp.res/temp.local/p1.cpp b/test/CXX/temp/temp.res/temp.local/p1.cpp
index ed534a4..1ad4464 100644
--- a/test/CXX/temp/temp.res/temp.local/p1.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p1.cpp
@@ -26,8 +26,7 @@ template <int N1, const int& N2, const int* N3> struct X1 {
// FIXME: Test this clause.
int i = 42;
-int* iptr = &i;
void test() {
X0<int> x0; (void)x0;
- X1<42, i, iptr> x1; (void)x1;
+ X1<42, i, &i> x1; (void)x1;
}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
index f987c12..86cdcf8 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
@@ -6,7 +6,7 @@ template<typename T>
struct A { };
struct X {
- template<> friend void f<int>(int); // expected-error{{in class scope}}
+ template<> friend void f<int>(int); // expected-error{{in a friend}}
template<> friend class A<int>; // expected-error{{cannot be a friend}}
friend void f<float>(float); // okay
diff --git a/test/CodeGen/atomic.c b/test/CodeGen/atomic.c
index c201a1a..aa5aa15 100644
--- a/test/CodeGen/atomic.c
+++ b/test/CodeGen/atomic.c
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 > %t1
-// RUN: grep @llvm.memory.barrier %t1 | count 42
+// RUN: grep @llvm.memory.barrier %t1 | count 38
// RUN: grep @llvm.atomic.load.add.i32 %t1 | count 3
// RUN: grep @llvm.atomic.load.sub.i8 %t1 | count 2
// RUN: grep @llvm.atomic.load.min.i32 %t1
@@ -8,7 +8,7 @@
// RUN: grep @llvm.atomic.load.umax.i32 %t1
// RUN: grep @llvm.atomic.swap.i32 %t1
// RUN: grep @llvm.atomic.cmp.swap.i32 %t1 | count 4
-// RUN: grep @llvm.atomic.load.and.i32 %t1 | count 2
+// RUN: grep @llvm.atomic.load.and.i32 %t1
// RUN: grep @llvm.atomic.load.or.i8 %t1
// RUN: grep @llvm.atomic.load.xor.i8 %t1
@@ -34,14 +34,12 @@ int atomic(void)
old = __sync_fetch_and_and(&val, 0x9);
old = __sync_fetch_and_or(&val, 0xa);
old = __sync_fetch_and_xor(&val, 0xb);
- old = __sync_fetch_and_nand(&val, 0xb);
old = __sync_add_and_fetch(&val, 1);
old = __sync_sub_and_fetch(&val, 2);
old = __sync_and_and_fetch(&valc, 3);
old = __sync_or_and_fetch(&valc, 4);
old = __sync_xor_and_fetch(&valc, 5);
- old = __sync_nand_and_fetch(&valc, 5);
__sync_val_compare_and_swap((void **)0, (void *)0, (void *)0);
diff --git a/test/CodeGen/mangle.c b/test/CodeGen/mangle.c
index a087b42..93d424a 100644
--- a/test/CodeGen/mangle.c
+++ b/test/CodeGen/mangle.c
@@ -59,3 +59,7 @@ extern int func (void) __asm__ ("FUNC");
int func(void) {
return 42;
}
+
+// CHECK: @_Z4foo9Dv4_f
+typedef __attribute__(( vector_size(16) )) float float4;
+void __attribute__((__overloadable__)) foo9(float4 f) {}
diff --git a/test/CodeGen/palignr.c b/test/CodeGen/palignr.c
index 68efb41..627e309 100644
--- a/test/CodeGen/palignr.c
+++ b/test/CodeGen/palignr.c
@@ -15,5 +15,5 @@ int4 align1(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 15); }
int4 align2(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 16); }
// CHECK: psrldq
int4 align3(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 17); }
-// CHECK: xorps
+// CHECK: xor
int4 align4(int4 a, int4 b) { return _mm_alignr_epi8(a, b, 32); }
diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c
index ac37975..b60f8c7 100644
--- a/test/CodeGen/regparm.c
+++ b/test/CodeGen/regparm.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | grep inreg | count 2
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
#define FASTCALL __attribute__((regparm(2)))
@@ -8,11 +8,16 @@ typedef struct {
int ccc[200];
} foo;
+typedef void (*FType)(int, int) __attribute ((regparm (3), stdcall));
+FType bar;
+
static void FASTCALL
-reduced(char b, double c, foo* d, double e, int f) {
-}
+reduced(char b, double c, foo* d, double e, int f);
int
main(void) {
+ // CHECK: call void @reduced(i8 signext inreg 0, {{.*}} %struct.anon* inreg null
reduced(0, 0.0, 0, 0.0, 0);
+ // CHECK: call x86_stdcallcc void {{.*}}(i32 inreg 1, i32 inreg 2)
+ bar(1,2);
}
diff --git a/test/CodeGen/restrict.c b/test/CodeGen/restrict.c
new file mode 100644
index 0000000..8bbff24
--- /dev/null
+++ b/test/CodeGen/restrict.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-darwin-apple -emit-llvm %s -o - | FileCheck %s
+
+// PR6695
+
+// CHECK: define void @test0(i32* %{{.*}}, i32 %{{.*}})
+void test0(int *x, int y) {
+}
+
+// CHECK: define void @test1(i32* noalias %{{.*}}, i32 %{{.*}})
+void test1(int * restrict x, int y) {
+}
+
+// CHECK: define void @test2(i32* %{{.*}}, i32* noalias %{{.*}})
+void test2(int *x, int * restrict y) {
+}
+
+typedef int * restrict rp;
+
+// CHECK: define void @test3(i32* noalias %{{.*}}, i32 %{{.*}})
+void test3(rp x, int y) {
+}
+
+// CHECK: define void @test4(i32* %{{.*}}, i32* noalias %{{.*}})
+void test4(int *x, rp y) {
+}
+
diff --git a/test/CodeGenCXX/constructor-init.cpp b/test/CodeGenCXX/constructor-init.cpp
index a0a35fa..284b8b5 100644
--- a/test/CodeGenCXX/constructor-init.cpp
+++ b/test/CodeGenCXX/constructor-init.cpp
@@ -80,3 +80,24 @@ void f() {
// CHECK-NOT: call void @_ZN1AIsED1Ev
// CHECK: ret void
}
+
+template<typename T>
+struct X {
+ X(const X &);
+
+ T *start;
+ T *end;
+};
+
+template<typename T> struct X;
+
+// Make sure that the instantiated constructor initializes start and
+// end properly.
+// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_
+// CHECK: {{store.*null}}
+// CHECK: {{store.*null}}
+// CHECK: ret
+template<typename T>
+X<T>::X(const X &other) : start(0), end(0) { }
+
+X<int> get_X(X<int> x) { return x; }
diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp
index ae8eefa..9cafd0a 100644
--- a/test/CodeGenCXX/copy-constructor-synthesis.cpp
+++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp
@@ -1,7 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
-// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
extern "C" int printf(...);
@@ -24,6 +21,7 @@ struct P {
};
+// CHECK: define linkonce_odr void @_ZN1XC1ERKS_
struct X : M, N, P { // ...
X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd),
au_i1(1234), au1_4("MASKED") {}
@@ -113,10 +111,46 @@ void f(const B &b1) {
B b2(b1);
}
-// CHECK-LP64: .globl __ZN1XC1ERKS_
-// CHECK-LP64: .weak_definition __ZN1XC1ERKS_
-// CHECK-LP64: __ZN1XC1ERKS_:
+// PR6628
+namespace PR6628 {
+
+struct T {
+ T();
+ ~T();
+
+ double d;
+};
+
+struct A {
+ A(const A &other, const T &t = T(), const T& t2 = T());
+};
+
+struct B : A {
+ A a1;
+ A a2;
+ A a[10];
+};
+
+// Force the copy constructor to be synthesized.
+void f(B b1) {
+ B b2 = b1;
+}
+
+// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281TC1Ev
+// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_
+// CHECK: call void @_ZN6PR66281TD1Ev
+// CHECK: call void @_ZN6PR66281TD1Ev
+}
-// CHECK-LP32: .globl __ZN1XC1ERKS_
-// CHECK-LP32: .weak_definition __ZN1XC1ERKS_
-// CHECK-LP32: __ZN1XC1ERKS_:
diff --git a/test/CodeGenCXX/member-expressions.cpp b/test/CodeGenCXX/member-expressions.cpp
index 720a9a7..d9fb394 100644
--- a/test/CodeGenCXX/member-expressions.cpp
+++ b/test/CodeGenCXX/member-expressions.cpp
@@ -44,3 +44,43 @@ int f() {
return A().foo();
}
}
+
+namespace test4 {
+ struct A {
+ int x;
+ };
+ struct B {
+ int x;
+ void foo();
+ };
+ struct C : A, B {
+ };
+
+ extern C *c_ptr;
+
+ // CHECK: define i32 @_ZN5test44testEv()
+ int test() {
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @_ZN5test41B3fooEv
+ c_ptr->B::foo();
+
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: store i32 5
+ c_ptr->B::x = 5;
+
+ // CHECK: load {{.*}} @_ZN5test45c_ptrE
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: getelementptr
+ // CHECK-NEXT: load i32*
+ return c_ptr->B::x;
+ }
+}
diff --git a/test/CodeGenCXX/multi-dim-operator-new.cpp b/test/CodeGenCXX/multi-dim-operator-new.cpp
new file mode 100644
index 0000000..7a235e8
--- /dev/null
+++ b/test/CodeGenCXX/multi-dim-operator-new.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -emit-llvm -o - | FileCheck %s
+// PR6641
+
+extern "C" int printf(const char *, ...);
+
+struct Foo {
+ Foo() : iFoo (2) {
+ printf("%p\n", this);
+ }
+ int iFoo;
+};
+
+
+typedef Foo (*T)[3][4];
+
+T bar() {
+ return new Foo[2][3][4];
+}
+
+T bug(int i) {
+ return new Foo[i][3][4];
+}
+
+void pr(T a) {
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 4; j++)
+ printf("%p\n", a[i][j]);
+}
+
+Foo *test() {
+ return new Foo[5];
+}
+
+int main() {
+ T f = bar();
+ pr(f);
+ f = bug(3);
+ pr(f);
+
+ Foo * g = test();
+ for (int i = 0; i < 5; i++)
+ printf("%d\n", g[i].iFoo);
+ return 0;
+}
+
+// CHECK: call noalias i8* @_Znam
+// CHECK: call noalias i8* @_Znam
+// CHECK: call noalias i8* @_Znam
+
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index 39b5909..5a5947d 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -147,3 +147,11 @@ void f(int &a) {
struct s0;
struct s1 { struct s0 &s0; };
void f0(s1 a) { s1 b = a; }
+
+// PR6024
+// CHECK: @_Z2f2v()
+// CHECK: alloca
+// CHECK: store
+// CHECK: load
+// CHECK: ret
+const int &f2() { return 0; }
diff --git a/test/CodeGenCXX/rtti-fundamental.cpp b/test/CodeGenCXX/rtti-fundamental.cpp
new file mode 100644
index 0000000..473f48d
--- /dev/null
+++ b/test/CodeGenCXX/rtti-fundamental.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+#include <typeinfo>
+
+std::type_info foo() {
+ return typeid(void);
+}
+
+namespace __cxxabiv1 {
+ struct __fundamental_type_info {
+ virtual ~__fundamental_type_info() {}
+ };
+}
+
+// CHECK: @_ZTIv = weak_odr constant
+// CHECK: @_ZTIPv = weak_odr constant
+// CHECK: @_ZTIPKv = weak_odr constant
+// CHECK: @_ZTIDi = weak_odr constant
+// CHECK: @_ZTIPDi = weak_odr constant
+// CHECK: @_ZTIPKDi = weak_odr constant
+// CHECK: @_ZTIDs = weak_odr constant
+// CHECK: @_ZTIPDs = weak_odr constant
+// CHECK: @_ZTIPKDs = weak_odr constant
+// CHECK: @_ZTIy = weak_odr constant
+// CHECK: @_ZTIPy = weak_odr constant
+// CHECK: @_ZTIPKy = weak_odr constant
+// CHECK: @_ZTIx = weak_odr constant
+// CHECK: @_ZTIPx = weak_odr constant
+// CHECK: @_ZTIPKx = weak_odr constant
+// CHECK: @_ZTIw = weak_odr constant
+// CHECK: @_ZTIPw = weak_odr constant
+// CHECK: @_ZTIPKw = weak_odr constant
+// CHECK: @_ZTIt = weak_odr constant
+// CHECK: @_ZTIPt = weak_odr constant
+// CHECK: @_ZTIPKt = weak_odr constant
+// CHECK: @_ZTIs = weak_odr constant
+// CHECK: @_ZTIPs = weak_odr constant
+// CHECK: @_ZTIPKs = weak_odr constant
+// CHECK: @_ZTIm = weak_odr constant
+// CHECK: @_ZTIPm = weak_odr constant
+// CHECK: @_ZTIPKm = weak_odr constant
+// CHECK: @_ZTIl = weak_odr constant
+// CHECK: @_ZTIPl = weak_odr constant
+// CHECK: @_ZTIPKl = weak_odr constant
+// CHECK: @_ZTIj = weak_odr constant
+// CHECK: @_ZTIPj = weak_odr constant
+// CHECK: @_ZTIPKj = weak_odr constant
+// CHECK: @_ZTIi = weak_odr constant
+// CHECK: @_ZTIPi = weak_odr constant
+// CHECK: @_ZTIPKi = weak_odr constant
+// CHECK: @_ZTIh = weak_odr constant
+// CHECK: @_ZTIPh = weak_odr constant
+// CHECK: @_ZTIPKh = weak_odr constant
+// CHECK: @_ZTIf = weak_odr constant
+// CHECK: @_ZTIPf = weak_odr constant
+// CHECK: @_ZTIPKf = weak_odr constant
+// CHECK: @_ZTIe = weak_odr constant
+// CHECK: @_ZTIPe = weak_odr constant
+// CHECK: @_ZTIPKe = weak_odr constant
+// CHECK: @_ZTId = weak_odr constant
+// CHECK: @_ZTIPd = weak_odr constant
+// CHECK: @_ZTIPKd = weak_odr constant
+// CHECK: @_ZTIc = weak_odr constant
+// CHECK: @_ZTIPc = weak_odr constant
+// CHECK: @_ZTIPKc = weak_odr constant
+// CHECK: @_ZTIb = weak_odr constant
+// CHECK: @_ZTIPb = weak_odr constant
+// CHECK: @_ZTIPKb = weak_odr constant
+// CHECK: @_ZTIa = weak_odr constant
+// CHECK: @_ZTIPa = weak_odr constant
+// CHECK: @_ZTIPKa = weak_odr constant
diff --git a/test/CodeGenCXX/rtti-linkage.cpp b/test/CodeGenCXX/rtti-linkage.cpp
index 799c1d4..b9eb5b4 100644
--- a/test/CodeGenCXX/rtti-linkage.cpp
+++ b/test/CodeGenCXX/rtti-linkage.cpp
@@ -92,6 +92,7 @@ const std::type_info &t2() {
(void)typeid(D *);
(void)typeid(D (*)());
(void)typeid(void (*)(D));
+ (void)typeid(void (*)(D&));
// The exception specification is not part of the RTTI descriptor, so it should not have
// internal linkage.
(void)typeid(void (*)() throw (D));
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
new file mode 100644
index 0000000..416c0a1
--- /dev/null
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
+// CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE
+// CHECK: @_ZTVN5test018stdio_sync_filebufIwEE = constant
+
+// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(
+// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_(
+// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd(
+
+namespace test0 {
+ struct basic_streambuf {
+ virtual ~basic_streambuf();
+ };
+ template<typename _CharT >
+ struct stdio_sync_filebuf : public basic_streambuf {
+ virtual void xsgetn();
+ };
+
+ // This specialization should cause the vtable to be emitted, even with
+ // the following extern template declaration.
+ template<> void stdio_sync_filebuf<wchar_t>::xsgetn() {
+ }
+ extern template class stdio_sync_filebuf<wchar_t>;
+}
+
+namespace test1 {
+ struct basic_streambuf {
+ virtual ~basic_streambuf();
+ };
+ template<typename _CharT >
+ struct stdio_sync_filebuf : public basic_streambuf {
+ virtual void xsgetn();
+ };
+
+ // Just a declaration should not force the vtable to be emitted.
+ template<> void stdio_sync_filebuf<wchar_t>::xsgetn();
+}
+
+namespace test2 {
+ template<typename T1>
+ class C {
+ virtual ~C();
+ void zedbar(double) {
+ }
+ template<typename T2>
+ void foobar(T2 foo) {
+ }
+ };
+ extern template class C<int>;
+ void g() {
+ // The extern template declaration should not prevent us from producing
+ // the implicit constructor (test at the top).
+ C<int> a;
+
+ // or foobar(test at the top).
+ a.foobar(0.0);
+
+ // But it should prevent zebbar
+ // (test at the top).
+ a.zedbar(0.0);
+ }
+}
+
+namespace test3 {
+ template<typename T>
+ class basic_fstreamXX {
+ virtual void foo(){}
+ virtual void is_open() const { }
+ };
+
+ extern template class basic_fstreamXX<char>;
+ // This template instantiation should not cause us to produce a vtable.
+ // (test at the top).
+ template void basic_fstreamXX<char>::is_open() const;
+}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index cd0cf77..4aad3c0 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -288,3 +288,16 @@ void g() {
}
}
+
+namespace PR6648 {
+ struct B {
+ ~B();
+ };
+ B foo;
+ struct D;
+ D& zed(B);
+ void foobar() {
+ // CHECK: call %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE
+ zed(foo);
+ }
+}
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
new file mode 100644
index 0000000..b91ba32
--- /dev/null
+++ b/test/CodeGenCXX/thunks.cpp
@@ -0,0 +1,137 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+namespace Test1 {
+
+// Check that we emit a non-virtual thunk for C::f.
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define void @_ZThn8_N5Test11C1fEv(
+void C::f() { }
+
+}
+
+namespace Test2 {
+
+// Check that we emit a thunk for B::f since it's overriding a virtual base.
+
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A {
+ virtual void b();
+ virtual void f();
+};
+
+// CHECK: define void @_ZTv0_n24_N5Test21B1fEv(
+void B::f() { }
+
+}
+
+namespace Test3 {
+
+// Check that we emit a covariant thunk for B::f.
+
+struct V1 { };
+struct V2 : virtual V1 { };
+
+struct A {
+ virtual V1 *f();
+};
+
+struct B : A {
+ virtual void b();
+
+ virtual V2 *f();
+};
+
+// CHECK: define %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv(
+V2 *B::f() { return 0; }
+
+}
+
+namespace Test4 {
+
+// Check that the thunk for 'C::f' has the same visibility as the function itself.
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct __attribute__((visibility("protected"))) C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define protected void @_ZThn8_N5Test41C1fEv(
+void C::f() { }
+
+}
+
+// This is from Test5:
+// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
+
+// Check that the thunk gets internal linkage.
+namespace {
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void c();
+
+ virtual void f();
+};
+
+// CHECK: define internal void @_ZThn8_N12_GLOBAL__N_11C1fEv(
+void C::f() { }
+
+}
+
+// Force C::f to be used.
+void f() {
+ C c;
+
+ c.f();
+}
+
+namespace Test5 {
+
+// Check that the thunk for 'B::f' gets the same linkage as the function itself.
+struct A {
+ virtual void f();
+};
+
+struct B : virtual A {
+ virtual void f() { }
+};
+
+void f(B b) {
+ b.f();
+}
+}
+
+
diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp
index 9d671c4..c404129 100644
--- a/test/CodeGenCXX/virt.cpp
+++ b/test/CodeGenCXX/virt.cpp
@@ -693,55 +693,3 @@ void test12_foo() {
// CHECK-LPLL64: call void %
// CHECK-LPLL64: call void @_ZN8test12_A3fooEv(%class.test14* %{{.*}})
-
-// FIXME: This is the wrong thunk, but until these issues are fixed, better
-// than nothing.
-// CHECK-LPLL64define weak %class.test8_D* @_ZTcvn16_n72_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|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: %{{retval|1}} = alloca %class.test8_D*
-// CHECK-LPLL64: %{{.addr|2}} = alloca %class.test8_D*
-// CHECK-LPLL64: store %class.test8_D* %0, %class.test8_D** %{{.addr|2}}
-// CHECK-LPLL64: %{{this|3}} = load %class.test8_D** %{{.addr|2}}
-// 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-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp
index 6277175..61de315 100644
--- a/test/CodeGenCXX/virtual-bases.cpp
+++ b/test/CodeGenCXX/virtual-bases.cpp
@@ -23,3 +23,26 @@ struct C : virtual A {
// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext)
// CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext)
C::C(bool) { }
+
+// PR6251
+namespace PR6251 {
+
+// Test that we don't call the A<char> constructor twice.
+
+template<typename T>
+struct A { A(); };
+
+struct B : virtual A<char> { };
+struct C : virtual A<char> { };
+
+struct D : B, C {
+ D();
+};
+
+// CHECK: define void @_ZN6PR62511DC1Ev
+// CHECK: call void @_ZN6PR62511AIcEC2Ev
+// CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev
+// CHECK: ret void
+D::D() { }
+
+}
diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
index a82fca7..c01c5ef 100644
--- a/test/CodeGenCXX/vtable-layout-abi-examples.cpp
+++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp
@@ -178,7 +178,6 @@ struct C : virtual public A { int j; };
// CHECK-NEXT: 7 | vcall_offset (-16)
// CHECK-NEXT: 8 | offset_to_top (-16)
// CHECK-NEXT: 9 | Test2::D RTTI
-// CHECK-NEXT: -- (Test2::A, 16) vtable address --
// CHECK-NEXT: -- (Test2::C, 16) vtable address --
// CHECK-NEXT: 10 | [unused] void Test2::A::f()
struct D : public B, public C {
diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp
index bc3d54b..3a0dae4 100644
--- a/test/CodeGenCXX/vtable-layout.cpp
+++ b/test/CodeGenCXX/vtable-layout.cpp
@@ -635,7 +635,6 @@ struct D : virtual B, virtual C { virtual void f(); };
// CHECK-NEXT: 9 | vcall_offset (-8)
// CHECK-NEXT: 10 | offset_to_top (-8)
// CHECK-NEXT: 11 | Test17::E RTTI
-// CHECK-NEXT: -- (Test17::A, 8) vtable address --
// CHECK-NEXT: -- (Test17::C, 8) vtable address --
// CHECK-NEXT: 12 | void Test17::E::f()
// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
@@ -693,7 +692,6 @@ struct C : A, B {
// CHECK-NEXT: 19 | vcall_offset (-16)
// CHECK-NEXT: 20 | offset_to_top (-16)
// CHECK-NEXT: 21 | Test18::D RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 22 | void Test18::D::f()
// CHECK-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
@@ -725,7 +723,6 @@ struct C : A, B {
// CHECK-NEXT: 9 | vcall_offset (0)
// CHECK-NEXT: 10 | offset_to_top (-8)
// CHECK-NEXT: 11 | Test18::C RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 12 | void Test18::B::f()
// CHECK-NEXT: 13 | [unused] void Test18::C::g()
@@ -745,7 +742,6 @@ struct C : A, B {
// CHECK-NEXT: 2 | vcall_offset (0)
// CHECK-NEXT: 3 | offset_to_top (0)
// CHECK-NEXT: 4 | Test18::B RTTI
-// CHECK-NEXT: -- (Test18::A, 16) vtable address --
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
// CHECK-NEXT: 5 | void Test18::B::f()
// CHECK-NEXT: 6 | [unused] void Test18::A::g()
@@ -881,9 +877,6 @@ class E : virtual C { };
// CHECK-NEXT: 12 | vcall_offset (-8)
// CHECK-NEXT: 13 | offset_to_top (-8)
// CHECK-NEXT: 14 | Test21::F RTTI
-// CHECK-NEXT: -- (Test21::A, 8) vtable address --
-// CHECK-NEXT: -- (Test21::B, 8) vtable address --
-// CHECK-NEXT: -- (Test21::C, 8) vtable address --
// CHECK-NEXT: -- (Test21::E, 8) vtable address --
// CHECK-NEXT: 15 | [unused] void Test21::F::f()
//
@@ -1012,7 +1005,6 @@ struct C : virtual A { };
// CHECK-NEXT: 6 | vcall_offset (-8)
// CHECK-NEXT: 7 | offset_to_top (-8)
// CHECK-NEXT: 8 | Test24::D RTTI
-// CHECK-NEXT: -- (Test24::A, 8) vtable address --
// CHECK-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-NEXT: 9 | [unused] void Test24::D::f()
@@ -1030,14 +1022,13 @@ struct C : virtual A { };
// CHECK-NEXT: 1 | vcall_offset (-8)
// CHECK-NEXT: 2 | offset_to_top (0)
// CHECK-NEXT: 3 | Test24::C RTTI
-// CHECK-NEXT: -- (Test24::A, 8) vtable address --
// CHECK-NEXT: -- (Test24::C, 8) vtable address --
// CHECK-NEXT: 4 | [unused] void Test24::A::f()
// CHECK-NEXT: 5 | vcall_offset (0)
-// CHECK-NEXT: 6 | offset_to_top (8)
-// CHECK-NEXT: 7 | Test24::C RTTI
-// CHECK-NEXT: -- (Test24::A, 0) vtable address --
-// CHECK-NEXT: 8 | void Test24::A::f()
+// CHECK-NEXT: 6 | offset_to_top (8)
+// CHECK-NEXT: 7 | Test24::C RTTI
+// CHECK-NEXT: -- (Test24::A, 0) vtable address --
+// CHECK-NEXT: 8 | void Test24::A::f()
struct D : B, C {
virtual void f();
};
@@ -1071,7 +1062,6 @@ struct B : virtual V { };
// CHECK-NEXT: 8 | offset_to_top (-8)
// CHECK-NEXT: 9 | Test25::C RTTI
// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: -- (Test25::V, 8) vtable address --
// CHECK-NEXT: 10 | [unused] void Test25::V::f()
// CHECK: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries).
@@ -1089,7 +1079,6 @@ struct B : virtual V { };
// CHECK-NEXT: 2 | offset_to_top (0)
// CHECK-NEXT: 3 | Test25::B RTTI
// CHECK-NEXT: -- (Test25::B, 8) vtable address --
-// CHECK-NEXT: -- (Test25::V, 8) vtable address --
// CHECK-NEXT: 4 | [unused] void Test25::V::f()
// CHECK-NEXT: 5 | vcall_offset (0)
// CHECK-NEXT: 6 | offset_to_top (8)
@@ -1284,3 +1273,33 @@ struct E : D {
void E::e() { }
}
+
+namespace Test29 {
+
+// Test that the covariant return thunk for B::f will have a virtual 'this' adjustment,
+// matching gcc.
+
+struct V1 { };
+struct V2 : virtual V1 { };
+
+struct A {
+ virtual V1 *f();
+};
+
+// CHECK: Vtable for 'Test29::B' (6 entries).
+// CHECK-NEXT: 0 | vbase_offset (0)
+// CHECK-NEXT: 1 | vcall_offset (0)
+// CHECK-NEXT: 2 | offset_to_top (0)
+// CHECK-NEXT: 3 | Test29::B RTTI
+// CHECK-NEXT: -- (Test29::A, 0) vtable address --
+// CHECK-NEXT: -- (Test29::B, 0) vtable address --
+// CHECK-NEXT: 4 | Test29::V2 *Test29::B::f()
+// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset]
+// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT: 5 | Test29::V2 *Test29::B::f()
+struct B : virtual A {
+ virtual V2 *f();
+};
+V2 *B::f() { return 0; }
+
+}
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index 63e17431..a4ea2a1 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -84,54 +84,54 @@ void use_F(F<char> &fc) {
// CHECK: @_ZTV1B = external constant
// C has no key function, so its vtable should have weak_odr linkage.
+// CHECK: @_ZTV1C = weak_odr constant
// CHECK: @_ZTS1C = weak_odr constant
// CHECK: @_ZTI1C = weak_odr constant
-// CHECK: @_ZTV1C = weak_odr constant
// D has a key function that is defined in this translation unit so its vtable is
// defined in the translation unit.
+// CHECK: @_ZTV1D = constant
// CHECK: @_ZTS1D = constant
// 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: @_ZTV1EIcE = constant
// 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: @_ZTV1EIsE = weak_odr constant
// 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: @_ZTV1FIsE = weak_odr constant
// 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: @_ZTV1EIlE = weak_odr constant
// 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: @_ZTV1FIlE = weak_odr constant
// 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: @_ZTV1FIiE = weak_odr constant
// 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
@@ -140,14 +140,14 @@ void use_F(F<char> &fc) {
// The anonymous struct for e has no linkage, so the vtable should have
// internal linkage.
+// CHECK: @"_ZTV3$_0" = internal constant
// CHECK: @"_ZTS3$_0" = internal constant
// CHECK: @"_ZTI3$_0" = internal constant
-// CHECK: @"_ZTV3$_0" = internal constant
// The A vtable should have internal linkage since it is inside an anonymous
// namespace.
+// CHECK: @_ZTVN12_GLOBAL__N_11AE = internal constant
// 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/CodeGenObjC/complex-property.m b/test/CodeGenObjC/complex-property.m
new file mode 100644
index 0000000..5a2b78b
--- /dev/null
+++ b/test/CodeGenObjC/complex-property.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s
+// rdar: // 7351147
+
+@interface A
+@property __complex int COMPLEX_PROP;
+- (__complex int)y;
+- (void) setY : (__complex int)rhs;
+@end
+
+void f0(A *a) {
+ _Complex int a1 = 25 + 10i;
+ a.COMPLEX_PROP += a1;
+ a.y += a1;
+}
+
+// CHECK-LP64: internal global [13 x i8] c"COMPLEX_PROP
+// CHECK-LP64: internal global [17 x i8] c"setCOMPLEX_PROP
+
+// rdar: // 7351147
+@interface B
+@property (assign) _Complex float f_complex_ivar;
+@end
+
+@implementation B
+
+@synthesize f_complex_ivar = _f_complex_ivar;
+-(void) unary_f_complex: (_Complex float) a0 {
+ self.f_complex_ivar = a0;
+}
+
+@end
+
diff --git a/test/CodeGenObjC/objc2-nonfragile-abi-impl.m b/test/CodeGenObjC/objc2-nonfragile-abi-impl.m
new file mode 100644
index 0000000..ff94330
--- /dev/null
+++ b/test/CodeGenObjC/objc2-nonfragile-abi-impl.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi2 -emit-llvm -o %t %s
+// rdar://7547942.
+
+@interface Base @end
+
+@interface Sub1 : Base @end
+
+@implementation Sub1 @end
+
+@implementation Base {
+@private
+ id ivar;
+}
+@end
+
diff --git a/test/Driver/nostdincxx.cpp b/test/Driver/nostdincxx.cpp
new file mode 100644
index 0000000..7e00555
--- /dev/null
+++ b/test/Driver/nostdincxx.cpp
@@ -0,0 +1,4 @@
+// RUN: %clangxx -nostdinc++ %s 2>&1 | FileCheck %s
+// XFAIL: win32
+// CHECK: file not found
+#include <vector>
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index ee93755..79c294b 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -37,3 +37,6 @@ protected:
class B : public A {
A::foo; // expected-warning{{access declarations are deprecated}}
};
+
+void f() throw();
+void f(); // expected-warning{{missing exception specification}}
diff --git a/test/Headers/c89.c b/test/Headers/c89.c
new file mode 100644
index 0000000..9e01ff9
--- /dev/null
+++ b/test/Headers/c89.c
@@ -0,0 +1,10 @@
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 -fsyntax-only -Xclang -verify -std=c89 %s
+
+// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
+// on win32 since we don't generally know how to find errno.h.
+
+#define __MM_MALLOC_H
+
+// PR6658
+#include <xmmintrin.h>
+
diff --git a/test/Sema/x86-intrinsics-headers.c b/test/Headers/x86-intrinsics-headers.c
index 24c2d92..24c2d92 100644
--- a/test/Sema/x86-intrinsics-headers.c
+++ b/test/Headers/x86-intrinsics-headers.c
diff --git a/test/Index/Inputs/remap-complete-to.c b/test/Index/Inputs/remap-complete-to.c
index 9f8be2c..30199db 100644
--- a/test/Index/Inputs/remap-complete-to.c
+++ b/test/Index/Inputs/remap-complete-to.c
@@ -1 +1,6 @@
-void f0() { }
+int f0(int *pointer1, float *pointer2) {
+ return pointer2 - pointer1;
+}
+
+void g() {
+
diff --git a/test/Index/cindex-on-invalid.m b/test/Index/cindex-on-invalid.m
index 7e190eb..d2d952d 100644
--- a/test/Index/cindex-on-invalid.m
+++ b/test/Index/cindex-on-invalid.m
@@ -1,7 +1,6 @@
-// RUN: not c-index-test -test-load-source local %s > %t 2> %t.err
-// RUN: FileCheck %s < %t.err
-// CHECK: error: expected identifier or '('
-// CHECK: Unable to load translation unit!
+// RUN: c-index-test -test-load-source local %s 2>&1 | FileCheck %s
int foo;
int
+
+// CHECK: cindex-on-invalid.m:6:70: error: expected identifier or '(' \ No newline at end of file
diff --git a/test/Index/print-usrs.c b/test/Index/print-usrs.c
new file mode 100644
index 0000000..9cd64f7
--- /dev/null
+++ b/test/Index/print-usrs.c
@@ -0,0 +1,17 @@
+// RUN: c-index-test -print-usr-file %s | FileCheck %s
+// This isn't really C code; it has a .c extension to get picked up by lit.
+ObjCClass NSObject
+ObjCCategory NSObject foo
+ObjCIvar x c:objc(cs)NSObject
+ObjCMethod foo: 0 c:objc(cs)NSObject
+ObjCMethod baz:with 1 c:objc(cs)NSObject
+ObjCProperty gimme c:objc(cs)NSObject
+ObjCProtocol blah
+// CHECK: c:objc(cs)NSObject
+// CHECK: c:objc(cy)NSObject^foo
+// CHECK: c:objc(cs)NSObject@^x
+// CHECK: c:objc(cs)NSObject(cm)foo:
+// CHECK: c:objc(cs)NSObject(im)baz:with
+// CHECK: c:objc(cs)NSObject(py)gimme
+// CHECK: c:objc(pl)blah
+
diff --git a/test/Index/recover-bad-code-rdar_7487294.c b/test/Index/recover-bad-code-rdar_7487294.c
index 97bb515..e060672 100644
--- a/test/Index/recover-bad-code-rdar_7487294.c
+++ b/test/Index/recover-bad-code-rdar_7487294.c
@@ -11,4 +11,3 @@ int foo(int x) {
// CHECK: 9:3: error: use of undeclared identifier 'help'
// CHECK: help
-// CHECK: 14:102: error: expected '}'
diff --git a/test/Index/remap-complete.c b/test/Index/remap-complete.c
index 9b7de06..813d1df 100644
--- a/test/Index/remap-complete.c
+++ b/test/Index/remap-complete.c
@@ -1,5 +1,8 @@
-// RUN: c-index-test -code-completion-at=%s:1:12 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:6:2 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s 2> %t.err | FileCheck %s
+// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t.err
// XFAIL: win32
-// CHECK: FunctionDecl:{ResultType void}{TypedText f0}{LeftParen (}{RightParen )}
+// CHECK: FunctionDecl:{ResultType int}{TypedText f0}{LeftParen (}
void f() { }
+
+// CHECK-DIAGS: remap-complete.c:2:19
diff --git a/test/PCH/changed-files.c b/test/PCH/changed-files.c
index dd08bdd..d1b603b 100644
--- a/test/PCH/changed-files.c
+++ b/test/PCH/changed-files.c
@@ -5,22 +5,24 @@ const char *s2 = m0;
// FIXME: This test fails inexplicably on Windows in a manner that makes it
// look like standard error isn't getting flushed properly.
-// RUN: true
-// RUNx: echo '#define m0 ""' > %t.h
-// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
-// RUNx: echo '' > %t.h
-// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
-// RUNx: grep "modified" %t.stderr
+// RUN: false
+// XFAIL: *
-// RUNx: echo '#define m0 000' > %t.h
-// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
-// RUNx: echo '' > %t.h
-// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
-// RUNx: grep "modified" %t.stderr
+// RUN: echo '#define m0 ""' > %t.h
+// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUN: echo '' > %t.h
+// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUN: grep "modified" %t.stderr
-// RUNx: echo '#define m0 000' > %t.h
-// RUNx: echo "#define m1 'abcd'" >> %t.h
-// RUNx: %clang_cc1 -emit-pch -o %t.h.pch %t.h
-// RUNx: echo '' > %t.h
-// RUNx: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
-// RUNx: grep "modified" %t.stderr
+// RUN: echo '#define m0 000' > %t.h
+// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUN: echo '' > %t.h
+// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUN: grep "modified" %t.stderr
+
+// RUN: echo '#define m0 000' > %t.h
+// RUN: echo "#define m1 'abcd'" >> %t.h
+// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUN: echo '' > %t.h
+// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2> %t.stderr
+// RUN: grep "modified" %t.stderr
diff --git a/test/Parser/cxx-default-args.cpp b/test/Parser/cxx-default-args.cpp
new file mode 100644
index 0000000..a084fb0
--- /dev/null
+++ b/test/Parser/cxx-default-args.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR6647
+class C {
+ // After the error, the rest of the tokens inside the default arg should be
+ // skipped, avoiding a "expected ';' after class" after 'undecl'.
+ void m(int x = undecl + 0); // expected-error {{use of undeclared identifier 'undecl'}}
+};
+
diff --git a/test/Parser/objc-messaging-neg-1.m b/test/Parser/objc-messaging-neg-1.m
index 0d0cb9d..4ddadb8 100644
--- a/test/Parser/objc-messaging-neg-1.m
+++ b/test/Parser/objc-messaging-neg-1.m
@@ -1,6 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+@interface A
++(void) foo:(int) a;
+@end
+
int main() {
id a;
[a bla:0 6:7]; // expected-error {{expected ']'}}
+ [A foo bar]; // expected-error {{expected ':'}}
+ [A foo bar bar1]; // expected-error {{expected ':'}}
}
diff --git a/test/Parser/statements.c b/test/Parser/statements.c
index a662c9b..bc7192a 100644
--- a/test/Parser/statements.c
+++ b/test/Parser/statements.c
@@ -57,3 +57,8 @@ void test6(void) {
int test7() {
return 4 // expected-error {{expected ';' after return statement}}
}
+
+void test8() {
+ // Should not skip '}' and produce a "expected '}'" error.
+ undecl // expected-error {{use of undeclared identifier 'undecl'}}
+}
diff --git a/test/Preprocessor/dependencies-and-pp.c b/test/Preprocessor/dependencies-and-pp.c
index d7bf4df..7877df3 100644
--- a/test/Preprocessor/dependencies-and-pp.c
+++ b/test/Preprocessor/dependencies-and-pp.c
@@ -1,5 +1,31 @@
+// Test -MT and -E flags, PR4063
+
// RUN: %clang -E -o %t.1 %s
// RUN: %clang -E -MD -MF %t.d -MT foo -o %t.2 %s
// RUN: diff %t.1 %t.2
// RUN: grep "foo:" %t.d
// RUN: grep "dependencies-and-pp.c" %t.d
+
+// Test -MQ flag without quoting
+
+// RUN: %clang -E -MD -MF %t.d -MQ foo -o %t %s
+// RUN: grep "foo:" %t.d
+
+// Test -MQ flag with quoting
+
+// RUN: %clang -E -MD -MF %t.d -MQ '$fo\ooo ooo\ ooo\\ ooo#oo' -o %t %s
+// RUN: fgrep '$$fo\ooo\ ooo\\\ ooo\\\\\ ooo\#oo:' %t.d
+
+// Test consecutive -MT flags
+
+// RUN: %clang -E -MD -MF %t.d -MT foo -MT bar -MT baz -o %t %s
+// RUN: diff %t.1 %t
+// RUN: fgrep "foo bar baz:" %t.d
+
+// Test consecutive -MT and -MQ flags
+
+// RUN: %clang -E -MD -MF %t.d -MT foo -MQ '$(bar)' -MT 'b az' -MQ 'qu ux' -MQ ' space' -o %t %s
+// RUN: fgrep 'foo $$(bar) b az qu\ ux \ space:' %t.d
+
+// TODO: Test default target without quoting
+// TODO: Test default target with quoting
diff --git a/test/Preprocessor/macro_disable.c b/test/Preprocessor/macro_disable.c
index d6509c3..d7859dc 100644
--- a/test/Preprocessor/macro_disable.c
+++ b/test/Preprocessor/macro_disable.c
@@ -1,5 +1,27 @@
-// RUN: %clang_cc1 -E %s | grep 'a: 2 + M_0(3)(4)(5);'
-// RUN: %clang_cc1 -E %s | grep 'b: 4 + 4 + 3 + 2 + 1 + M_0(3)(2)(1);'
+// RUN: %clang_cc1 %s -E | FileCheck -strict-whitespace %s
+// Check for C99 6.10.3.4p2.
+
+#define f(a) f(x * (a))
+#define x 2
+#define z z[0]
+f(f(z));
+// CHECK: f(2 * (f(2 * (z[0]))));
+
+
+
+#define A A B C
+#define B B C A
+#define C C A B
+A
+// CHECK: A B C A B A C A B C A
+
+
+// PR1820
+#define i(x) h(x
+#define h(x) x(void)
+extern int i(i));
+// CHECK: int i(void)
+
#define M_0(x) M_ ## x
#define M_1(x) x + M_0(0)
@@ -11,3 +33,11 @@
a: M_0(1)(2)(3)(4)(5);
b: M_0(5)(4)(3)(2)(1);
+// CHECK: a: 2 + M_0(3)(4)(5);
+// CHECK: b: 4 + 4 + 3 + 2 + 1 + M_0(3)(2)(1);
+
+#define n(v) v
+#define l m
+#define m l a
+c: n(m) X
+// CHECK: c: m a X
diff --git a/test/Preprocessor/macro_disable2.c b/test/Preprocessor/macro_disable2.c
deleted file mode 100644
index 229cf32..0000000
--- a/test/Preprocessor/macro_disable2.c
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_cc1 -E %s | grep 'A B C A B A C A B C A'
-
-#define A A B C
-#define B B C A
-#define C C A B
-
-A
-
diff --git a/test/Preprocessor/macro_disable3.c b/test/Preprocessor/macro_disable3.c
deleted file mode 100644
index eab0a5e..0000000
--- a/test/Preprocessor/macro_disable3.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 %s -E | FileCheck -strict-whitespace %s
-// Check for C99 6.10.3.4p2.
-
-#define f(a) f(x * (a))
-#define x 2
-#define z z[0]
-f(f(z));
-
-// CHECK: f(2 * (f(2 * (z[0]))));
-
diff --git a/test/Preprocessor/macro_disable4.c b/test/Preprocessor/macro_disable4.c
deleted file mode 100644
index 820858c..0000000
--- a/test/Preprocessor/macro_disable4.c
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clang_cc1 -P -E %s | grep 'int f(void)'
-// PR1820
-
-#define f(x) h(x
-#define h(x) x(void)
-extern int f(f));
diff --git a/test/Preprocessor/output_paste_avoid.c b/test/Preprocessor/output_paste_avoid.c
index 835a921..8c6173a 100644
--- a/test/Preprocessor/output_paste_avoid.c
+++ b/test/Preprocessor/output_paste_avoid.c
@@ -24,3 +24,7 @@ E: test(str)
// Should expand to L "str" not L"str"
// CHECK: E: L "str"
+// Should avoid producing >>=.
+#define equal =
+F: >>equal
+// CHECK: F: >> =
diff --git a/test/Sema/format-attribute.c b/test/Sema/attr-format.c
index 6e1bd0f..0fadf98 100644
--- a/test/Sema/format-attribute.c
+++ b/test/Sema/attr-format.c
@@ -32,3 +32,49 @@ int rdar6623513(void *, const char*, const char*, ...)
int rdar6623513_aux(int len, const char* s) {
rdar6623513(0, "hello", "%.*s", len, s);
}
+
+
+
+// same as format(printf(...))...
+void a2(const char *a, ...) __attribute__((format(printf0, 1,2))); // no-error
+void b2(const char *a, ...) __attribute__((format(printf0, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
+void c2(const char *a, ...) __attribute__((format(printf0, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
+void d2(const char *a, int c) __attribute__((format(printf0, 1,2))); // expected-error {{format attribute requires variadic function}}
+void e2(char *str, int c, ...) __attribute__((format(printf0, 2,3))); // expected-error {{format argument not a string type}}
+
+// FreeBSD usage
+#define __printf0like(fmt,va) __attribute__((__format__(__printf0__,fmt,va)))
+void null(int i, const char *a, ...) __printf0like(2,0); // no-error
+void null(int i, const char *a, ...) {
+ if (a)
+ (void)0/* vprintf(...) would go here */;
+}
+
+void callnull(void){
+ null(0, 0); // no error
+ null(0, (char*)0); // no error
+ null(0, (void*)0); // no error
+ null(0, (int*)0); // expected-warning {{incompatible pointer types}}
+}
+
+
+
+// PR4470
+int xx_vprintf(const char *, va_list);
+
+const char *foo(const char *format) __attribute__((format_arg(1)));
+
+void __attribute__((format(printf, 1, 0)))
+foo2(const char *fmt, va_list va) {
+ xx_vprintf(foo(fmt), va);
+}
+
+// PR6542
+extern void gcc_format (const char *, ...)
+ __attribute__ ((__format__(__gcc_diag__, 1, 2)));
+extern void gcc_cformat (const char *, ...)
+ __attribute__ ((__format__(__gcc_cdiag__, 1, 2)));
+extern void gcc_cxxformat (const char *, ...)
+ __attribute__ ((__format__(__gcc_cxxdiag__, 1, 2)));
+extern void gcc_tformat (const char *, ...)
+ __attribute__ ((__format__(__gcc_tdiag__, 1, 2)));
diff --git a/test/Sema/function-sentinel-attr.c b/test/Sema/attr-sentinel.c
index 9bcbec4..db90d07 100644
--- a/test/Sema/function-sentinel-attr.c
+++ b/test/Sema/attr-sentinel.c
@@ -11,9 +11,7 @@ void foo7 (int x, ...) __attribute__ ((__sentinel__(0))); // expected-note {{fun
void foo10 (int x, ...) __attribute__ ((__sentinel__(1,1)));
void foo12 (int x, ... ) ATTR; // expected-note {{function has been explicitly marked sentinel here}}
-int main ()
-{
-
+void test1() {
foo1(1, NULL); // OK
foo1(1, 0) ; // expected-warning {{missing sentinel in function call}}
foo5(1, NULL, 2); // OK
@@ -28,3 +26,23 @@ int main ()
foo12(1); // expected-warning {{not enough variable arguments in 'foo12' declaration to fit a sentinel}}
}
+
+
+void (*e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
+
+void test2() {
+ void (*b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)); // expected-note {{function has been explicitly marked sentinel here}}
+ void (*z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))); // expected-note {{function has been explicitly marked sentinel here}}
+
+
+ void (*y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))); // expected-note {{function has been explicitly marked sentinel here}}
+
+ b(1, "%s", (void*)0); // OK
+ b(1, "%s", 0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s", (void*)0, 1, 0); // OK
+
+ y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}}
+
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
+}
diff --git a/test/Sema/attr-unused.c b/test/Sema/attr-unused.c
index e45ec43..2871514 100644
--- a/test/Sema/attr-unused.c
+++ b/test/Sema/attr-unused.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: %clang_cc1 -verify -Wunused-variable -fsyntax-only %s
static void (*fp0)(void) __attribute__((unused));
@@ -10,3 +10,18 @@ int f1() __attribute__((unused));
int g0 __attribute__((unused));
int f2() __attribute__((unused(1, 2))); // expected-error {{attribute requires 0 argument(s)}}
+
+struct Test0_unused {} __attribute__((unused));
+struct Test0_not_unused {};
+typedef int Int_unused __attribute__((unused));
+typedef int Int_not_unused;
+
+void test0() {
+ int x; // expected-warning {{unused variable}}
+
+ Int_not_unused i0; // expected-warning {{unused variable}}
+ Int_unused i1;
+
+ struct Test0_not_unused s0; // expected-warning {{unused variable}}
+ struct Test0_unused s1;
+}
diff --git a/test/Sema/format-attr-pr4470.c b/test/Sema/format-attr-pr4470.c
deleted file mode 100644
index 374d8b3..0000000
--- a/test/Sema/format-attr-pr4470.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wformat=2 %s
-
-#include <stdarg.h>
-int vprintf(const char *, va_list);
-
-const char *foo(const char *format) __attribute__((format_arg(1)));
-
-void __attribute__((format(printf, 1, 0)))
-foo2(const char *fmt, va_list va)
-{
- vprintf(foo(fmt), va);
-}
diff --git a/test/Sema/format-attribute-printf0.c b/test/Sema/format-attribute-printf0.c
deleted file mode 100644
index 33e8d40..0000000
--- a/test/Sema/format-attribute-printf0.c
+++ /dev/null
@@ -1,26 +0,0 @@
-//RUN: %clang_cc1 -fsyntax-only -verify %s
-
-#include <stdarg.h>
-
-// same as format(printf(...))...
-void a2(const char *a, ...) __attribute__((format(printf0, 1,2))); // no-error
-void b2(const char *a, ...) __attribute__((format(printf0, 1,1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
-void c2(const char *a, ...) __attribute__((format(printf0, 0,2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
-void d2(const char *a, int c) __attribute__((format(printf0, 1,2))); // expected-error {{format attribute requires variadic function}}
-void e2(char *str, int c, ...) __attribute__((format(printf0, 2,3))); // expected-error {{format argument not a string type}}
-
-// FreeBSD usage
-#define __printf0like(fmt,va) __attribute__((__format__(__printf0__,fmt,va)))
-void null(int i, const char *a, ...) __printf0like(2,0); // no-error
-void null(int i, const char *a, ...) {
- if (a)
- (void)0/* vprintf(...) would go here */;
-}
-
-void callnull(void){
- null(0, 0); // no error
- null(0, (char*)0); // no error
- null(0, (void*)0); // no error
- null(0, (int*)0); // expected-warning {{incompatible pointer types}}
-}
-
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 4db775f..dcc4c35 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -238,3 +238,16 @@ void test_positional_arguments() {
printf("%2$*8$d", (int) 2, (int) 3); // expected-warning{{specified field width is missing a matching 'int' argument}}
}
+// PR 6697 - Handle format strings where the data argument is not adjacent to the format string
+void myprintf_PR_6697(const char *format, int x, ...) __attribute__((__format__(printf,1, 3)));
+void test_pr_6697() {
+ myprintf_PR_6697("%s\n", 1, "foo"); // no-warning
+ myprintf_PR_6697("%s\n", 1, (int)0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+ // FIXME: Not everything should clearly support positional arguments,
+ // but we need a way to identify those cases.
+ myprintf_PR_6697("%1$s\n", 1, "foo"); // no-warning
+ myprintf_PR_6697("%2$s\n", 1, "foo"); // expected-warning{{data argument position '2' exceeds the number of data arguments (1)}}
+ myprintf_PR_6697("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (1)}}
+ myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{conversion specifies type 'char *' but the argument has type 'int'}}
+}
+
diff --git a/test/Sema/function-pointer-sentinel-attribute.c b/test/Sema/function-pointer-sentinel-attribute.c
deleted file mode 100644
index 5f17a26..0000000
--- a/test/Sema/function-pointer-sentinel-attribute.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-void (*e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
-
-int main() {
- void (*b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)); // expected-note {{function has been explicitly marked sentinel here}}
- void (*z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))); // expected-note {{function has been explicitly marked sentinel here}}
-
-
- void (*y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))); // expected-note {{function has been explicitly marked sentinel here}}
-
- b(1, "%s", (void*)0); // OK
- b(1, "%s", 0); // expected-warning {{missing sentinel in function call}}
- z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in function call}}
- z(1, "%s", (void*)0, 1, 0); // OK
-
- y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}}
-
- y(1, "%s", (void*)0,3,4,5,6,7); // OK
-}
diff --git a/test/Sema/init.c b/test/Sema/init.c
index c271248..b9867cf 100644
--- a/test/Sema/init.c
+++ b/test/Sema/init.c
@@ -75,7 +75,8 @@ int sym_fw1a_scr[] = {
};
// PR3001
-struct s1 s2 = {
+struct s1 s2 = { // expected-error {{variable has incomplete type 'struct s1'}} \
+ // expected-note {{forward declaration of 'struct s1'}}
.a = sizeof(struct s3), // expected-error {{invalid application of 'sizeof'}} \
// expected-note{{forward declaration of 'struct s3'}}
.b = bogus // expected-error {{use of undeclared identifier 'bogus'}}
diff --git a/test/Sema/nested-redef.c b/test/Sema/nested-redef.c
index 6a19921..bbc4859 100644
--- a/test/Sema/nested-redef.c
+++ b/test/Sema/nested-redef.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct X { // expected-note{{previous definition is here}}
- struct X { } x; // expected-error{{nested redefinition of 'X'}} \
- // expected-error{{field has incomplete type}}
+ struct X { } x; // expected-error{{nested redefinition of 'X'}}
};
struct Y { };
diff --git a/test/Sema/return.c b/test/Sema/return.c
index 3ab23f4..fab6a82 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -222,3 +222,20 @@ void test32() {
void test33() {
if (j) while (1) { }
}
+
+// Test that 'static inline' functions are only analyzed for CFG-based warnings
+// when they are used.
+static inline int si_has_missing_return() {} // no-warning
+static inline int si_has_missing_return_2() {}; // expected-warning{{control reaches end of non-void function}}
+static inline int si_forward();
+static inline int si_has_missing_return_3(int x) {
+ if (x)
+ return si_has_missing_return_3(x+1);
+} // expected-warning{{control may reach end of non-void function}}
+
+int test_static_inline(int x) {
+ si_forward();
+ return x ? si_has_missing_return_2() : si_has_missing_return_3(x);
+}
+static inline int si_forward() {} // expected-warning{{control reaches end of non-void function}}
+
diff --git a/test/Sema/struct-packed-align.c b/test/Sema/struct-packed-align.c
index 60a9feb..2b94567 100644
--- a/test/Sema/struct-packed-align.c
+++ b/test/Sema/struct-packed-align.c
@@ -37,6 +37,14 @@ struct __attribute__((packed)) packed_fas {
extern int d1[sizeof(struct packed_fas) == 1 ? 1 : -1];
extern int d2[__alignof(struct packed_fas) == 1 ? 1 : -1];
+struct packed_after_fas {
+ char a;
+ int b[];
+} __attribute__((packed));
+
+extern int d1_2[sizeof(struct packed_after_fas) == 1 ? 1 : -1];
+extern int d2_2[__alignof(struct packed_after_fas) == 1 ? 1 : -1];
+
// Alignment
struct __attribute__((aligned(8))) as1 {
diff --git a/test/Sema/warn-gnu-designators.c b/test/Sema/warn-gnu-designators.c
new file mode 100644
index 0000000..d5ac8cf
--- /dev/null
+++ b/test/Sema/warn-gnu-designators.c
@@ -0,0 +1,2 @@
+// RUN: %clang_cc1 -Wno-gnu-designator -verify %s
+struct { int x, y, z[12] } value = { x:17, .z [3 ... 5] = 7 };
diff --git a/test/Sema/warn-shadow.c b/test/Sema/warn-shadow.c
index c9a783b..a112210 100644
--- a/test/Sema/warn-shadow.c
+++ b/test/Sema/warn-shadow.c
@@ -43,3 +43,8 @@ void test3(void) {
void test4(int i) { // expected-warning {{declaration shadows a variable in the global scope}}
}
+
+// Don't warn about shadowing for function declarations.
+void test5(int i);
+void test6(void (*f)(int i)) {}
+void test7(void *context, void (*callback)(void *context)) {}
diff --git a/test/SemaCXX/PR6618.cpp b/test/SemaCXX/PR6618.cpp
new file mode 100644
index 0000000..10d4dc8
--- /dev/null
+++ b/test/SemaCXX/PR6618.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+class bar; // expected-note {{forward declaration of 'bar'}}
+struct zed {
+ bar g; // expected-error {{field has incomplete type}}
+};
+class baz {
+ zed h;
+};
+void f() {
+ enum {
+ e = sizeof(baz)
+ };
+}
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index 1c6e790..7095d92 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -6,14 +6,48 @@ public:
};
struct D : S {
- D() : b1(0), b2(1), b1(0), S(), S() {} // expected-error {{multiple initializations given for non-static member 'b1'}} \
- // expected-note {{previous initialization is here}} \
- // expected-error {{multiple initializations given for base 'S'}} \
- // expected-note {{previous initialization is here}}
-
+ D() :
+ b1(0), // expected-note {{previous initialization is here}}
+ b2(1),
+ b1(0), // expected-error {{multiple initializations given for non-static member 'b1'}}
+ S(), // expected-note {{previous initialization is here}}
+ S() // expected-error {{multiple initializations given for base 'S'}}
+ {}
int b1;
int b2;
+};
+struct A {
+ struct {
+ int a;
+ int b;
+ };
+ A();
};
+A::A() : a(10), b(20) { }
+
+namespace Test1 {
+ template<typename T> struct A {};
+ template<typename T> struct B : A<T> {
+
+ B() : A<T>(), // expected-note {{previous initialization is here}}
+ A<T>() { } // expected-error {{multiple initializations given for base 'A<T>'}}
+ };
+}
+
+namespace Test2 {
+ template<typename T> struct A : T {
+ A() : T(), // expected-note {{previous initialization is here}}
+ T() { } // expected-error {{multiple initializations given for base 'T'}}
+ };
+}
+namespace Test3 {
+ template<typename T> struct A {
+ T t;
+
+ A() : t(1), // expected-note {{previous initialization is here}}
+ t(2) { } // expected-error {{multiple initializations given for non-static member 't'}}
+ };
+}
diff --git a/test/SemaCXX/class-layout.cpp b/test/SemaCXX/class-layout.cpp
index 2b8d1d3..f3c75f4 100644
--- a/test/SemaCXX/class-layout.cpp
+++ b/test/SemaCXX/class-layout.cpp
@@ -48,6 +48,13 @@ struct H : G { };
SA(6, sizeof(H) == 1);
+struct I {
+ char b;
+ int a;
+} __attribute__((packed));
+
+SA(6_1, sizeof(I) == 5);
+
// PR5580
namespace PR5580 {
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index accc8db..e2a966bd 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -7,7 +7,8 @@
struct ToBool { explicit operator bool(); };
struct B;
-struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
+struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} \
+ // expected-note 2 {{candidate is the implicit copy constructor}}
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
struct I { operator int(); };
struct J { operator I(); };
@@ -197,3 +198,18 @@ void test()
// *must* create a separate temporary copy of class objects. This can only
// be properly tested at runtime, though.
}
+
+namespace PR6595 {
+ struct String {
+ String(const char *);
+ operator const char*() const;
+ };
+
+ void f(bool Cond, String S) {
+ (void)(Cond? S : "");
+ (void)(Cond? "" : S);
+ const char a[1] = {'a'};
+ (void)(Cond? S : a);
+ (void)(Cond? a : S);
+ }
+}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 7010d2e..ae3dc86 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -78,3 +78,8 @@ namespace PR6421 {
}
};
}
+
+namespace PR6709 {
+ template<class T> class X { T v; ~X() { ++*v; } };
+ void a(X<int> x) {}
+}
diff --git a/test/SemaCXX/exception-spec.cpp b/test/SemaCXX/exception-spec.cpp
index 782cf83..498611e 100644
--- a/test/SemaCXX/exception-spec.cpp
+++ b/test/SemaCXX/exception-spec.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fms-extensions %s
// Straight from the standard:
// Plain function with spec
@@ -50,7 +50,7 @@ void r4() throw(int, float);
void r4() throw(float, int);
void r5() throw(int); // expected-note {{previous declaration}}
-void r5(); // expected-error {{exception specification in declaration does not match}}
+void r5(); // expected-warning {{missing exception specification}}
void r6() throw(...); // expected-note {{previous declaration}}
void r6() throw(int); // expected-error {{exception specification in declaration does not match}}
@@ -170,7 +170,7 @@ void fnptrs()
// Member function stuff
struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
-void Str1::f() // expected-error {{does not match previous declaration}}
+void Str1::f() // expected-warning {{missing exception specification}}
{
}
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
index 7b17afb..7307a47 100644
--- a/test/SemaCXX/invalid-member-expr.cpp
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -19,3 +19,21 @@ void test2() {
x->operator; // expected-error{{missing type specifier after 'operator'}}
x->operator typedef; // expected-error{{missing type specifier after 'operator'}}
}
+
+// PR6327
+namespace test3 {
+ template <class A, class B> struct pair {};
+
+ void test0() {
+ pair<int, int> z = minmax({}); // expected-error {{expected expression}}
+ }
+
+ struct string {
+ class iterator {};
+ };
+
+ void test1() {
+ string s;
+ string::iterator i = s.foo(); // expected-error {{no member named 'foo'}}
+ }
+}
diff --git a/test/SemaCXX/namespace-alias.cpp b/test/SemaCXX/namespace-alias.cpp
index 06114c3..3ea1ccf 100644
--- a/test/SemaCXX/namespace-alias.cpp
+++ b/test/SemaCXX/namespace-alias.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-namespace N { };
+namespace N { struct X { }; };
namespace A = N;
@@ -83,3 +83,11 @@ namespace K {
KC::func(); // expected-error {{undeclared identifier 'KC'}}
}
}
+
+// PR6341
+namespace A = N;
+namespace N { }
+namespace A = N;
+
+A::X nx;
+
diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp
index 2a9d31f..d47b707 100644
--- a/test/SemaCXX/namespace.cpp
+++ b/test/SemaCXX/namespace.cpp
@@ -68,3 +68,25 @@ namespace foo {
static foo::x test1; // ok
static foo::X test2; // typo: expected-error {{no type named 'X' in}}
+
+namespace PR6620 {
+ namespace numeric {
+ namespace op {
+ struct greater {};
+ }
+ namespace {
+ extern op::greater const greater;
+ }
+ }
+
+ namespace numeric {
+ namespace {
+ op::greater const greater = op::greater();
+ }
+
+ template<typename T, typename U>
+ int f(T& l, U& r)
+ { numeric::greater(l, r); }
+
+ }
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 8657c0d..9a611c3 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -64,7 +64,7 @@ void f2() {
A::C c1;
struct A::C c2;
struct S : public A::C {};
-struct A::undef; // expected-error {{'undef' does not name a tag member in the specified scope}}
+struct A::undef; // expected-error {{no struct named 'undef' in namespace 'A'}}
namespace A2 {
typedef int INT;
diff --git a/test/SemaCXX/new-delete-predefined-decl-2.cpp b/test/SemaCXX/new-delete-predefined-decl-2.cpp
new file mode 100644
index 0000000..981476d
--- /dev/null
+++ b/test/SemaCXX/new-delete-predefined-decl-2.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DQUALIFIED -fsyntax-only -verify %s
+
+// PR5904
+void f0(int *ptr) {
+#ifndef QUALIFIED
+ operator delete(ptr);
+#endif
+}
+
+void f1(int *ptr) {
+ ::operator delete[](ptr);
+}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index 54d41b8..4846e72 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -138,3 +138,12 @@ struct a {
a a;
int a::sa = a.a; // expected-error {{invalid use of nonstatic data member 'a'}}
+
+
+namespace PR6645 {
+ typedef int foo;
+ namespace Inner {
+ typedef int PR6645::foo; // expected-error{{typedef declarator cannot be qualified}} \
+ // expected-error{{definition or redeclaration of 'foo' not in a namespace enclosing 'PR6645'}}
+ }
+}
diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp
index 2630278..a5dd7e2 100644
--- a/test/SemaCXX/static-cast.cpp
+++ b/test/SemaCXX/static-cast.cpp
@@ -60,7 +60,7 @@ void t_529_2()
(void)static_cast<A*>((H*)0); // expected-error {{ambiguous conversion}}
(void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
(void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'B **' to 'A **' is not allowed}}
- (void)static_cast<char&>(i); // expected-error {{non-const lvalue reference to type 'char' cannot be initialized with a value of type 'int'}}
+ (void)static_cast<char&>(i); // expected-error {{non-const lvalue reference to type 'char' cannot bind to a value of unrelated type 'int'}}
}
// Anything to void
@@ -91,7 +91,7 @@ void t_529_5_8()
(void)static_cast<H*>((A*)0); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous cast from base 'A' to derived 'H':\n struct A -> struct B -> struct G1 -> struct H\n struct A -> struct B -> struct G2 -> struct H}}
(void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'B *' to 'E *' is not allowed}}
- (void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'E' cannot be initialized with a value of type 'B'}}
+ (void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'E' cannot bind to a value of unrelated type 'B'}}
// TODO: Test inaccessible base in context where it's accessible, i.e.
// member function and friend.
diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
index 2634202..f419156 100644
--- a/test/SemaCXX/warn-reorder-ctor-initialization.cpp
+++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -87,3 +87,15 @@ class Anon3 {
union {int a,b;};
Anon3() : b(1) {}
};
+
+namespace T1 {
+
+struct S1 { };
+struct S2: virtual S1 { };
+struct S3 { };
+
+struct S4: virtual S3, S2 {
+ S4() : S2(), // expected-warning {{base class 'T1::S2' will be initialized after}}
+ S3() { }; // expected-note {{base 'T1::S3'}}
+};
+}
diff --git a/test/SemaObjC/block-type-safety.m b/test/SemaObjC/block-type-safety.m
index dab0af4..b40f9b0 100644
--- a/test/SemaObjC/block-type-safety.m
+++ b/test/SemaObjC/block-type-safety.m
@@ -34,11 +34,11 @@ void test1() {
r0(^Super* () { return 0; }); // OK
r0(^Sub* () { return 0; }); // OK, variable of type Super* gets return value of type Sub*
- r0(^id () { return 0; }); // expected-error {{incompatible block pointer types passing 'id (^)(void)', expected 'Super *(^)()'}}
+ r0(^id () { return 0; });
r1(^Super* () { return 0; }); // expected-error {{incompatible block pointer types passing 'Super *(^)(void)', expected 'Sub *(^)()'}}
r1(^Sub* () { return 0; }); // OK
- r1(^id () { return 0; }); // expected-error {{incompatible block pointer types passing 'id (^)(void)', expected 'Sub *(^)()'}}
+ r1(^id () { return 0; });
r2(^id<NSObject>() { return 0; });
}
@@ -60,7 +60,7 @@ void f1(void (^f)(id x)) {
void test2(void)
{
f0(^(id a) { }); // OK
- f1(^(A* a) { }); // expected-error {{incompatible block pointer types passing 'void (^)(A *)', expected 'void (^)(id)'}}
+ f1(^(A* a) { });
f1(^(id<NSObject> a) { }); // OK
}
@@ -80,7 +80,7 @@ void test2(void)
// programmer wants to write this:
-printMyThings1 {
- [myThings enumerateObjectsWithBlock: ^(MyThing *obj) { // expected-error {{incompatible block pointer types sending 'void (^)(MyThing *)', expected 'void (^)(id)'}}
+ [myThings enumerateObjectsWithBlock: ^(MyThing *obj) {
[obj printThing];
}];
}
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
index 24324f8..18cbb83 100644
--- a/test/SemaObjC/category-1.m
+++ b/test/SemaObjC/category-1.m
@@ -62,16 +62,16 @@
// <rdar://problem/7249233>
@protocol MultipleCat_P
--(void) im0;
+-(void) im0; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end
-@interface MultipleCat_I @end
+@interface MultipleCat_I @end // expected-note {{required for direct or indirect protocol 'MultipleCat_P'}}
@interface MultipleCat_I() @end
@interface MultipleCat_I() <MultipleCat_P> @end
-@implementation MultipleCat_I // expected-warning {{incomplete implementation}}, expected-warning {{method definition for 'im0' not found}}
+@implementation MultipleCat_I // expected-warning {{incomplete implementation}}
@end
// <rdar://problem/7680391> - Handle nameless categories with no name that refer
diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m
index 497a1b6..08fb366 100644
--- a/test/SemaObjC/compare-qualified-id.m
+++ b/test/SemaObjC/compare-qualified-id.m
@@ -5,7 +5,7 @@ typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
-@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
+@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@interface NSObject <NSObject> {} @end
@@ -15,7 +15,7 @@ typedef struct {} NSFastEnumerationState;
@interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey; @end
extern NSString * const NSTaskDidTerminateNotification;
-@interface XCPropertyExpansionContext : NSObject <NSCopying> {
+@interface XCPropertyExpansionContext : NSObject <NSCopying> { // expected-note {{required for direct or indirect protocol 'NSCopying'}}
NSMutableDictionary * _propNamesToPropValuesCache;
} @end
@@ -23,8 +23,7 @@ extern NSString * const NSTaskDidTerminateNotification;
- (NSString *)evaluateAsStringInContext:(XCPropertyExpansionContext *)context withNestingState:(const void *)state;
@end
-@implementation XCPropertyExpansionContext // expected-warning {{method definition for 'copyWithZone:' not found}} \
- // expected-warning {{incomplete implementation}}
+@implementation XCPropertyExpansionContext // expected-warning {{incomplete implementation}}
- (NSString *)expandedValueForProperty:(NSString *)property {
id <XCPropertyValues> cachedValueNode = [_propNamesToPropValuesCache objectForKey:property]; // expected-warning {{method '-objectForKey:' not found (return type defaults to 'id')}}
if (cachedValueNode == ((void *)0)) { }
diff --git a/test/SemaObjC/comptypes-7.m b/test/SemaObjC/comptypes-7.m
index fedad1b..2519c41 100644
--- a/test/SemaObjC/comptypes-7.m
+++ b/test/SemaObjC/comptypes-7.m
@@ -66,5 +66,10 @@ int main()
if (obj_C == j) foo() ; // expected-warning {{comparison of distinct pointer types ('Class' and 'int *')}}
if (j == obj_C) foo() ; // expected-warning {{comparison of distinct pointer types ('int *' and 'Class')}}
+ Class bar1 = Nil;
+ Class <MyProtocol> bar = Nil;
+ bar = bar1;
+ bar1 = bar;
+
return 0;
}
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index 914e3ca..1436f7e 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -21,10 +21,10 @@
@end
@interface DTFilterOutputStream2
-- nextOutputStream;
+- nextOutputStream; // expected-note {{{{method definition for 'nextOutputStream' not found}}
@end
-@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'nextOutputStream' not found}}
+@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
self = nextOutputStream; // expected-warning {{incompatible type assigning 'id<DTOutputStreams>', expected 'DTFilterOutputStream2 *'}}
diff --git a/test/SemaObjC/gcc-cast-ext.m b/test/SemaObjC/gcc-cast-ext.m
index 28abfbc..599e37d 100644
--- a/test/SemaObjC/gcc-cast-ext.m
+++ b/test/SemaObjC/gcc-cast-ext.m
@@ -5,8 +5,8 @@ typedef struct _NSRange { } NSRange;
@class PBXFileReference;
@interface PBXDocBookmark
-+ alloc;
-- autorelease;
++ alloc; // expected-note {{{{method definition for 'alloc' not found}}
+- autorelease; // expected-note {{{{method definition for 'autorelease' not found}}
@end
// GCC allows pointer expressions in integer constant expressions.
@@ -14,7 +14,7 @@ struct {
char control[((int)(char *)2)];
} xx;
-@implementation PBXDocBookmark // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'autorelease' not found}} expected-warning {{method definition for 'alloc' not found}}
+@implementation PBXDocBookmark // expected-warning {{incomplete implementation}}
+ (id)bookmarkWithFileReference:(PBXFileReference *)fileRef gylphRange:(NSRange)range anchor:(NSString *)htmlAnchor
{
diff --git a/test/SemaObjC/ivar-in-class-extension-error.m b/test/SemaObjC/ivar-in-class-extension-error.m
new file mode 100644
index 0000000..ffc0e8b
--- /dev/null
+++ b/test/SemaObjC/ivar-in-class-extension-error.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar:// 6812436
+
+@interface A @end
+
+@interface A () { // expected-error {{ivars may not be placed in class extension}}
+ int _p0;
+}
+@property int p0;
+@end
+
+@interface A(CAT) { // expected-error {{ivars may not be placed in categories}}
+ int _p1;
+}
+@end
diff --git a/test/SemaObjC/ivar-in-implementations.m b/test/SemaObjC/ivar-in-implementations.m
index 32d3c35..4060526 100644
--- a/test/SemaObjC/ivar-in-implementations.m
+++ b/test/SemaObjC/ivar-in-implementations.m
@@ -11,12 +11,29 @@
@implementation INTFSTANDALONE : Super // expected-warning {{class implementation may not have super class}}
{
-@private
- id IVAR1;
+ id PRIV_IVAR;
@protected
- id IVAR2; // expected-error {{only private ivars may be declared in implementation}}
+ id PRTCTD;
@private
id IVAR3;
int IVAR; // expected-error {{instance variable is already declared}}
+@public
+ id IVAR4;
}
@end
+
+@interface Base @end
+
+@implementation Base {
+ int ivar1;
+@public
+ int ivar2;
+}
+@end
+
+id fn1(INTFSTANDALONE *b) { return b->PRIV_IVAR; } // expected-error {{instance variable 'PRIV_IVAR' is private}}
+
+id fn2(INTFSTANDALONE *b) { return b->PRTCTD; } // expected-error {{instance variable 'PRTCTD' is protected}}
+
+id fn4(INTFSTANDALONE *b) { return b->IVAR4; }
+
diff --git a/test/SemaObjC/ivar-sem-check-1.m b/test/SemaObjC/ivar-sem-check-1.m
index 099a7a6..de038f5 100644
--- a/test/SemaObjC/ivar-sem-check-1.m
+++ b/test/SemaObjC/ivar-sem-check-1.m
@@ -9,8 +9,7 @@ typedef int FOO();
int arr[]; // expected-error {{field has incomplete type}}
struct S IC; // expected-error {{field has incomplete type}}
struct T { // expected-note {{previous definition is here}}
- struct T {} X; // expected-error {{nested redefinition of 'T'}} \
- // expected-error {{field has incomplete type}}
+ struct T {} X; // expected-error {{nested redefinition of 'T'}}
}YYY;
FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}}
int kaka; // expected-note {{previous declaration is here}}
diff --git a/test/SemaObjC/method-arg-decay.m b/test/SemaObjC/method-arg-decay.m
index f600029..012a3ee 100644
--- a/test/SemaObjC/method-arg-decay.m
+++ b/test/SemaObjC/method-arg-decay.m
@@ -56,7 +56,7 @@ PBXFindMatchContains, PBXFindMatchStartsWith, PBXFindMatchWholeWords,
@interface PBXProjectModule : PBXModule <PBXFindableText> {
}
@end @class PBXBookmark;
-@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection;
+@protocol PBXSelectionTarget - (NSObject <PBXSelectionTarget> *) performAction:(id)action withSelection:(NSArray *)selection; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end @class XCPropertyDictionary, XCPropertyCondition, XCPropertyConditionSet, XCMutablePropertyConditionSet;
extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExposedModulesOnly);
@interface NSString (StringUtilities) - (NSString *) trimToLength:(NSInteger)length preserveRange:(NSRange)range;
@@ -67,14 +67,12 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos
@interface XCExtendedTabView : NSTabView <XCDockViewHeader> {
}
@end @class PBXProjectDocument, PBXFileReference, PBXModule, XCWindowTool;
-@interface XCPerspectiveModule : PBXProjectModule <PBXSelectionTarget> {
+@interface XCPerspectiveModule : PBXProjectModule <PBXSelectionTarget> { // expected-note {{required for direct or indirect protocol 'PBXSelectionTarget'}}
XCExtendedTabView *_perspectivesTabView;
}
-- (PBXModule *) moduleForTab:(NSTabViewItem *)item;
+- (PBXModule *) moduleForTab:(NSTabViewItem *)item; // expected-note {{method definition for 'moduleForTab:' not found}}
@end
-@implementation XCPerspectiveModule // expected-warning {{method definition for 'moduleForTab:' not found}} \
- // expected-warning {{method definition for 'performAction:withSelection:' not found}} \
- // expected-warning {{incomplete implementation}}
+@implementation XCPerspectiveModule // expected-warning {{incomplete implementation}}
+ (void) openForProjectDocument:(PBXProjectDocument *)projectDocument {
}
- (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data {
diff --git a/test/SemaObjC/method-undef-category-warn-1.m b/test/SemaObjC/method-undef-category-warn-1.m
index 75ca5b5..b367801 100644
--- a/test/SemaObjC/method-undef-category-warn-1.m
+++ b/test/SemaObjC/method-undef-category-warn-1.m
@@ -1,30 +1,26 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface MyClass1
+@interface MyClass1
@end
@protocol P
-- (void) Pmeth;
-- (void) Pmeth1;
+- (void) Pmeth; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+- (void) Pmeth1; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end
-@interface MyClass1(CAT) <P>
-- (void) meth2;
+@interface MyClass1(CAT) <P> // expected-note {{required for direct or indirect protocol 'P'}}
+- (void) meth2; // expected-note {{method definition for 'meth2' not found}}
@end
-@implementation MyClass1(CAT) // expected-warning {{incomplete implementation}} \
- expected-warning {{method definition for 'meth2' not found}} \
- expected-warning {{method definition for 'Pmeth' not found}}
+@implementation MyClass1(CAT) // expected-warning {{incomplete implementation}}
- (void) Pmeth1{}
@end
-@interface MyClass1(DOG) <P>
-- (void)ppp;
+@interface MyClass1(DOG) <P> // expected-note {{required for direct or indirect protocol 'P'}}
+- (void)ppp; // expected-note {{method definition for 'ppp' not found}}
@end
-@implementation MyClass1(DOG) // expected-warning {{incomplete implementation}} \
- expected-warning {{method definition for 'ppp' not found}} \
- expected-warning {{method definition for 'Pmeth1' not found}}
+@implementation MyClass1(DOG) // expected-warning {{incomplete implementation}}
- (void) Pmeth {}
@end
diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m
index fc27870..1addcf7 100644
--- a/test/SemaObjC/method-undef-extension-warn-1.m
+++ b/test/SemaObjC/method-undef-extension-warn-1.m
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-@interface MyClass
+@interface MyClass // expected-note {{required for direct or indirect protocol 'P'}}
@end
@protocol P
- (void)Pmeth;
-- (void)Pmeth1;
+- (void)Pmeth1; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end
// Class extension
@interface MyClass () <P>
-- (void)meth2;
+- (void)meth2; // expected-note {{method definition for 'meth2' not found}}
@end
// Add a category to test that clang does not emit warning for this method.
@@ -18,8 +18,6 @@
- (void)categoryMethod;
@end
-@implementation MyClass // expected-warning {{incomplete implementation}} \
- expected-warning {{method definition for 'meth2' not found}} \
- expected-warning {{method definition for 'Pmeth1' not found}}
+@implementation MyClass // expected-warning {{incomplete implementation}}
- (void)Pmeth {}
@end
diff --git a/test/SemaObjC/method-undefined-warn-1.m b/test/SemaObjC/method-undefined-warn-1.m
index cfe1d56..1ebc59e 100644
--- a/test/SemaObjC/method-undefined-warn-1.m
+++ b/test/SemaObjC/method-undefined-warn-1.m
@@ -3,12 +3,12 @@
@interface INTF
- (void) meth;
- (void) meth : (int) arg1;
-- (int) int_meth;
-+ (int) cls_meth;
-+ (void) cls_meth1 : (int) arg1;
+- (int) int_meth; // expected-note {{method definition for 'int_meth' not found}}
++ (int) cls_meth; // expected-note {{method definition for 'cls_meth' not found}}
++ (void) cls_meth1 : (int) arg1; // expected-note {{method definition for 'cls_meth1:' not found}}
@end
-@implementation INTF // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'int_meth' not found}} expected-warning {{method definition for 'cls_meth' not found}} expected-warning {{method definition for 'cls_meth1:' not found}}
+@implementation INTF // expected-warning {{incomplete implementation}}
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
@@ -17,12 +17,12 @@
@interface INTF1
- (void) meth;
- (void) meth : (int) arg1;
-- (int) int_meth;
-+ (int) cls_meth;
-+ (void) cls_meth1 : (int) arg1;
+- (int) int_meth; // expected-note {{method definition for 'int_meth' not found}}
++ (int) cls_meth; // expected-note {{method definition for 'cls_meth' not found}}
++ (void) cls_meth1 : (int) arg1; // expected-note {{method definition for 'cls_meth1:' not found}}
@end
-@implementation INTF1 // expected-warning {{incomplete implementation}} expected-warning {{method definition for 'int_meth' not found}} expected-warning {{method definition for 'cls_meth' not found}} expected-warning {{method definition for 'cls_meth1:' not found}}
+@implementation INTF1 // expected-warning {{incomplete implementation}}
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
diff --git a/test/SemaObjC/method-warn-unused-attribute.m b/test/SemaObjC/method-warn-unused-attribute.m
index d9dcf99..042f442 100644
--- a/test/SemaObjC/method-warn-unused-attribute.m
+++ b/test/SemaObjC/method-warn-unused-attribute.m
@@ -1,8 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-value -verify %s
@interface INTF
-// Currently this is rejected by both GCC and Clang (and Clang was crashing on it).
-- (id) foo __attribute__((warn_unused_result)); // expected-warning{{warning: 'warn_unused_result' attribute only applies to function types}}
+- (id) foo __attribute__((warn_unused_result));
+- (void) garf __attribute__((warn_unused_result)); // expected-warning {{attribute 'warn_unused_result' cannot be applied to Objective-C method without return value}}
+- (int) fee __attribute__((warn_unused_result));
++ (int) c __attribute__((warn_unused_result));
@end
+void foo(INTF *a) {
+ [a garf];
+ [a fee]; // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}}
+ [INTF c]; // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}}
+}
+
diff --git a/test/SemaObjC/no-protocol-option-tests.m b/test/SemaObjC/no-protocol-option-tests.m
new file mode 100644
index 0000000..5d2da0a
--- /dev/null
+++ b/test/SemaObjC/no-protocol-option-tests.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -Wno-protocol -verify %s
+// rdar: // 7056600
+
+@protocol P
+- PMeth;
+@end
+
+// Test1
+@interface I <P> @end
+@implementation I @end // no warning with -Wno-protocol
+
+// Test2
+@interface C -PMeth; @end
+@interface C (Category) <P> @end
+@implementation C (Category) @end // no warning with -Wno-protocol
+
+// Test2
+@interface super - PMeth; @end
+@interface J : super <P>
+- PMeth; // expected-note {{ method definition for 'PMeth' not found}}
+@end
+@implementation J @end // expected-warning {{incomplete implementation}}
+
+// Test3
+@interface K : super <P>
+@end
+@implementation K @end // no warning with -Wno-protocol
+
+// Test4
+@interface Root @end
+@interface L : Root<P> @end
+@implementation L @end // no warning with -Wno-protocol
diff --git a/test/SemaObjC/nsobject-attribute.m b/test/SemaObjC/nsobject-attribute.m
index fdf9e35..13a4929 100644
--- a/test/SemaObjC/nsobject-attribute.m
+++ b/test/SemaObjC/nsobject-attribute.m
@@ -7,11 +7,16 @@ static CGColorRef tmp = 0;
typedef struct S1 __attribute__ ((NSObject)) CGColorRef1; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
typedef void * __attribute__ ((NSObject)) CGColorRef2; // expected-error {{__attribute ((NSObject)) is for pointer types only}}
+
@interface HandTested {
@public
CGColorRef x;
}
+
@property(copy) CGColorRef x;
+// rdar: // 7809460
+typedef struct CGColor *CGColorRefNoNSObject;
+@property (nonatomic, retain) __attribute__((NSObject)) CGColorRefNoNSObject color;
@end
void setProperty(id self, id value) {
@@ -24,6 +29,7 @@ id getProperty(id self) {
@implementation HandTested
@synthesize x=x;
+@dynamic color;
@end
int main(int argc, char *argv[]) {
diff --git a/test/SemaObjC/property-expression-error.m b/test/SemaObjC/property-expression-error.m
index b59c1b1..6b5cf04 100644
--- a/test/SemaObjC/property-expression-error.m
+++ b/test/SemaObjC/property-expression-error.m
@@ -16,3 +16,8 @@ int main() {
&object.index; // expected-error {{address of property expression requested}}
return 0;
}
+
+typedef int Foo;
+void test() {
+ Foo.x; // expected-error {{expected identifier or '('}}
+}
diff --git a/test/SemaObjC/property-in-class-extension.m b/test/SemaObjC/property-in-class-extension.m
new file mode 100644
index 0000000..3f252d0
--- /dev/null
+++ b/test/SemaObjC/property-in-class-extension.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar: // 7766184
+
+@interface Foo @end
+
+@interface Foo ()
+ @property (readonly) int bar;
+@end
+
+void FUNC () {
+ Foo *foo;
+ foo.bar = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+}
+
+
diff --git a/test/SemaObjC/property-ivar-mismatch.m b/test/SemaObjC/property-ivar-mismatch.m
index ea3acfc..16ff338 100644
--- a/test/SemaObjC/property-ivar-mismatch.m
+++ b/test/SemaObjC/property-ivar-mismatch.m
@@ -3,12 +3,12 @@
@interface Test4
{
- char ivar;
+ char ivar; // expected-note{{ivar is declared here}}
}
@property int prop;
@end
@implementation Test4
-@synthesize prop = ivar; // expected-error {{type of property 'prop' does not match type of ivar 'ivar'}}
+@synthesize prop = ivar; // expected-error {{type of property 'prop' ('int') does not match type of ivar 'ivar' ('char')}}
@end
diff --git a/test/SemaObjC/property.m b/test/SemaObjC/property.m
index b7f0fca..4d00bd2 100644
--- a/test/SemaObjC/property.m
+++ b/test/SemaObjC/property.m
@@ -2,7 +2,7 @@
@interface I
{
- int IVAR;
+ int IVAR; // expected-note{{ivar is declared here}}
int name;
}
@property int d1;
@@ -19,7 +19,7 @@
@synthesize d1; // expected-error {{synthesized property 'd1' must either be named the same as}}
@dynamic bad; // expected-error {{property implementation must have its declaration in interface 'I'}}
@synthesize prop_id; // expected-error {{synthesized property 'prop_id' must either be named the same}} // expected-note {{previous declaration is here}}
-@synthesize prop_id = IVAR; // expected-error {{type of property 'prop_id' does not match type of ivar 'IVAR'}} // expected-error {{property 'prop_id' is already implemented}}
+@synthesize prop_id = IVAR; // expected-error {{type of property 'prop_id' ('id') does not match type of ivar 'IVAR' ('int')}} // expected-error {{property 'prop_id' is already implemented}}
@synthesize name; // OK! property with same name as an accessible ivar of same name
@end
diff --git a/test/SemaObjC/undef-protocol-methods-1.m b/test/SemaObjC/undef-protocol-methods-1.m
index 9a35ef7..cbef3e5 100644
--- a/test/SemaObjC/undef-protocol-methods-1.m
+++ b/test/SemaObjC/undef-protocol-methods-1.m
@@ -1,40 +1,34 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@protocol P1
-- (void) P1proto;
-+ (void) ClsP1Proto;
+- (void) P1proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
++ (void) ClsP1Proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
- (void) DefP1proto;
@end
@protocol P2
-- (void) P2proto;
-+ (void) ClsP2Proto;
+- (void) P2proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
++ (void) ClsP2Proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end
@protocol P3<P2>
-- (void) P3proto;
-+ (void) ClsP3Proto;
+- (void) P3proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
++ (void) ClsP3Proto; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+ (void) DefClsP3Proto;
@end
@protocol PROTO<P1, P3>
-- (void) meth;
-- (void) meth : (int) arg1;
-+ (void) cls_meth : (int) arg1;
+- (void) meth; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
+- (void) meth : (int) arg1; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
++ (void) cls_meth : (int) arg1; // expected-warning {{method in protocol not implemented [-Wprotocol]}}
@end
-@interface INTF <PROTO>
+@interface INTF <PROTO> // expected-note 3 {{required for direct or indirect protocol 'PROTO'}} \
+ // expected-note 2 {{required for direct or indirect protocol 'P1'}} \
+ // expected-note 2 {{required for direct or indirect protocol 'P3'}} \
+ // expected-note 2 {{required for direct or indirect protocol 'P2'}}
@end
-@implementation INTF // expected-warning {{incomplete implementation}} \
- expected-warning {{method definition for 'meth' not found}} \
- expected-warning {{method definition for 'meth:' not found}} \
- expected-warning {{method definition for 'cls_meth:' not found}} \
- expected-warning {{method definition for 'P3proto' not found}} \
- expected-warning {{method definition for 'ClsP3Proto' not found}} \
- expected-warning {{method definition for 'P2proto' not found}} \
- expected-warning {{method definition for 'ClsP2Proto' not found}} \
- expected-warning {{method definition for 'ClsP1Proto' not found}} \
- expected-warning {{method definition for 'P1proto' not found}}
+@implementation INTF // expected-warning {{incomplete implementation}}
- (void) DefP1proto{}
+ (void) DefClsP3Proto{}
diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp
index 600115b..d0dd9c9 100644
--- a/test/SemaTemplate/dependent-base-classes.cpp
+++ b/test/SemaTemplate/dependent-base-classes.cpp
@@ -55,7 +55,7 @@ namespace PR6031 {
template<typename T>
struct NoDepBase {
int foo() {
- class NoDepBase::Nested nested; // expected-error{{'Nested' does not name a tag member in the specified scope}}
+ class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}}
typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \
// FIXME: expected-error{{unqualified-id}}
return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}}
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 8bc2631..6ee30aa 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -74,12 +74,16 @@ namespace test3 {
template<typename T>
class X3 {
template<typename U, U Value> friend struct X2a;
- template<typename U, T Value> friend struct X2b;
+
+ // FIXME: the redeclaration note ends up here because redeclaration
+ // lookup ends up finding the friend target from X3<int>.
+ template<typename U, T Value> friend struct X2b; // expected-error {{template non-type parameter has a different type 'long' in template redeclaration}} \
+ // expected-note {{previous non-type template parameter with type 'int' is here}}
};
X3<int> x3i; // okay
- X3<long> x3l; // FIXME: should cause an instantiation-time failure
+ X3<long> x3l; // expected-note {{in instantiation}}
}
// PR5716
diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp
index f883b93..2d27075 100644
--- a/test/SemaTemplate/instantiate-declref.cpp
+++ b/test/SemaTemplate/instantiate-declref.cpp
@@ -36,7 +36,7 @@ namespace N {
typedef int INT;
template struct N::Outer::Inner::InnerTemplate<INT>::VeryInner;
-template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{'UeberInner' does not name a tag member}}
+template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{no struct named 'UeberInner' in 'N::Outer::Inner::InnerTemplate<int>'}}
namespace N2 {
struct Outer2 {
diff --git a/test/SemaTemplate/instantiate-elab-type-specifier.cpp b/test/SemaTemplate/instantiate-elab-type-specifier.cpp
new file mode 100644
index 0000000..e5e10a8
--- /dev/null
+++ b/test/SemaTemplate/instantiate-elab-type-specifier.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR5681
+template <class T> struct Base {
+ struct foo {};
+ int foo;
+};
+
+template <class T> struct Derived : Base<T> {
+ typedef struct Base<T>::foo type;
+};
+
+template struct Derived<int>;
diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp
index 92915c7..8cd7342 100644
--- a/test/SemaTemplate/instantiate-expr-4.cpp
+++ b/test/SemaTemplate/instantiate-expr-4.cpp
@@ -43,6 +43,19 @@ struct Temporaries0 {
template struct Temporaries0<5, 7>;
+// Ensure that both the constructor and the destructor are instantiated by
+// checking for parse errors from each.
+template<int N> struct BadX {
+ BadX() { int a[-N]; } // expected-error {{array size is negative}}
+ ~BadX() { int a[-N]; } // expected-error {{array size is negative}}
+};
+
+template<int N>
+struct PR6671 {
+ void f() { (void)BadX<1>(); } // expected-note 2 {{instantiation}}
+};
+template struct PR6671<1>;
+
// ---------------------------------------------------------------------
// new/delete expressions
// ---------------------------------------------------------------------
diff --git a/test/SemaTemplate/instantiate-function-params.cpp b/test/SemaTemplate/instantiate-function-params.cpp
new file mode 100644
index 0000000..ea8dd70
--- /dev/null
+++ b/test/SemaTemplate/instantiate-function-params.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR6619
+template<bool C> struct if_c { };
+template<typename T1> struct if_ {
+ typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 7{{in instantiation}}
+};
+template <class Model, void (Model::*)()> struct wrap_constraints { };
+template <class Model>
+inline char has_constraints_(Model* , // expected-note 4{{while substituting deduced template arguments into function template 'has_constraints_' [with }} \
+ // expected-note 3{{candidate template ignored}}
+ wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 4{{in instantiation}}
+
+template <class Model> struct not_satisfied {
+ static const bool value = sizeof( has_constraints_((Model*)0) == 1); // expected-error 3{{no matching function}}
+};
+template <class ModelFn> struct requirement_;
+template <void(*)()> struct instantiate {
+};
+template <class Model> struct requirement_<void(*)(Model)> : if_< not_satisfied<Model> >::type { // expected-error 3{{no type named}} \
+ // expected-note 7{{in instantiation}}
+};
+template <class Model> struct usage_requirements {
+};
+template < typename TT > struct InputIterator {
+ typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note 2{{in instantiation}}
+};
+template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note 2{{in instantiation}}
+ typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note 2 {{in instantiation}}
+
+};
+typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX; // expected-error{{no member named}} \
+// expected-note 6{{in instantiation}}
+
+template<typename T> struct X0 { };
+template<typename R, typename A1> struct X0<R(A1 param)> { };
+
+template<typename T, typename A1, typename A2>
+void instF0(X0<T(A1)> x0a, X0<T(A2)> x0b) {
+ X0<T(A1)> x0c;
+ X0<T(A2)> x0d;
+}
+
+template void instF0<int, int, float>(X0<int(int)>, X0<int(float)>);
+
+template<typename R, typename A1, R (*ptr)(A1)> struct FuncPtr { };
+template<typename A1, int (*ptr)(A1)> struct FuncPtr<int, A1, ptr> { };
+
+template<typename R, typename A1> R unary_func(A1);
+
+template<typename R, typename A1, typename A2>
+void use_func_ptr() {
+ FuncPtr<R, A1, &unary_func<R, A1> > fp1;
+ FuncPtr<R, A2, &unary_func<R, A2> > fp2;
+};
+
+template void use_func_ptr<int, float, double>();
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index 16ecc47..e292aa3 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -37,3 +37,21 @@ namespace PR6457 {
};
B<int> b;
}
+
+namespace PR6657 {
+ struct X
+ {
+ X (int, int) { }
+ };
+
+ template <typename>
+ void f0()
+ {
+ X x = X(0, 0);
+ }
+
+ void f1()
+ {
+ f0<int>();
+ }
+}
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index 5d69b50..44f396e 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -50,3 +50,33 @@ namespace test1 {
Registry<int>::node node(0);
}
}
+
+// Redeclarations during explicit instantiations.
+namespace test2 {
+ template <typename T> class A {
+ class Foo;
+ class Foo {
+ int foo();
+ };
+ };
+ template class A<int>;
+
+ template <typename T> class B {
+ class Foo;
+ class Foo {
+ typedef int X;
+ };
+ typename Foo::X x;
+ class Foo;
+ };
+ template class B<int>;
+
+ template <typename T> class C {
+ class Foo;
+ class Foo;
+ };
+ template <typename T> class C<T>::Foo {
+ int x;
+ };
+ template class C<int>;
+}
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
index eecb445..e059434 100644
--- a/test/SemaTemplate/instantiate-member-initializers.cpp
+++ b/test/SemaTemplate/instantiate-member-initializers.cpp
@@ -10,14 +10,14 @@ A<int> a0;
A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}}
template<typename T> struct B {
- // FIXME: This should warn about initialization order
- B() : b(1), a(2) { }
+ B() : b(1), // expected-warning {{member 'b' will be initialized after}}
+ a(2) { } // expected-note {{field a}}
int a;
int b;
};
-B<int> b0;
+B<int> b0; // expected-note {{in instantiation of member function 'B<int>::B' requested here}}
template <class T> struct AA { AA(int); };
template <class T> class BB : public AA<T> {
diff --git a/test/SemaTemplate/instantiation-default-2.cpp b/test/SemaTemplate/instantiation-default-2.cpp
index 4d6756e..5a744a0 100644
--- a/test/SemaTemplate/instantiation-default-2.cpp
+++ b/test/SemaTemplate/instantiation-default-2.cpp
@@ -13,6 +13,6 @@ Constant<int*, &x> *c3;
Constant<float (*)(int, double), f> *c4;
Constant<float (*)(int, double), &f> *c5;
-Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
+Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
Constant<float, 0> *c7; // expected-note{{while substituting}}
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 9c20f2a..6e4f751 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -47,10 +47,8 @@ A3<h> *a14_1;
A3<&h> *a14_2;
A3<f> *a14_3;
A3<&f> *a14_4;
-A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
-A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}
-// FIXME: the first error includes the string <overloaded function
-// type>, which makes Doug slightly unhappy.
+A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (*)(int)'}}
+A3<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (*)(int)'}}
struct Y { } y;
@@ -59,17 +57,15 @@ volatile X * X_volatile_ptr;
template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
X an_X;
A4<an_X> *a15_1; // okay
-A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'X const &' to template argument of type 'X volatile' ignores qualifiers}}
+A4<*X_volatile_ptr> *a15_2; // expected-error{{non-type template argument does not refer to any declaration}}
A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'X const &' cannot bind to template argument of type 'struct Y'}} \
// FIXME: expected-error{{expected unqualified-id}}
template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
A5<h> *a16_1;
A5<f> *a16_3;
-A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}}
-A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}
-// FIXME: the first error includes the string <overloaded function
-// type>, which makes Doug slightly unhappy.
+A5<h2> *a16_6; // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'float (float)'}}
+A5<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (&)(int)'}}
struct Z {
int foo(int);
@@ -97,21 +93,21 @@ template<unsigned char C> struct Overflow; // expected-note{{template parameter
Overflow<5> *overflow1; // okay
Overflow<255> *overflow2; // okay
-Overflow<256> *overflow3; // expected-error{{non-type template argument value '256' is too large for template parameter of type 'unsigned char'}}
+Overflow<256> *overflow3; // expected-warning{{non-type template argument value '256' truncated to '0' for template parameter of type 'unsigned char'}}
template<unsigned> struct Signedness; // expected-note{{template parameter is declared here}}
Signedness<10> *signedness1; // okay
-Signedness<-10> *signedness2; // expected-error{{non-type template argument provides negative value '-10' for unsigned template parameter of type 'unsigned int'}}
+Signedness<-10> *signedness2; // expected-warning{{non-type template argument with value '-10' converted to '4294967286' for unsigned template parameter of type 'unsigned int'}}
template<signed char C> struct SignedOverflow; // expected-note 3 {{template parameter is declared here}}
SignedOverflow<1> *signedoverflow1;
SignedOverflow<-1> *signedoverflow2;
SignedOverflow<-128> *signedoverflow3;
-SignedOverflow<-129> *signedoverflow4; // expected-error{{non-type template argument value '-129' is too large for template parameter of type 'signed char'}}
+SignedOverflow<-129> *signedoverflow4; // expected-warning{{non-type template argument value '-129' truncated to '127' for template parameter of type 'signed char'}}
SignedOverflow<127> *signedoverflow5;
-SignedOverflow<128> *signedoverflow6; // expected-error{{non-type template argument value '128' is too large for template parameter of type 'signed char'}}
-SignedOverflow<(unsigned char)128> *signedoverflow7; // expected-error{{non-type template argument value '128' is too large for template parameter of type 'signed char'}}
+SignedOverflow<128> *signedoverflow6; // expected-warning{{non-type template argument value '128' truncated to '-128' for template parameter of type 'signed char'}}
+SignedOverflow<(unsigned char)128> *signedoverflow7; // expected-warning{{non-type template argument value '128' truncated to '-128' for template parameter of type 'signed char'}}
// Check canonicalization of template arguments.
template<int (*)(int, int)> struct FuncPtr0;
@@ -171,3 +167,12 @@ namespace pr6249 {
int h();
template int f<int, h>();
}
+
+namespace PR6723 {
+ template<unsigned char C> void f(int (&a)[C]); // expected-note 2{{candidate template ignored}}
+ void g() {
+ int arr512[512];
+ f(arr512); // expected-error{{no matching function for call}}
+ f<512>(arr512); // expected-error{{no matching function for call}}
+ }
+}
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 1000818..998fbbb 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -1078,9 +1078,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
// stderr and stdout in the file system, all with different buffers
// but writing to the same device.
fflush(stderr);
-#endif
+#endif
}
- return 0;
}
return Unit.take();
@@ -1737,7 +1736,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
SourceLocation Loc = D->getLocation();
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
Loc = Class->getClassLoc();
- return cxloc::translateSourceLocation(D->getASTContext(), Loc);
+ return cxloc::translateSourceLocation(getCursorContext(C), Loc);
}
CXSourceRange clang_getCursorExtent(CXCursor C) {
@@ -1800,7 +1799,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) {
return clang_getNullRange();
Decl *D = getCursorDecl(C);
- return cxloc::translateSourceRange(D->getASTContext(), D->getSourceRange());
+ return cxloc::translateSourceRange(getCursorContext(C), D->getSourceRange());
}
CXCursor clang_getCursorReferenced(CXCursor C) {
diff --git a/tools/CIndex/CIndexDiagnostic.cpp b/tools/CIndex/CIndexDiagnostic.cpp
index 6aed49e..0314a67 100644
--- a/tools/CIndex/CIndexDiagnostic.cpp
+++ b/tools/CIndex/CIndexDiagnostic.cpp
@@ -201,7 +201,7 @@ CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
return createCXString("");
}
- const CodeModificationHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
+ const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
if (ReplacementRange) {
if (Hint.RemoveRange.isInvalid()) {
// Create an empty range that refers to a single source
@@ -265,6 +265,7 @@ void clang::LoadSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
}
SourceMgr.overrideFileContents(File, Buffer);
+ SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
}
// Parse the diagnostics, emitting them one by one until we've
diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp
index 8521971..379320c 100644
--- a/tools/CIndex/CIndexUSRs.cpp
+++ b/tools/CIndex/CIndexUSRs.cpp
@@ -79,7 +79,10 @@ private:
USRGenerator UG;
public:
StringUSRGenerator()
- : Out(StrBuf), UG(Out) {}
+ : Out(StrBuf), UG(Out) {
+ // Add the USR space prefix.
+ Out << "c:";
+ }
llvm::StringRef str() {
return Out.str();
@@ -266,16 +269,22 @@ CXString clang_getCursorUSR(CXCursor C) {
StringUSRGenerator SUG;
SUG->Visit(static_cast<Decl*>(D));
- if (SUG->ignoreResults() || SUG.str().empty())
+ if (SUG->ignoreResults())
return createCXString("");
// Return a copy of the string that must be disposed by the caller.
return createCXString(SUG.str(), true);
}
+static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
+ if (!(s.size() >= 2 && s[0] == 'c' && s[1] == ':'))
+ return "";
+ return s.substr(2);
+}
+
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
StringUSRGenerator SUG;
- SUG << clang_getCString(classUSR);
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
SUG->GenObjCIvar(name);
return createCXString(SUG.str(), true);
}
@@ -284,7 +293,7 @@ CXString clang_constructUSR_ObjCMethod(const char *name,
unsigned isInstanceMethod,
CXString classUSR) {
StringUSRGenerator SUG;
- SUG << clang_getCString(classUSR);
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
SUG->GenObjCMethod(name, isInstanceMethod);
return createCXString(SUG.str(), true);
}
@@ -302,7 +311,7 @@ CXString clang_constructUSR_ObjCProtocol(const char *name) {
}
CXString clang_constructUSR_ObjCCategory(const char *class_name,
- const char *category_name) {
+ const char *category_name) {
StringUSRGenerator SUG;
SUG->GenObjCCategory(class_name, category_name);
return createCXString(SUG.str(), true);
@@ -311,7 +320,7 @@ CXString clang_constructUSR_ObjCCategory(const char *class_name,
CXString clang_constructUSR_ObjCProperty(const char *property,
CXString classUSR) {
StringUSRGenerator SUG;
- SUG << clang_getCString(classUSR);
+ SUG << extractUSRSuffix(clang_getCString(classUSR));
SUG->GenObjCProperty(property);
return createCXString(SUG.str(), true);
}
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
index e94a786..6aa7a57 100644
--- a/tools/CIndex/CMakeLists.txt
+++ b/tools/CIndex/CMakeLists.txt
@@ -43,10 +43,10 @@ if(MSVC)
# windows.h doesn't compile with /Za
get_target_property(NON_ANSI_COMPILE_FLAGS CIndex COMPILE_FLAGS)
string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
- set(NON_ANSI_COMPILE_FLAGS "${NON_ANSI_COMPILE_FLAGS} /D_CINDEX_LIB_")
set_target_properties(CIndex PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS})
endif(MSVC)
set_target_properties(CIndex
PROPERTIES
- LINKER_LANGUAGE CXX)
+ LINKER_LANGUAGE CXX
+ DEFINE_SYMBOL _CINDEX_LIB_)
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 38c8811..d7f3483 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -202,14 +202,14 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
unsigned display_opts = CXDiagnostic_DisplaySourceLocation
| CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges;
unsigned i, num_fixits;
-
+
if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
return;
Msg = clang_formatDiagnostic(Diagnostic, display_opts);
fprintf(stderr, "%s\n", clang_getCString(Msg));
clang_disposeString(Msg);
-
+
clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic),
&file, 0, 0, 0);
if (!file)
@@ -223,7 +223,7 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
CXSourceLocation end = clang_getRangeEnd(range);
unsigned start_line, start_column, end_line, end_column;
CXFile start_file, end_file;
- clang_getInstantiationLocation(start, &start_file, &start_line,
+ clang_getInstantiationLocation(start, &start_file, &start_line,
&start_column, 0);
clang_getInstantiationLocation(end, &end_file, &end_line, &end_column, 0);
if (clang_equalLocations(start, end)) {
@@ -979,6 +979,177 @@ int perform_token_annotation(int argc, const char **argv) {
}
/******************************************************************************/
+/* USR printing. */
+/******************************************************************************/
+
+static int insufficient_usr(const char *kind, const char *usage) {
+ fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
+ return 1;
+}
+
+static unsigned isUSR(const char *s) {
+ return s[0] == 'c' && s[1] == ':';
+}
+
+static int not_usr(const char *s, const char *arg) {
+ fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
+ return 1;
+}
+
+static void print_usr(CXString usr) {
+ const char *s = clang_getCString(usr);
+ printf("%s\n", s);
+ clang_disposeString(usr);
+}
+
+static void display_usrs() {
+ fprintf(stderr, "-print-usrs options:\n"
+ " ObjCCategory <class name> <category name>\n"
+ " ObjCClass <class name>\n"
+ " ObjCIvar <ivar name> <class USR>\n"
+ " ObjCMethod <selector> [0=class method|1=instance method] "
+ "<class USR>\n"
+ " ObjCProperty <property name> <class USR>\n"
+ " ObjCProtocol <protocol name>\n");
+}
+
+int print_usrs(const char **I, const char **E) {
+ while (I != E) {
+ const char *kind = *I;
+ unsigned len = strlen(kind);
+ switch (len) {
+ case 8:
+ if (memcmp(kind, "ObjCIvar", 8) == 0) {
+ if (I + 2 >= E)
+ return insufficient_usr(kind, "<ivar name> <class USR>");
+ if (!isUSR(I[2]))
+ return not_usr("<class USR>", I[2]);
+ else {
+ CXString x;
+ x.Spelling = I[2];
+ x.MustFreeString = 0;
+ print_usr(clang_constructUSR_ObjCIvar(I[1], x));
+ }
+
+ I += 3;
+ continue;
+ }
+ break;
+ case 9:
+ if (memcmp(kind, "ObjCClass", 9) == 0) {
+ if (I + 1 >= E)
+ return insufficient_usr(kind, "<class name>");
+ print_usr(clang_constructUSR_ObjCClass(I[1]));
+ I += 2;
+ continue;
+ }
+ break;
+ case 10:
+ if (memcmp(kind, "ObjCMethod", 10) == 0) {
+ if (I + 3 >= E)
+ return insufficient_usr(kind, "<method selector> "
+ "[0=class method|1=instance method] <class USR>");
+ if (!isUSR(I[3]))
+ return not_usr("<class USR>", I[3]);
+ else {
+ CXString x;
+ x.Spelling = I[3];
+ x.MustFreeString = 0;
+ print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
+ }
+ I += 4;
+ continue;
+ }
+ break;
+ case 12:
+ if (memcmp(kind, "ObjCCategory", 12) == 0) {
+ if (I + 2 >= E)
+ return insufficient_usr(kind, "<class name> <category name>");
+ print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
+ I += 3;
+ continue;
+ }
+ if (memcmp(kind, "ObjCProtocol", 12) == 0) {
+ if (I + 1 >= E)
+ return insufficient_usr(kind, "<protocol name>");
+ print_usr(clang_constructUSR_ObjCProtocol(I[1]));
+ I += 2;
+ continue;
+ }
+ if (memcmp(kind, "ObjCProperty", 12) == 0) {
+ if (I + 2 >= E)
+ return insufficient_usr(kind, "<property name> <class USR>");
+ if (!isUSR(I[2]))
+ return not_usr("<class USR>", I[2]);
+ else {
+ CXString x;
+ x.Spelling = I[2];
+ x.MustFreeString = 0;
+ print_usr(clang_constructUSR_ObjCProperty(I[1], x));
+ }
+ I += 3;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (I != E) {
+ fprintf(stderr, "Invalid USR kind: %s\n", *I);
+ display_usrs();
+ return 1;
+ }
+ return 0;
+}
+
+int print_usrs_file(const char *file_name) {
+ char line[2048];
+ const char *args[128];
+ unsigned numChars = 0;
+
+ FILE *fp = fopen(file_name, "r");
+ if (!fp) {
+ fprintf(stderr, "error: cannot open '%s'\n", file_name);
+ return 1;
+ }
+
+ /* This code is not really all that safe, but it works fine for testing. */
+ while (!feof(fp)) {
+ char c = fgetc(fp);
+ if (c == '\n') {
+ unsigned i = 0;
+ const char *s = 0;
+
+ if (numChars == 0)
+ continue;
+
+ line[numChars] = '\0';
+ numChars = 0;
+
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+
+ s = strtok(line, " ");
+ while (s) {
+ args[i] = s;
+ ++i;
+ s = strtok(0, " ");
+ }
+ if (print_usrs(&args[0], &args[i]))
+ return 1;
+ }
+ else
+ line[numChars++] = c;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -1006,7 +1177,9 @@ static void print_usage(void) {
" c-index-test -test-annotate-tokens=<range> {<args>}*\n"
" c-index-test -test-inclusion-stack-source {<args>}*\n"
" c-index-test -test-inclusion-stack-tu <AST file>\n"
- " c-index-test -test-print-linkage-source {<args>}*\n\n"
+ " c-index-test -test-print-linkage-source {<args>}*\n"
+ " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
+ " c-index-test -print-usr-file <file>\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"
@@ -1049,6 +1222,16 @@ int main(int argc, const char **argv) {
else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
NULL);
+ else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
+ if (argc > 2)
+ return print_usrs(argv + 2, argv + argc);
+ else {
+ display_usrs();
+ return 1;
+ }
+ }
+ else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
+ return print_usrs_file(argv[2]);
print_usage();
return 1;
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6434cb4..f88d229 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -11,6 +11,10 @@ LEVEL = ../../../..
TOOLNAME = clang
ifndef CLANG_IS_PRODUCTION
TOOLALIAS = clang++
+else
+ ifdef CLANGXX_IS_PRODUCTION
+ TOOLALIAS = clang++
+ endif
endif
CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
@@ -33,4 +37,6 @@ include $(LLVM_SRC_ROOT)/Makefile.rules
ifdef CLANG_IS_PRODUCTION
CPP.Defines += -DCLANG_IS_PRODUCTION
endif
-
+ifdef CLANGXX_IS_PRODUCTION
+CPP.Defines += -DCLANGXX_IS_PRODUCTION
+endif
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 0b108ae..35854be 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -29,8 +29,10 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/DynamicLibrary.h"
#include "llvm/Target/TargetSelect.h"
@@ -195,9 +197,9 @@ static int cc1_test(Diagnostic &Diags,
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
- CompilerInstance Clang;
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
- Clang.setLLVMContext(new llvm::LLVMContext);
+ Clang->setLLVMContext(new llvm::LLVMContext);
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") {
@@ -214,17 +216,17 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// well formed diagnostic object.
TextDiagnosticBuffer DiagsBuffer;
Diagnostic Diags(&DiagsBuffer);
- CompilerInvocation::CreateFromArgs(Clang.getInvocation(), ArgBegin, ArgEnd,
+ CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd,
Diags);
// Infer the builtin include path if unspecified.
- if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
- Clang.getHeaderSearchOpts().ResourceDir.empty())
- Clang.getHeaderSearchOpts().ResourceDir =
+ if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
+ Clang->getHeaderSearchOpts().ResourceDir.empty())
+ Clang->getHeaderSearchOpts().ResourceDir =
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Honor -help.
- if (Clang.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");
@@ -234,27 +236,27 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Honor -version.
//
// FIXME: Use a better -version message?
- if (Clang.getFrontendOpts().ShowVersion) {
+ if (Clang->getFrontendOpts().ShowVersion) {
llvm::cl::PrintVersionMessage();
return 0;
}
// Create the actual diagnostics engine.
- Clang.createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin));
- if (!Clang.hasDiagnostics())
+ Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin));
+ if (!Clang->hasDiagnostics())
return 1;
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
llvm::llvm_install_error_handler(LLVMErrorHandler,
- static_cast<void*>(&Clang.getDiagnostics()));
+ static_cast<void*>(&Clang->getDiagnostics()));
- DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics());
+ DiagsBuffer.FlushDiagnostics(Clang->getDiagnostics());
// Load any requested plugins.
for (unsigned i = 0,
- e = Clang.getFrontendOpts().Plugins.size(); i != e; ++i) {
- const std::string &Path = Clang.getFrontendOpts().Plugins[i];
+ e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) {
+ const std::string &Path = Clang->getFrontendOpts().Plugins[i];
std::string Error;
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error;
@@ -262,11 +264,26 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// If there were errors in processing arguments, don't do anything else.
bool Success = false;
- if (!Clang.getDiagnostics().getNumErrors()) {
+ if (!Clang->getDiagnostics().getNumErrors()) {
// Create and execute the frontend action.
- llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(Clang));
- if (Act)
- Success = Clang.ExecuteAction(*Act);
+ llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+ if (Act) {
+ Success = Clang->ExecuteAction(*Act);
+ if (Clang->getFrontendOpts().DisableFree)
+ Act.take();
+ }
+ }
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+
+ // When running with -disable-free, don't do any destruction or shutdown.
+ if (Clang->getFrontendOpts().DisableFree) {
+ if (Clang->getFrontendOpts().ShowStats)
+ llvm::PrintStatistics();
+ Clang.take();
+ return !Success;
}
// Managed static deconstruction. Useful for making things like
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 2108c8f..3f1cca1 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -24,6 +24,7 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
@@ -73,10 +74,10 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
/// \param Args - The vector of command line arguments.
/// \param Edit - The override command to perform.
/// \param SavedStrings - Set to use for storing string representations.
-void ApplyOneQAOverride(llvm::raw_ostream &OS,
- std::vector<const char*> &Args,
- llvm::StringRef Edit,
- std::set<std::string> &SavedStrings) {
+static void ApplyOneQAOverride(llvm::raw_ostream &OS,
+ std::vector<const char*> &Args,
+ llvm::StringRef Edit,
+ std::set<std::string> &SavedStrings) {
// This does not need to be efficient.
if (Edit[0] == '^') {
@@ -140,8 +141,9 @@ void ApplyOneQAOverride(llvm::raw_ostream &OS,
/// ApplyQAOverride - Apply a comma separate list of edits to the
/// input argument lists. See ApplyOneQAOverride.
-void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
- std::set<std::string> &SavedStrings) {
+static void ApplyQAOverride(std::vector<const char*> &Args,
+ const char *OverrideStr,
+ std::set<std::string> &SavedStrings) {
llvm::raw_ostream *OS = &llvm::errs();
if (OverrideStr[0] == '#') {
@@ -195,12 +197,19 @@ int main(int argc, const char **argv) {
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
+# ifdef CLANGXX_IS_PRODUCTION
+ const bool CXXIsProduction = true;
+# else
+ const bool CXXIsProduction = false;
+# endif
#else
const bool IsProduction = false;
+ const bool CXXIsProduction = false;
#endif
Driver TheDriver(Path.getBasename(), Path.getDirname(),
llvm::sys::getHostTriple(),
- "a.out", IsProduction, Diags);
+ "a.out", IsProduction, CXXIsProduction,
+ Diags);
// Check for ".*++" or ".*++-[^-]*" to determine if we are a C++
// compiler. This matches things like "c++", "clang++", and "clang++-1.1".
@@ -265,6 +274,11 @@ int main(int argc, const char **argv) {
if (C.get())
Res = TheDriver.ExecuteCompilation(*C);
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+
llvm::llvm_shutdown();
return Res;
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 432456b..8a7afbb 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -783,6 +783,7 @@ sub RunBuildCommand {
my $IgnoreErrors = shift;
my $Cmd = $Args->[0];
my $CCAnalyzer = shift;
+ my $CXXAnalyzer = shift;
# Get only the part of the command after the last '/'.
if ($Cmd =~ /\/([^\/]+)$/) {
@@ -809,12 +810,12 @@ sub RunBuildCommand {
$ENV{"CCC_CXX"} = $1;
}
shift @$Args;
- unshift @$Args, $CCAnalyzer;
+ unshift @$Args, $CXXAnalyzer;
}
elsif ($IgnoreErrors) {
if ($Cmd eq "make" or $Cmd eq "gmake") {
AddIfNotPresent($Args, "CC=$CCAnalyzer");
- AddIfNotPresent($Args, "CXX=$CCAnalyzer");
+ AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
AddIfNotPresent($Args,"-k");
AddIfNotPresent($Args,"-i");
}
@@ -845,7 +846,8 @@ sub RunBuildCommand {
# When 'CC' is set, xcodebuild uses it to do all linking, even if we are
# linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
- # when linking such files.
+ # (via c++-analyzer) when linking such files.
+ $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
}
return (system(@$Args) >> 8);
@@ -1232,9 +1234,8 @@ if (defined $OutputFormat) {
$ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
}
-
# Run the build.
-my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
+my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX);
if (defined $OutputFormat) {
if ($OutputFormat =~ /plist/) {
diff --git a/utils/VtableTest/Makefile b/utils/VtableTest/Makefile
index 0e06026..dd615ae 100644
--- a/utils/VtableTest/Makefile
+++ b/utils/VtableTest/Makefile
@@ -5,17 +5,20 @@ all: one
test.cc: gen.cc
g++ gen.cc -o gen
- gen >test.cc
+ ./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-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
+ ./test-clang >test-clang.sum
one: test-gcc.sum test-clang.sum
cmp test-gcc.sum test-clang.sum
+
+clean:
+ rm -f gen test-gcc test-clang test.cc test-gcc.sum test-clang.sum test-gcc.s test-clang.s
diff --git a/utils/VtableTest/check-ztt b/utils/VtableTest/check-ztt
index 77cf99d..4a83c55 100755
--- a/utils/VtableTest/check-ztt
+++ b/utils/VtableTest/check-ztt
@@ -6,10 +6,10 @@ N_STRUCTS=300
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
+ sed -n "/^__ZTT.*s$i:/,/\.[sgm][elo]/p" test-clang.s |
+ grep -v '\.[sgm][elo]' | sed -e 's/[()]//g' -e '/^$/d' >test-clang-ztt
+ sed -n "/^__ZTT.*s$i:/,/\.[sgm][elo]/p" test-gcc.s |
+ grep -v '\.[sgm][elo]' | sed -e 's/[()]//g' -e 's/ + /+/' >test-gcc-ztt
diff -U3 test-gcc-ztt test-clang-ztt
if [ $? != 0 ]; then
echo "FAIL: s$i VTT"
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 63084b5..621b2f0 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://checker.minormatter.com/checker-237.tar.bz2">checker-237.tar.bz2</a></b> (built March 11, 2010)
+<b><a href="http://checker.minormatter.com/checker-238.tar.bz2">checker-238.tar.bz2</a></b> (built April 1, 2010)
diff --git a/www/get_started.html b/www/get_started.html
index f750fa0..141698f 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -65,7 +65,7 @@ follows:</p>
to find your C++ standard library headers. If Clang cannot find your
system libstdc++ headers, please follow these instructions:</li>
<ul>
- <li>'<tt>touch empty.cpp; gcc -v empty.cpp -fsyntax-only</tt>' to get the
+ <li>'<tt>gcc -v -x c++ /dev/null -fsyntax-only</tt>' to get the
path.</li>
<li>Look for the comment "FIXME: temporary hack:
hard-coded paths" in <tt>clang/lib/Frontend/InitHeaderSearch.cpp</tt> and
OpenPOWER on IntegriCloud